## 一.實(shí)驗(yàn)環(huán)境:
```
操作系統(tǒng) Windows XP SP3
開發(fā)環(huán)境 VC++ 6.0
調(diào)試器 Ollydbg
```
## 二.實(shí)驗(yàn)代碼:
```
#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;
}
}
}
```
## 三.溢出原理
程序未對輸入的密碼進(jìn)行長度檢測,接收密碼的緩沖區(qū)只有8,而輸入的密碼最長可以輸入1024。判斷密碼是否正確的變量authenticated存儲在棧中,當(dāng)輸入的密碼長度大于8時(shí),輸入的字符串將沖破緩沖區(qū),淹沒authenticated所處的位置。當(dāng)密碼錯(cuò)誤時(shí)authenticated的值是1,正確的時(shí)候authenticated的值是0.這就意味著我們可以構(gòu)造一個(gè)合適的輸入字符串來改變判斷結(jié)果。
## 四.實(shí)戰(zhàn)調(diào)試
我們的重點(diǎn)不是逆向工程,而是漏洞分析,故此不再詳訴諸如尋找main函數(shù)等逆向知識。
1.在jmp mai下斷點(diǎn),方便后續(xù)反復(fù)調(diào)試

2.單步步入main函數(shù)分析程序

3.分析main函數(shù)邏輯,可以看出主要問題出在密碼比對函數(shù)00401005
3.1輸出引導(dǎo)字符串后,要求用戶輸入密碼。

3.2通過00401005處的函數(shù)進(jìn)行密碼比對

3.3判斷比對結(jié)果是不是0,如果是0則輸出成功字符串,如果是1則輸出失敗字符串。

4.單步執(zhí)行程序,隨便輸入一個(gè)密碼,然后單步步入00401005函數(shù),分析這個(gè)函數(shù)的內(nèi)容。

4.1可以看出這個(gè)00401005是個(gè)跳轉(zhuǎn),直接單步進(jìn)入函數(shù)真實(shí)位置。

4.2進(jìn)入到函數(shù)內(nèi)部后可以看到真正的密碼是1234567,如果我們是在逆向破解這個(gè)程序,那么到了這一步,就已經(jīng)算是成功了。但是我們的目的是分析漏洞,所以我們現(xiàn)在進(jìn)一步分析這個(gè)函數(shù)。

4.2.1可以看出,在strcmp之后,ebp-4的位置上就有了密碼比對的結(jié)果
4.2.1.1strcmp比對密碼,將比對結(jié)果存入ebp-4的位置上

4.2.1.2棧中的密碼比對結(jié)果

4.2.2如果是正常的程序,這個(gè)時(shí)候就應(yīng)該返回了,但是因?yàn)槭菍?shí)驗(yàn)代碼,所以下面還有一個(gè)strcpy的拷貝函數(shù),將輸入的密碼字符串拷貝入一個(gè)長度為8的緩沖區(qū)中。

4.2.3當(dāng)執(zhí)行完strcpy的時(shí)候我們看一下堆棧區(qū),可以看到字符串緩沖區(qū)的位置就在密碼字符串比對結(jié)果旁邊,并且strcpy沒有對拷貝入的字符串進(jìn)行長度判斷。因此我們可以判斷,我們在構(gòu)造一個(gè)合適的字符串傳入的情況下,是可以覆蓋密碼字符串比對結(jié)果的。這也意味著我們可以傳入一個(gè)合適的字符串來沖破密碼驗(yàn)證。

5.我們重新加載這個(gè)程序,并且傳入一個(gè)特定的字符串“qqqqqqqq”

6.運(yùn)行到密碼比對函數(shù)進(jìn)行分析
6.1可以看出strcmp函數(shù)沒有任何問題的執(zhí)行成功并且返回了1,代表密碼錯(cuò)誤。并且把存儲在eax中的返回值存儲到ebp-4的位置上。
6.1.1函數(shù)執(zhí)行

6.1.2返回值存儲在eax中

6.1.3 eax中的值mov到了ebp-4的位置上

6.2下面到了引起溢出錯(cuò)誤的strcpy函數(shù),詳細(xì)分析該函數(shù)溢出的過程。
6.2.1首先記錄一下strcpy沒有執(zhí)行前堆棧的情況

6.2.2 執(zhí)行strcpy函數(shù)

6.2.3 可以看到,堆棧中原本保存著密碼比對結(jié)果的位置ebp-4,由于傳入字符串超長,已經(jīng)被覆蓋成了0。這樣一來,原本比對失敗的結(jié)果就變成了比對成功。

7.運(yùn)行至返回,成功輸出密碼比對成功的信息

7.1控制臺成功信息

8.那么是任何長于1234567的字符串都可以成功覆蓋比對結(jié)果嗎,嘗試一下,輸入9個(gè)q,可以看到,對比結(jié)果的位置上并沒有被覆蓋成00,而是71,而只有對比結(jié)果等于0才可以成功驗(yàn)證。這說明不是任意長度字符串都可以。

9.那么有什么結(jié)果可以覆蓋成整好是0呢,那么答案是長度為8的字符串,長度為8的字符串實(shí)際長度為9,因?yàn)檫€有用來標(biāo)記字符串結(jié)束的00,我們就是要使用結(jié)尾處的00來覆蓋對比結(jié)果,使其數(shù)值為0。

參考材料:《0day安全:軟件漏洞分析技術(shù)》