1. 程式人生 > 其它 >棧溢位逆向分析

棧溢位逆向分析

棧溢位漏洞逆向分析

摘要:針對StackOverflow.cpp程式,首先將其編譯為二進位制檔案,進而通過動態逆向分析工具,以彙編指令為粒度,詳細分析指令的功能及漏洞觸發和利用方法。

關鍵詞:棧溢位 逆向分析

工具:Windows10 Dev-C++ Ollydbg[吾愛]

棧溢位漏洞原理

棧溢位屬於緩衝區溢位,指的是程式向棧中某個變數中寫入的位元組數超過了這個變數本身所申請的位元組數,因而導致其寫入與其相鄰的棧,導致相鄰棧中資料改變。

利用方式有:

通過覆蓋某些區域性變數值達到繞過驗證效果

通過移植惡意程式碼並修改返回地址達到某種目的

程式碼逆向分析

  • 首先將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~”對應地址,直接跳轉到驗證成功語句。

  • 利用惡意程式碼修改程式

由於棧溢位導致覆蓋的漏洞,導致惡意程式碼可以肆意尋找著陸點,如修改程式走向,這裡不詳細介紹。