參考我之前發的一篇 Windows棧溢出原理
還有 brant 師傅的《0day安全筆記》
解題過程

逆向和分析
這個過程就是IDA的使用和匯編代碼的理解
IDA使用技巧:
getshell分兩種情況:
(1) 內存程序中有getshell函數[system("/bin/sh")]或指令時,直接調用/劫持。
(2) 存程序中沒有getshell函數或指令時, 就要編寫shellcode。
Pwn常用工具
gdb:Linux下程序調試
PEDA:針對gdb的python漏洞利用開發協助
pwndbg:和PEDA類似,GDB插件
pwntools:寫exp和poc的利器(python庫)
checksec:檢查elf程序的安全性和程序的運行平台(一般來說peda里面自帶的就夠了)
objdump和readelf:可以很快的知道elf程序中的關鍵信息(Ubuntu自帶)
ROPgadget:強大的Rop利用工具
one_gadget:可以快速的尋找libc中的調用exec('bin/sh')的位置
libc-database: 可以通過泄露的libc的某個函數地址查出遠程系統是用的哪個libc版本
檢測elf安全性
拿到elf,首先用checksec檢查elf運行平台,安全措施
如果用gcc的編譯后,默認會開啟所有的安全措施

1、RELRO:有Partial RELRO和FULL RELRO(開啟),如果開啟,則無法修改got表
2、Stack:如果棧中開啟Canary found,就不能用直接用溢出的方法覆蓋棧中返回地址
而且要通過改寫指針與局部變量、leak canary、overwrite canary的方法來繞過
3、NX:NX enabled 如果這個保護開啟就是意味着棧中數據沒有執行權限
以前的經常用的call esp或者jmp esp的方法就不能使用,但是可以利用rop這種方法繞過
4、PIE:PIE enabled 如果程序開啟這個地址隨機化選項,就意味着程序每次運行的時候地址都會變化
而如果沒有開PIE的話那么No PIE (0x400000),括號內的數據就是程序的基地址
5、FORTIFY:FORTIFY_SOURCE 機制對格式化字符串有兩個限制
(1)包含%n的格式化字符串不能位於程序內存中的可寫地址。
(2)當使用位置參數時,必須使用范圍內的所有參數。
所以如果要使用%7$x,你必須同時使用1,2,3,4,5和6。
泄露libc地址和版本的方法
[1] 利用格式化字符串漏洞 泄露棧中的數據,從而找到libc的某個函數地址
再利用libc-database來判斷遠程libc的版本,之后再計算出libc的基址,一般找__libc_start_main的地址
[2] 利用write這個函數,pwntools有個很好用的函數DynELF去利用這個函數計算出程序的各種地址
括函數的基地址,libc的基地址,libc中system的地址
[3] 利用printf函數,printf函數輸出的時候遇到0x00時候會停止輸出
如果輸入的時候沒有在最后的字節處填充0x00,那么輸出的時候就可能泄露棧中的重要數據,比如libc的某個函數地址
簡單的棧溢出
程序沒有開啟任何保護:
方法一:傳統的教材思路是把shellcode寫入棧中,然后查找程序中或者libc中有沒有call esp或者jmp esp,
比如這個題目: http://blog.csdn.net/niexinming/article/details/76893510
方法二:但是現代操作系統中libc中會開啟地址隨機化,所以先尋找程序中system的函數,再布局棧空間,
調用gets(.bss),最后調用system('/bin/sh')
比如這個題目:http://blog.csdn.net/niexinming/article/details/78796408
方法三:覆蓋虛表方式利用棧溢出漏洞,這個方法是m4x師傅的方法,
比如這個題目:http://blog.csdn.net/niexinming/article/details/78144301
開啟nx的程序
開啟nx之后棧和bss段就只有讀寫權限,沒有執行權限了,所以就要用到rop這種方法拿到系統權限,如果程序很復雜,或者程序用的是靜態編譯的話,那么就可以使用ROPgadget這個工具很方便的直接生成rop利用鏈。有時候好多程序不能直接用ROPgadget這個工具直接找到利用鏈,所以就要手動分析程序來getshell了,比如這兩個題目: http://blog.csdn.net/niexinming/article/details/78259866
開啟canary的程序
開啟canary后就不能直接使用普通的溢出方法來覆蓋棧中的函數返回地址了,要用一些巧妙的方法來繞過或者利canary本身的弱點來攻擊 【1】利用canary泄露flag,這個方法很巧妙的運用了canary本身的弱點,當stack_check_fail時,會打印出正在運行中程序的名稱,所以,我們只要將libc_argv[0]覆蓋為flag的地址就能將flag打印出來,比如這個題目: http://blog.csdn.net/niexinming/article/details/78522682 【2】利用printf函數泄露一個子進程的Canary,再在另一個子進程棧中偽造Canary就可以繞過Canary的保護了,比如這個題目:http://blog.csdn.net/niexinming/article/details/78681846
開啟PIE的程序
(1) 利用printf函數盡量多打印一些棧中的數據,根據泄露的地址來計算程序基地址,libc基地址,system地址
比如這篇文章中echo2的wp: http://blog.csdn.net/niexinming/article/details/78512274
(2) 利用write泄露程序的關鍵信息,這樣的話可以很方便的用DynELF這個函數了
比如這個文章中的rsbo2的題解:http://blog.csdn.net/niexinming/article/details/78620566
全部保護開啟
如果程序的棧可以被完全控制,那么程序的保護全打開也會被攻破
比如這個題目:http://blog.csdn.net/niexinming/article/details/78666941
格式化字符串漏洞
格式化漏洞現在很難在成熟的軟件中遇到,但是這個漏洞卻很有趣 (1) pwntools有很不錯的函數FmtStr和fmtstr_payload來自動計算格式化漏洞的利用點
並且自動生成payload
比如這個題目:http://blog.csdn.net/niexinming/article/details/78699413
和 http://blog.csdn.net/niexinming/article/details/78512274 中echo的題解
(2) 格式化漏洞也是信息泄露的好伴侶,比如這個題目中制造格式化字符串漏洞泄露各種數據
http://blog.csdn.net/niexinming/article/details/78768850
uaf漏洞
如果把堆釋放之后,沒有把指針指針清0,還讓指針保存下來,那么就會引發很多問題
比如這個題目 http://blog.csdn.net/niexinming/article/details/78598635
任意位置寫
如果程序可以在內存中的任意位置寫的話,那么威力絕對很大 (1) 雖然只能寫一個字節,但是依然可以控制程序的並getshell
比如這個題目 http://blog.csdn.net/niexinming/article/details/78542089
(1) 修改got表是個控制程序流程的好辦法,很多題目只要能通過各種方法控制got的寫入,就可以最終得到勝利
比如這個題目: http://blog.csdn.net/niexinming/article/details/78542089
(3) 如果能計算出libc的基地址的話,控制top_chunk指針也是解題的好方法
比如這個題目: http://blog.csdn.net/niexinming/article/details/78759363
Pwn大佬博客
學習資源
Pwn思維導圖

