## 一.實驗環(huán)境:
```
操作系統(tǒng) Windows XP SP3
開發(fā)環(huán)境 VC++ 6.0
調(diào)試器 Ollydbg
```
## 二.實驗代碼:
```
#include <stdio.h>
#include<string.h>
#define PASSWORD "1234567"
int verify_password (char *password)
{
int authenticated;
char buffer[8];
authenticated=strcmp(password,PASSWORD);
strcpy(buffer,password);
return authenticated;
}
main()
{
int valid_flag=0;
char password[1024];
while(1)
{
printf("please input password: ");
scanf("%s",password);
valid_flag = verify_password(password);
if(valid_flag)
{
printf("incorrect password!nn");
}
else
{
printf("Congratulation! You have passed the verification!n");
break;
}
}
}
```
## 三.溢出原理
程序未對輸入的密碼進行長度檢測,接收密碼的緩沖區(qū)只有8,而輸入的密碼最長可以輸入1024。判斷密碼是否正確的變量authenticated存儲在棧中,當輸入的密碼長度大于8時,輸入的字符串將沖破緩沖區(qū),淹沒authenticated所處的位置。當密碼錯誤時authenticated的值是1,正確的時候authenticated的值是0.這就意味著我們可以構(gòu)造一個合適的輸入字符串來改變判斷結(jié)果。
## 四.實戰(zhàn)調(diào)試
我們的重點不是逆向工程,而是漏洞分析,故此不再詳訴諸如尋找main函數(shù)等逆向知識。
1.在jmp mai下斷點,方便后續(xù)反復(fù)調(diào)試
![圖片描述](/upload/attach/201811/201811281016_RSU94EXGY2ANDNK.png)
2.單步步入main函數(shù)分析程序
![圖片描述](/upload/attach/201811/201811281017_J23FBFCJTGBB57B.png)
3.分析main函數(shù)邏輯,可以看出主要問題出在密碼比對函數(shù)00401005
3.1輸出引導(dǎo)字符串后,要求用戶輸入密碼。
![圖片描述](/upload/attach/201811/201811281017_9GPNXMB4X9DGTHS.png)
3.2通過00401005處的函數(shù)進行密碼比對
![圖片描述](/upload/attach/201811/201811281018_XXU7U29EPD6884H.png)
3.3判斷比對結(jié)果是不是0,如果是0則輸出成功字符串,如果是1則輸出失敗字符串。
![圖片描述](/upload/attach/201811/201811281018_8E4XWEYCR9399GM.png)
4.單步執(zhí)行程序,隨便輸入一個密碼,然后單步步入00401005函數(shù),分析這個函數(shù)的內(nèi)容。
![圖片描述](/upload/attach/201811/201811281018_KR39VDTCXVPQNB9.png)
4.1可以看出這個00401005是個跳轉(zhuǎn),直接單步進入函數(shù)真實位置。
![圖片描述](/upload/attach/201811/201811281018_MDE763Y9E9US7A8.png)
4.2進入到函數(shù)內(nèi)部后可以看到真正的密碼是1234567,如果我們是在逆向破解這個程序,那么到了這一步,就已經(jīng)算是成功了。但是我們的目的是分析漏洞,所以我們現(xiàn)在進一步分析這個函數(shù)。
![圖片描述](/upload/attach/201811/201811281019_KZ8WYXPAS5VBT92.png)
4.2.1可以看出,在strcmp之后,ebp-4的位置上就有了密碼比對的結(jié)果
4.2.1.1strcmp比對密碼,將比對結(jié)果存入ebp-4的位置上
![圖片描述](/upload/attach/201811/201811281019_D4KJNBPM4SHJYVC.png)
4.2.1.2棧中的密碼比對結(jié)果
![圖片描述](/upload/attach/201811/201811281019_CEPWYM3SUZQR85S.png)
4.2.2如果是正常的程序,這個時候就應(yīng)該返回了,但是因為是實驗代碼,所以下面還有一個strcpy的拷貝函數(shù),將輸入的密碼字符串拷貝入一個長度為8的緩沖區(qū)中。
![圖片描述](/upload/attach/201811/201811281019_JEUJVBG2UAXBGUW.png)
4.2.3當執(zhí)行完strcpy的時候我們看一下堆棧區(qū),可以看到字符串緩沖區(qū)的位置就在密碼字符串比對結(jié)果旁邊,并且strcpy沒有對拷貝入的字符串進行長度判斷。因此我們可以判斷,我們在構(gòu)造一個合適的字符串傳入的情況下,是可以覆蓋密碼字符串比對結(jié)果的。這也意味著我們可以傳入一個合適的字符串來沖破密碼驗證。
![圖片描述](/upload/attach/201811/201811281020_FBYCZBNZTXJSPXB.png)
5.我們重新加載這個程序,并且傳入一個特定的字符串“qqqqqqqq”
![圖片描述](/upload/attach/201811/201811281020_PHZM85HZWD9Y95G.png)
6.運行到密碼比對函數(shù)進行分析
6.1可以看出strcmp函數(shù)沒有任何問題的執(zhí)行成功并且返回了1,代表密碼錯誤。并且把存儲在eax中的返回值存儲到ebp-4的位置上。
6.1.1函數(shù)執(zhí)行
![圖片描述](/upload/attach/201811/201811281020_M8GBB2SETAADX47.png)
6.1.2返回值存儲在eax中
![圖片描述](/upload/attach/201811/201811281020_GF6P7K8ZE3U5KK7.png)
6.1.3 eax中的值mov到了ebp-4的位置上
![圖片描述](/upload/attach/201811/201811281020_JFTRC4N2YQ65636.png)
6.2下面到了引起溢出錯誤的strcpy函數(shù),詳細分析該函數(shù)溢出的過程。
6.2.1首先記錄一下strcpy沒有執(zhí)行前堆棧的情況
![圖片描述](/upload/attach/201811/201811281021_843XH6HCP65AQS6.png)
6.2.2 執(zhí)行strcpy函數(shù)
![圖片描述](/upload/attach/201811/201811281021_CUN3HG8CABXJW98.png)
6.2.3 可以看到,堆棧中原本保存著密碼比對結(jié)果的位置ebp-4,由于傳入字符串超長,已經(jīng)被覆蓋成了0。這樣一來,原本比對失敗的結(jié)果就變成了比對成功。
![圖片描述](/upload/attach/201811/201811281021_W7S2DVTN48WKWHS.png)
7.運行至返回,成功輸出密碼比對成功的信息
![圖片描述](/upload/attach/201811/201811281021_K78ETMGTJZ8E9CN.png)
7.1控制臺成功信息
![圖片描述](/upload/attach/201811/201811281022_2SXAPW82MUSS7HU.png)
8.那么是任何長于1234567的字符串都可以成功覆蓋比對結(jié)果嗎,嘗試一下,輸入9個q,可以看到,對比結(jié)果的位置上并沒有被覆蓋成00,而是71,而只有對比結(jié)果等于0才可以成功驗證。這說明不是任意長度字符串都可以。
![圖片描述](/upload/attach/201811/201811281022_ZWAU98TSFPEPZFK.png)
9.那么有什么結(jié)果可以覆蓋成整好是0呢,那么答案是長度為8的字符串,長度為8的字符串實際長度為9,因為還有用來標記字符串結(jié)束的00,我們就是要使用結(jié)尾處的00來覆蓋對比結(jié)果,使其數(shù)值為0。
![圖片描述](/upload/attach/201811/201811281022_76KK6WHB964G6JP.png)
參考材料:《0day安全:軟件漏洞分析技術(shù)》