為什麼會先說防禦機制呢
因為在打 pwn 之前
要先對這些防禦原理有基礎才有辦法知道你要怎麼打
在學習以下東西時
建議各位先去弄一台 linux 環境並且裝上 pwntools
裝好後有個指令叫做 checksec
可以檢查這支程式有什麼樣子的保護
名稱 | 用處 |
---|---|
Arch | 架構 |
RELRO | read only relocation , 用來限制程序中重定向位置的可寫區域, 通常 Partial RELRO 代表 GOT表 可寫 |
Canary | stack 保護機制,利用 cookie 來確認是否被攻擊,因為bof攻擊通常會將整個 stack 改寫而覆蓋掉 cookie |
NX | No Execute(Win平台上稱之為 DEP), 不能再stack上執行指令 |
PIE | Position Independent Code 或稱 ASLR(address space layout randomization) , 記憶體地址隨機化 |
從上面的表可以知道
這支程式 GOT 表可以被修改
沒有隨機記憶體區塊
stack 上不能執行東西
大宗分為兩大類
因為記憶體有兩個大主體嘛 stack 跟 heap
今天只會提到 stack
在攻擊手段中
通常叫做 overflow 攻擊
原因是因為程式在輸入區域變數時
沒有加以限制導致過長的輸入可以蓋掉 ebp, ret 等之類的重要資料
導致精心加工的字串可以導致控制程式流程
如果你有學過 C 語言
不知道有沒有老師曾經跟你說過 gets()
是個很危險的函數
沒事不要亂用
其實就是因為該函數沒有對輸入的字元數做限制
導致如果有人輸入過長就會導致程式崩潰
但這樣 "輸入過長就會導致程式崩潰" 其實在 pwn 的領域看來
就是我可以利用這支程式打下你主機拉~
以上這些都是對於 stack 的相關攻擊手法
可以看到一堆 ret2
其實就是 return to(two)
的意思
那藉由這個字
我想前一篇為什麼說 ret位置是精隨
應該不言而喻了吧
介紹個簡單的例子帶大家認識什麼是 pwn
就用最基礎的 ret2text
來說吧
還記的 text 在記憶體中是什麼嗎
是存放指令碼的地方
意思就是我們要利用 ret 位址
跳到某個關鍵的程式碼上去執行
利用上面講防禦保護的 bof_1
當例子
我們可以從原始碼看出 win()
是我們要得結果
可是這支程式怎麼樣都沒有執行到阿
只有 vuln()
該怎麼辦
這邊要注意到剛剛說的 gets()
很危險
因為它可以輸入任意長度導致覆蓋 return
而使得改變流程
這邊先釐清個思路
main()
call 了 vuln()
vuln()
的 return 位址會回到 main()
的 return 0;
那行vuln()
有 gets()
導致可以跳去任意地方vuln()
跳到 win()
吧這時候就得去看看程式的組語了
我們得算算 buf
這個變數離 ebp 多遠才有辦法蓋到 ret
gets@plt
就是 call gets 的地方
那上面的 lea eax, [ebp-0x1c]
就是把 buf
變數的位址放進暫存器
所以可以知道 buf
離 ebp 有 0x1c
那麼遠
接著來看一下 win()
在什麼位址開始
好的0x080484eb
現在什麼都有了
構造一下 payload
灌進去程式當作輸入
python -c "print 'a'*(0x1c+4)+'\xeb\x84\x04\x08'"|./bof_1
這邊要注意ret地址在寫的時候要倒著放
因為是 Little-Endien
+----------+ < buf (EBP - 0x1C)
| |
+----------+
| |
+----------+
| |
+----------+
| |
+----------+
| |
+----------+
| |
+----------+
| |
+----------+ < EBP
| old EBP |
+----------+
| ret |
+----------+
前面會先用隨便一個東西填充滿 0x1c 個來讓我們到達 ebp
接著在放 4 個填充到達 ret 位置
+----------+ < buf (EBP - 0x1C)
| aaaa |
+----------+
| aaaa |
+----------+
| aaaa |
+----------+
| aaaa |
+----------+
| aaaa |
+----------+
| aaaa |
+----------+
| aaaa |
+----------+ < EBP
| aaaa |
+----------+
| ret |
+----------+
接著要寫入我們所要跳轉的位址去 ret
+----------+ < buf (EBP - 0x1C)
| aaaa |
+----------+
| aaaa |
+----------+
| aaaa |
+----------+
| aaaa |
+----------+
| aaaa |
+----------+
| aaaa |
+----------+
| aaaa |
+----------+ < EBP
| aaaa |
+----------+
|0x080484eb|
+----------+
所以當 vuln()
執行完之後就會 return 回我們指定的地方
也就是 win()
的位置
成功~