By WinsOn @ Cybersword
In the classic stack overflow model, the return address of the function is overwritten to control the program execution flow (EIP register). Generally, the return address is overwritten with 0x7FFA4512, this address is a jmp esp command. When the function returns, it jumps to this address for execution, that is, jmp esp. At this time, ESP just points to the Shellcode we set on the stack, then the Shellcode is executed.
The reason why data on the stack can be executed is that the early operating system did not differentiate data and code, and the EIP can be executed wherever it points.
When DEP (Data Execution Prevention Data Execution Protection) is introduced, the Memory Page attributes on the heap and stack no longer have executable attributes by default. If you want to directly execute Data on the stack, an error occurs:
Return Oriented Programming, also known as Ret2Libc, is a commonly used technical room that bypasses DEP. The so-called ROP Gadget is a series of commands ending with retn. All these Gadget commands can be combined to complete specific tasks. For example, you can call VirtualProtect to add executable attributes to the specified memory block.
For the purpose of stable utilization, it is required that the selected Gadget address be fixed. No matter when it is, it directs to the desired command. The concept of ASLR is introduced here.
The full name of ASLR is Address Space Layout Randomization, that is, Address Space pattern Randomization. ASLR makes it unnecessary to use a fixed base address for loading the program. This technology requires the dual support of the operating system and applications so that ASLR can play a normal role. The program that supports ASLR sets the IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE ID in the PE Header to indicate that it supports ASLR.
You can use Visual Studio to configure project properties so that binary files support ASLR:
ASLR mainly affects the following parts:
1. Module randomization
When the system maps the PE file to the memory, the base address loaded to the file is randomly processed. The address is determined when the system starts. The address changes after the system restarts ., Use Ollydbg to load an application and view the module list:
After restarting the operating system, check again and find that all the base addresses have changed:
2. Stack randomization
Each time a program is loaded, the base address of the heap and stack in its memory space changes. The address of the variable in the memory also changes.
3. PEB/TEB randomization
Since Windows XP SP2, the addresses of PEB and TEB are no longer fixed.
However, it is very rare that someone uses a fixed address to obtain the PEB and TEB pointers, but uses the fs register for location.
TEB can be obtained using FS: [18 h]
PEB can be obtained from 30 h of TEB offset
Common ASLR bypass methods include:
1. Attack the module where ASLR is not enabled
Although image randomization exists, ASLR-enabled modules may not exist in the process. The previously mentioned drop-down technique requires obtaining a Gadget from a fixed address. If there is a module in the process that does not enable ASLR, you can obtain the Gadget from that module. Using the OD OllyFindAddr plug-in, you can quickly find the modules in the process space that are not enabled with ASLR.
2. HeapSpray Technology
Although stack randomization exists, HeapSpray technology will deploy ShellCode to 0x0C0C0C0C (or other specified addresses, usually this address is relatively large) and will not be affected by stack randomization. As a matter of fact, when HeapSpray bypasses DEP using the drop object (ROP), it uses the aforementioned "attack against the ASLR module not enabled ". However, HeapSpray places ShellCode on the stack.
3. Overwrite some return addresses
In image randomization, although the base address of the module loading changes, the low-level words of the entry point addresses of each module remain unchanged, and only the high-level words are randomly processed.
For the address 0 × 12345678, the part 5678 is fixed. If there is a buffer overflow, You can overwrite the last two bytes through memcpy. You can set it to 0 × 12340000 ~ Any value in 0x1234FFFF.
If it is overwritten by strcpy, because strcpy copies the end character 0 × 00 at the end, it can overwrite 0 × 12345678 to 0 × 12345600, or 0 × 12340001 ~ 0x123400FF.
Partial return address overwrites ensure that the distance between the covered address and the base address is fixed. You can find the applicable jump instruction from the vicinity of the Base Address.
This method is not universally applicable because the Cookie on the stack will be damaged when the returned address is overwritten. However, for specific analysis of specific problems, various situations need to be considered to bypass the operating system's security protection mechanism.
4. Java Applet Spray
The memory space dynamically applied in Java Applet has the executable attribute (PAGE_EXECUTE_READWRITE). Similar to HeapSpray technology, you can allocate skateboard commands (such as NOP) and ShellCode on fixed addresses, go to the address to run the command. Unlike the conventional HeapSpray, the maximum size of the Applet application space is 100 MB, while the conventional HeapSpray can reach 1 GB.
5. JIT Spray
JIT (Just In Time Compilation) instant Compilation, that is, the interpreter (such as the Python interpreter ).
The main idea is to perform a lot of XOR operations in the ActionScript code. Then, it is compiled into bytecode and updated to the Flash VM multiple times. In this way, it creates many memory blocks with malicious Xor operations. For example, a sequence is:
Var y = (0x11223344 ^ 0x44332211 ^ 0x4433221 );
The interpreter is interpreted:
If you jump to a byte in the middle to start code execution, the result is another scene:
For more information about JIT, see Pointer Inference and JIT Spraying and Writing JIT-Spray shellcode for fun and profit.
6. The SharedUserData-based method proposed by Tombkeeper on CanSecWest 2013
From Windows NT 4 to Windows 8, the location of SharedUserData is always fixed on address 0x7ffe0000. From the WRK source code nti386.h and ntamd64.h, we can see that:
# Define MM_SHARED_USER_DATA_VA 0x7FFE0000
On x86 Windows, you can see through Windbg:
0: 001> dt _ KUSER_SHARED_DATA SystemCall 0x7ffe0000
Ntdll! _ KUSER_SHARED_DATA
+ 0 × 300 SystemCall: 0x774364f0
0x7ffe0300 always points to KiFastSystemCall
0: 001> uf poi (0x7ffe0300)
Ntdll! KiFastSystemCall:
774364f0 8bd4 mov edx, esp
774364f2 0f34 sysenter
774364f4 c3 ret
Disassemble the NtUserLockWorkStation function and find that it enters the kernel through 7ffe0300:
0: 001> uf USER32! NtUserLockWorkStation
USER32! NtUserLockWorkStation:
75f70fad b8e6110000 mov eax, 11E6h
75f70fb2 ba0003fe7f mov edx, offset SharedUserData! SystemCallStub (7ffe0300)
75f70fb7 ff12 call dword ptr [edx]
75f70fb9 c3 ret
Here, 11E6 is the service number of NtUserLockWorkStation (0x01E6 service in ShadowSSDT). You can see through Xuetr:
In this way, the register content should be properly arranged before the vulnerability is triggered, and the function is used to fill the EAX register with the service number in the System Service (SSDT/Shadow SSDT), and then the EIP is redirected to the corresponding place for execution, you can call the specified function. However, there are also great limitations: it only works on x86 Windows; it is almost impossible to call functions with parameters.
For 64-bit Windows systems, 0x7ffe0350 always points to the function ntdll! LdrHotPatchRoutine.
The HotPatchBuffer struct is defined as follows:
Struct HotPatchBuffer {
ULONG NotSoSure01; // & amp; 0 × 20000000! = 0
ULONG NotSoSure02;
USHORT PatcherNameOffset; // structure relative offset address
USHORT PatcherNameLen;
USHORT PatcheeNameOffset;
USHORT PatcheeNameLen;
USHORT UnknownNameOffset;
USHORT UnknownNameLen
};
LdrHotPatchRoutine call method:
Void LdrHotPatchRoutine (struct * HotPatchBuffer );
Properly deploy the register content before triggering the vulnerability, reasonably fill in the content of the HotPatchBuffer struct, and then call LdrHotPatchRoutine.
For webpage Trojans, you can specify to load a DLL file from a remote address;
If the DLL has been packaged and sent to the victim through other methods, run the local load DLL command.
This method usually requires HeapSpray to assist in the layout of memory data, and requires the file sharing server to store malicious DLL; it only works for 32-bit applications on 64-bit systems; not applicable to Windows 8 (patched ).
References and additional reading:
0-day security * software vulnerability analysis technology, Version 2, Wang Qing
Pointer Inference and JIT Spraying
Writing JIT-Spray shellcode for fun and profit (Chinese Version)
DEP-ASLR bypass without ROP-JIT