棧遷移
當我們的rop鏈過長時很可能棧空間不夠,並且ebp之前的空間其實只是填充一些沒什么用的數據
棧遷移機理
與傳統的pop_ret類似,利用level_ret實現棧的遷移,都是尋找很小短的零碎代碼,進行拼接,和拼積木很像。
level ret//拆解
mov esp,ebp//esp跟着ebp走
pop ebp //棧基指針的轉移
pop eip//ret
示例
.data:0804A008 count dd 539h //1337用十六進制表示就是539h
當我們還不知道level_ret時,采用一般的rop必然要在回到輸入點,就這道題就是(main函數),但發現main函數受到count的影響僅一次main(無法重復利用main),所以要換一種思路。那我們能否利用有效的代碼段與一段可以容納數據(在我們的腳本中的要發送的數據)構成類似棧的結構,答案當然是可以的
顯然有read 函數,但是(0x40-0x28)真正的數據填充區域有限,可有read函數,就想能否將數據寫入某個位置(比如.bss)read(0,buf,0x100)
| buf(ebp) | //pop數值到ebp,改變基址
| read(ret) | //pop到eip,執行read(0,buf,0x100)
| ret | //執行完read后返回,pop到eip
| 0 |
| buf |
| 0x100 |
這是一開始的棧的布局,看着很合理,但實際上還有缺陷,,比如執行完read后執行流終斷,,因為.bss沒有棧的pop的機制段,放很多數據卻沒法用。
| buf |//pop數值到ebp,改變基址
| read_plt |//pop到eip,執行read(0,buf,0x100)
| leave_ret |//pop到eip,執行leave_ret=>esp被代跑(觸發)
| 0 |//此時棧指針都沒了(棧已被移走;觸發后)
| buf |
| 0x100 |
泄露地址
.bss | buf2 |//這里寫buf2的原因是pop ebp, 改變基址
| puts_plt |//這里要打印泄露puts的裝載地址,leave_ret 的ret那一步
| pop_ret |//puts(puts_got)后,pop到eip,執行
| puts_gots |//要泄露的參數值,之后pop掉
pop ret =》 | read_plt |//pop到eip,執行read(0,buf,0x100)
| leave_ret |//pop到eip,執行leave_ret=>esp被代跑(觸發)
| 0 |//此時棧指針都沒了(已被移走;觸發后)
| buf |
| 0x100 |
調用system 函數
.bss | bbbb |//隨便 改變基址pop ebp 那一步
| system |//leave_ret 的ret那一步
| cccc |//返回地址隨便寫
| binsh_addr |
上圖僅供參考