DEP (Data Execution Prevention) was introduced in Windows in 2004 with Windows XP Service Pack 2 which ensures that data does not gets executed unless it has execute memory rights (PAGE_EXECUTE). To bypass DEP we will use ROP (Return Oriented Programming) gadgets. I have also provided MS Visual Studio solution in a zip for testing.
What is ROP ?:
After the introduction of ASLR (Address space layout randomization) shellcodes which had hardened addresses of the APIs started to fail. For example API UrlDownloadToFileA was located at 0x781C4868 in windows XP SP3 even after reboot. Hence it was very easy to develop exploits and shellcodes. From Windows 7 onwards, most of the essential modules started to load at random addresses after every reboot (due to ASLR) which failed all previous shellcodes / exploits which had defined fixed addresses in their exploits. But few remained ASLR disabled (msvcr71.dll, msxml15.dll etc ) which are still loaded at the fixed addresses in similar builds of Windows even after reboots. This gives an opportunity to use some of the code section (gadgets) in an artful way to change memory protection rights of shellcode area. For example, we can find the instructions necessary to prepare the arguments on stack and then call the VirtualProtect function to change the memory rights of shellcode region and then execute it. This can be done by first calculating the instructions which could do this and then populating it on stack in a manner that there is a "ret" instruction at the end of those instructions. When "ret" gets executed OS will pop an address from ESP (stack pointer) and transfer control to that instructions and so on and so forth. Once all parameters to VirtualProtect /VirtualAlloc are prepared a JMP instruction to VirtualProtect will change memory permissions of shellcode region and hence DEP will be bypassed.Purpose of ROP:
- Change memory region rights (or allocate memory) of shellcode to PAGE_EXECUTE or PAGE_EXECUTE_READWRITE (DEP bypass)
- Change EIP control to ROP chain (stack pivot)
- Execute shellcode
This Blog:
- Using C for demonstration of ROP
- ROP gadgets creation using mona.py (immunity debugger's extension) in msvcr71.dll
- Use of VirtualProtect function for changing memory rights
Requirements:
Steps:
- Set up VS project ( Download VS project )
- Create ROP chains /suggestion using mona
- Build the exe and open with Immunity or windbg. Program will halt on software breakpoint (int 3) instruction defined in inline assembly
- Step into ROP gadgets and see the behavior of ROP chain. When arguments to VirtualProtect are prepared, PUSHAD instruction pushes arguments on stack and returns which is a jump to VirtualProtect function.
- Shellcode will get executed and calculator will popup showing the successful bypass of DEP by ROP
Build and test environment: Windows 7 x64 SP1
1. Setup project:
Open the .sln file with Visual studio or create new project in visual studio and copy paste the rop_x86.cpp file contents in main file and build the solution. We will use msvcr71.dll for creating ROP chain. This dll is loaded most of the times, but if it isn't loaded already, we can use LoadLibrary API to load it. In this example i have loaded it using LoadLibrary as you can see in the code.
2. Creating ROP Chains:
Here i assume that you have installed mona in immunity by now. Now to check which modules (dlls) are ASLR disabled give this command !mona noaslr in the command window at the bottom as shown in image 2.1
Image 2.1
-------------
You can see that there is one module which is ASLR disabled, means we can use this module to generate rop chain. To generate gadgets provide command !mona rop -m msvcr71.dll which will create three files namely rop.txt, rop_suggetsions.txt and rop_chains.txt. Rop_chains.txt will contain nicely prepared rop gadgets in different languages like C, python and ruby. Image 2.2 shows the output of rop generation command.
Image 2.2
-------------
I have used some of these gadgets and some of my own. You can search for specific gadgets in rop.txt and rop_suggestions.txt files. Some of the gadgets created by mona are shown in image 2.3.
Image 2.3
3. Analysis of ROP with Windbg / Immunity:
Execute the binary and it will break at instruction "int 0x03" as shown in image 3.1. As breakpoint will hit, source file will be loaded and we will be able to see the source as well. Then step into using F11. Next instruction will add 0xd0 to ESP. Actually rop gadgets and shellcode declared in char ROP_shellcode[] are pushed on stack. To trigger the rop chain we have to point ESP to first gadget and execute the "ret" instruction. In real world exploits it is called stack pivot (usually xchg eax,esp ; ret) but in this scenario i have simplified it by pointing ESP to rop chain and then executing "ret" instruction manually. Difference of ESP and rop chain is shown in image 3.2 and difference is evaluated in image 3.3.
Image 3.1
-------------
Image 3.2
-------------
Image 3.3
-------------
Image3.4 shows the rop chain in immunity debugger. By stepping in you can see the execution of rop step by step.
Image 3.4
-------------
4. ROP Chain Execution:
From here on we will be executing rop chain. Stepping in using F11 will give a fair idea that how rop gadgets are executed. You will notice that every instruction is followed by "ret" which triggers another gadget until the purpose is achieved. Thats why this is called return oriented programming (ROP).
Image 4.1
-------------
Here (image 4.2) is the chain with symbols (dps display addresses with symbols) showing addresses of msvcr71.dll
Image 4.2
-------------
Main purpose of this chain is to prepare arguments to VirtualProtect in registers in an order that when "PUSHAD" intruction is executed, stack should be prepared in following order (image 4.3) at gadget 0x7c3415a2.
Here is little description of VirtualProtect from MSDN.
Here is little description of VirtualProtect from MSDN.
BOOL WINAPI VirtualProtect( => A pointer to VirtualProtect() _In_ LPVOID lpAddress, => Address whose rights have to be changed (some address down the ESP) _In_ SIZE_T dwSize, => dwSize up to you to chose as needed (0x201) _In_ DWORD flNewProtect, => flNewProtect (0x40) _Out_ PDWORD lpflOldProtect => A writable pointer );
Following image shows the stack when VirtualProtect is called via a jump to pointer ( to VirtualProtect) stored in EAX.
Image 4.3
-------------
To see the memory rights at this point use !address esp command which will show the memory rights of the page as given in image 4.4
Image 4.4
-------------
5. Identifying successful DEP bypass:
Set a breakpoint at gadget pointed by ESP (bp 7c35630c) and run the sample using F5 command or "g". When breakpoint hits, check the memory rights using !address esp command. You will notice that the page will have PAGE_EXECUTE_READWRITE protection rights as shown in image 5.1.
Image 5.1
-------------
After confirming memory rights elevation, we can give command "g" in command panel which should popup the calculator (image 5.2) if everything goes well. In my tests i have observed that sometimes stack is not aligned and an exception occurs, in that case just re-run the sample and it will run fine.
Image 5.2
-------------
You can also visit these links which are more rop development-centric rather than reversing / analysis of rop gadgets:
Enjoy exploiting!!!