好久沒寫 pwn 了,今天來寫一題 Pwn 的 CTF 吧~
題目是 pwnable.tw 的第一題 start。
執行起來會發現
輸入太長會觸發 segmentation fault
我們先確認一下保護記憶體機置
可以看出沒有設任何保護機制
我們再用 IDA 打開
我們可以發現,首先他將 esp 值 push 進去,接下來 push exit 函數的位置,作為 return address。
接著透過 XOR 將 register 值歸零後,又 push 值進去,因此整支程式的記憶體配值如下
接下來我們可以看到
0x8048087 <_start+39>: mov ecx,esp
0x8048089 <_start+41>: mov dl,0x14
0x804808b <_start+43>: mov bl,0x1
0x804808d <_start+45>: mov al,0x4
0x804808f <_start+47>: int 0x80
從 0x08048087 開始是個 system call,可以看到他把 eax 設為 0x04,0x04 為 write。
將 esp(stack 頂端)的值給 ecx,edx 設為 0x14,因此得知會從 esp 往下輸出 20 bytes 的內容,也就是 Ler's start the CTF:
接下來
0x8048091 <_start+49>: xor ebx,ebx
0x8048093 <_start+51>: mov dl,0x3c
0x8048095 <_start+53>: mov al,0x3
0x8048097 <_start+55>: int 0x80
這個 system call 是 read,然而他將 edx 設為 0x3c,ecx 還是之前位置,因此
-------------- <-- ecx, esp
| Let' |
--------------
| s st |
--------------
| art |
--------------
| the |
--------------
| CTF: |
--------------
| retaddr | (exit address)
--------------
| saved esp |
--------------
很明顯的只要輸入超過 20 就可以覆蓋掉saved esp 與 return address。
已經找到有問題的地方了,接下來我們繼續往下看要怎麼構造 payload。
0x8048099 <_start+57>: add esp,0x14
0x804809c <_start+60>: ret
最後兩行是這個,我們可以看到他把 esp 往下移 0x14
-------------- <-- ecx
| Let' |
--------------
| s st |
--------------
| art |
--------------
| the |
--------------
| CTF: |
-------------- <-- esp
| retaddr | (exit address)
--------------
| saved esp |
--------------
並且執行 ret 把 esp 值 pop 出來給 eip,讓他順利的執行 exit。
現在我們希望能自己寫一個 shellcode 進去讓他執行。我們希望讓他能讓 eip 直接跳到我們寫的程式碼去執行,但我們不知道 eip 的位置不能動他,因此為了達到這個目的,最簡單的方法就是修改 esp 值,讓他在 ret 的時候能 pop 出我們 shellcode 的位置給 eip。
那我們要怎麼做呢?明天再操作給大家看吧~
好啦,今天的主題是: