棧知識、部分保護措施
GDB顯示的棧地址有時候并不是可靠的地址,gdb也是用特殊的進程映像來拿地址的。且gdb默認關閉棧地址隨機化。但是,偏移量是沒有錯誤的。目前還沒學到咋解決
第一個棧幀是main函數棧幀,之前的一些系統函數什么的沒有棧幀。
執行了leave之后的情況:會pop ebp,所以esp+1,然后ebp恢復原來樣子了。然后會執行retn,那就是將返回地址相當于pop給eip寄存器。
canary(金絲雀)保護措施,在?ebp下面會有一個值,創建棧幀的時候就有了。如果銷毀棧幀時檢測到這個值被修改了,那么他就會崩潰退出。可以在gcc編譯的時候打開
2個16進制數字代表1個字節
64位一個ebp是8字節,32位是4
ret2shellcode題目講解
1.動調拿到溢出字節數
需要注意,如果棧存放的是指針,這工具會把指針的數據打印出來。所以esp實際上存的是指針,不是我們想要溢出的字符串。
2.寫exp?
payload一定要有shellcode(arm后的),但是返回地址需要考慮一下,最好不在棧上做執行,因為有太多保護措施。觀察軟件main函數會對一個全局變量賦值,那就在bss段進行執行吧。
ljust(填充前方字節流長度到幾,填充數據),這是個函數,可以這樣寫:
arm(shellcraft.sh()).ljust(目標長度,b'A')。
有時候需要recv完畢再send不然會IO錯誤。
返回導向編程
ret2syscall
本質上是操作空間內核里面的代碼。
在舉例中,my_puts是用戶函數,其中調用了函數write。eax是傳入系統調用號。在動態鏈接庫的作用下,write對應的匯編代碼進行實現功能,調用更加底層的系統函數/接口之類。
ldd命令可以查看一個可執行程序的所有動態鏈接庫,如ldd a.out
需要關注libc.so.6,記錄著c語言標準動態鏈接庫的軟連接。(記錄軟連接在更新動態鏈接庫的時候更加便捷)就在lib文件夾里面?。有時候會出現本地打不通,遠程打通,或者反過來,可能原因之一就是動態鏈接庫版本不同了,這種的排錯還是比較困難的。
動態鏈接庫也是elf文件,有位置無關代碼編寫技術?,這個技術被PIE借鑒了。
動態鏈接庫會載入在shared那個區域。ret2libc的目的就是把程序從text跳轉到shared libraries。
execve就是上面libc.so包裝在system里面的一個系統調用。?
int 0x80就是一個中斷號,代表系統調用。再讀取eax里面存的調用號。
但是程序沒有這樣連續的片段,其實將間斷的片段(gadget)組合起來也可以達到這樣的效果,就是ROP。
執行過程?
詳見視頻P3的2:27:10左右。需要注意ret的效果和EIP的作用,以及pop了esp會移動的。
利用ret控制eip,用pop eax可以直接把想要的值覆蓋在棧上。
做題
2:47:28左右
運氣好部分寄存器值已經是對的,可以不用pop什么了
用drawio工具,看棧的變化,進一步理解ROP過程以編寫payload
只是了解:popad
?按?edi
、esi
、ebp
、esp
(原棧指針,不過該值不存回?esp
?)、ebx
、edx
、ecx
、eax
?順序彈出。