棧溢位逆向分析
棧溢位漏洞逆向分析
摘要:針對StackOverflow.cpp程式,首先將其編譯為二進位制檔案,進而通過動態逆向分析工具,以彙編指令為粒度,詳細分析指令的功能及漏洞觸發和利用方法。
關鍵詞:棧溢位 逆向分析
工具:Windows10 Dev-C++ Ollydbg[吾愛]
棧溢位漏洞原理
棧溢位屬於緩衝區溢位,指的是程式向棧中某個變數中寫入的位元組數超過了這個變數本身所申請的位元組數,因而導致其寫入與其相鄰的棧,導致相鄰棧中資料改變。
- 轉載請註明出處:https://www.cnblogs.com/merk11/
利用方式有:
通過覆蓋某些區域性變數值達到繞過驗證效果
通過移植惡意程式碼並修改返回地址達到某種目的
程式碼逆向分析
- 首先將stackoverflow.cpp編譯生成exe檔案,並用OD開啟動態除錯。找到程式執行的入口和main函式入口並下斷點,完成準備工作。
-
對stackoverflow.cpp次要部分進行簡要理解
-
我們跟進到scanf函式那裡,測試棧溢位的情形,首先我們嘗試正常的錯誤密碼1234561
我們可以看到它的存入方式是從右到左從上到下的。
再嘗試溢位的錯誤密碼555555555
我們可以看到它搶佔了當前位置+0x4的棧幀空間,可能會導致未知的錯誤。
- 接著我們進入重點分析的verify_password函式中,主要觀察函式的返回位置和棧幀的變化。
00401500 55 push ebp 00401501 89E5 mov ebp,esp 00401503 83EC 28 sub esp,0x28 #更新棧基址指標,提升棧頂指標,分配一段0x28空間
00401506 C74424 04 00404>mov dword ptr ss:[esp+0x4],StackOve.0040400> #將“1234567”字串變數地址存入esp+0x4
0040150E 8B45 08 mov eax,dword ptr ss:[ebp+0x8] #將ebp+0x8變數地址存入eax
00401511 890424 mov dword ptr ss:[esp],eax #將eax中的地址存入esp的字串變數
由c語言程式分析,這裡的返回值是strcmp產生的,而strcpy則是起到儲存此密碼的作用,這兩個函式在棧溢位的情形很可能造成未知的錯誤,所以F7步入函式內部檢視。
這裡我的輸入密碼為:88888888
764496A0 8B5424 04 mov edx,dword ptr ss:[esp+0x4]
764496A4 8B4C24 08 mov ecx,dword ptr ss:[esp+0x8] #使用edx,ecx儲存esp+0x4和esp+0x8
764496A8 F7C2 03000000 test edx,0x3 #也就是“1234567”和輸入值,test會將ZF置1
764496AE 75 3C jnz short msvcrt.764496EC #於是這裡跳轉
764496B0 8B02 mov eax,dword ptr ds:[edx] #將edx變數地址放入eax
764496B2 3A01 cmp al,byte ptr ds:[ecx] #比較eax和ecx中變數的低位,ZF置1
764496B4 75 2E jnz short msvcrt.764496E4 #於是這裡不跳轉
764496E4 1BC0 sbb eax,eax #eax歸零
764496E6 D1E0 shl eax,1 #移位
764496E8 83C0 01 add eax,0x1 #加1,此時eax值為00000001
764496EB C3 retn #返回
strcmp函式似乎沒有引發錯誤,返回值正確
返回main函式
00401519 8945 F4 mov dword ptr ss:[ebp-0xC],eax #eax中的變數放入ebp-0xC位置
0040151C 8B45 08 mov eax,dword ptr ss:[ebp+0x8] #將ebp+0x8變數地址放入eax
0040151F 894424 04 mov dword ptr ss:[esp+0x4],eax #將eax中地址放入esp+0x4位置
00401523 8D45 EC lea eax,dword ptr ss:[ebp-0x14] #將ebp-0x14變數地址裝入eax
00401526 890424 mov dword ptr ss:[esp],eax #將eax變數地址值放入esp位置
現在我們知道重點關注的是儲存返回值的位置ebp-0xC也就是0062FA6C ,接下來F7進入strcpy函式看看是否有事發生。由於棧溢位,儲存位置向下的高地址最可能被覆蓋。
我們快進到strcpy中的關鍵語句
76446819 8917 mov dword ptr ds:[edi],edx
7644681B 83C7 04 add edi,0x4
7644681E BA FFFEFE7E mov edx,0x7EFEFEFF
76446823 8B01 mov eax,dword ptr ds:[ecx]
76446825 03D0 add edx,eax
76446827 83F0 FF xor eax,-0x1
7644682A 33C2 xor eax,edx
7644682C 8B11 mov edx,dword ptr ds:[ecx]
7644682E 83C1 04 add ecx,0x4
76446831 A9 00010181 test eax,0x81010100
76446836 74 E1 je short msvcrt.76446819
這裡4位元組為單位依次存入我們所輸入變數的資料。
76446870 8817 mov byte ptr ds:[edi],dl #將edx低位存入edi
76446872 8B4424 08 mov eax,dword ptr ss:[esp+0x8] #將esp+0x8地址放入eax
76446876 5F pop edi #edi出棧
注意到這裡edi的地址為0062FA6C,也就是我們重點關切的地方,如果這裡被覆蓋為0則會使錯誤的密碼通過驗證
為什麼會引起覆蓋,雖然我輸入的是“88888888”似乎剛好佔用了兩個棧幀,但是一般字串後面會帶有一個空字元,空字元的ascii碼為0,並且入棧方式是從右向左,從高地址到低地址的所以這裡剛好覆蓋了我們的返回值。
利用方式
漏洞觸發的地方是在verify_password函式中的strcmp函式的返回值,在strcpy函式中進行賦值的過程中,棧溢位導致高地址的棧幀資料被覆蓋,從而改變了返回值,使程式驗證判定出現錯誤。
- 利用字串覆蓋返回值
首先我們知道strcmp的返回值有三種情況
大於返回00000001 可以通過構造字串進行覆蓋,利用字串結尾的空字元
等於返回00000000
小於返回FFFFFFFF 不太容易進行構造覆蓋,因為\0無法輸入
- 利用字串覆蓋返回地址
這種方式在原始碼的方式難以進行,具體思路是:
將字串覆蓋到EIP地址,通過修改返回地址為“congratulation~”對應地址,直接跳轉到驗證成功語句。
- 利用惡意程式碼修改程式
由於棧溢位導致覆蓋的漏洞,導致惡意程式碼可以肆意尋找著陸點,如修改程式走向,這裡不詳細介紹。
- 轉載請註明出處:https://www.cnblogs.com/merk11/