Bypassing Windows DEP (Data Execution Prevention)

Bypassing DEP on Windows XP Service Pack 2 Using ZwSetInformationProcess

Fahri Shihab
7 min readSep 18, 2020

Introduction

Welcome to the 2nd writeup for MS08–067 exploit development. If you haven’t read the previous post, I suggest you go through that first so we can be on the same page.

In the previous post, we disabled DEP completely by switching it to AlwaysOff. However, in a real world scenario, this is unlikely.

You should have a brief idea on what DEP is, and you can get more information from their official documentation.

Modes of DEP

In short, there are 4 modes of Data Execution Prevention. Quoting from one of Corelan’s write up:

  1. AlwaysOn : Indicates that all processes are protected by DEP (no exceptions). In this mode, DEP cannot be turned off at runtime.
  2. AlwaysOff : Indicates that no processes are protected by DEP. In this mode, DEP cannot be turned on at runtime. On 64bit Windows systems, DEP is always turned on and cannot be disabled. Keep in mind that Internet Explorer is still a 32bit application (and is subject to the DEP modes described above).
  3. OptIn: Enables Data Execution Prevention for core system images and those specified in the DEP configuration dialog. OptIn enables DEP only for operating system components, including the Windows kernel and drivers. Administrators can enable DEP on selected executable files. This is the Windows default setting.
  4. OptOut: User can specify applications that would be OptOut of DEP. If application is not listed in Exceptions then DEP is enabled for that application.

How DEP Protects You

Set back your DEP mode to OptOut. Attach svchost on immunity debugger and set a breakpoint at

0x7C941EED   FFE4   JMP ESP ==> This will be our EIP replacement

Run the previous exploit, and you should reach your breakpoint. Step into (f7) and then you will see an access violation like this screenshot.

Access Violation due to DEP

This happens because DEP did its job, preventing the program to execute code.

The Principal

Bypassing DEP to achieve code execution is cool, but the principal is even better. A good reference to understand this is Bypassing Windows Hardware-enforced Data Execution Prevention Paper”, Skape and Skywing 10/2005.

Here is a graphical view from IDA

Graph View of ntdll!LdrpCheckNXCompatibility

If you notice on the first graph at address 7C91D3F8,

7C91D3F8   3C 01            CMP AL,1

It’s going to compare the lower bytes of EAX (AL) to 1. So we’re going to have to set AL to 1.We can use this instruction

ntdll!NtdllOkayToLockRoutine:7c952080 b001             mov     al,0x1
7c952082 c20400 ret 0x4

I won’t be going into the details of the concept, because Skape and Skywing already did a fantastic job there!

Modifying The Exploit

Bypassing NX

Referring back to our previous exploit. We must first redirect EIP to 7C952080 to set AL to 1.

Once that is set up, we can return it to where it compares AL to 1 at 7C91D3F8

Now try and run the program. Don’t forget to set a breakpoint at 7C952080 where it sets AL to 1.

Breakpoint at 7C952080

Breakpoint hit, which is a good sign. Now step into each of the instructions (f7). You will notice that it follows through like the graph above.

Access Violation Because EBP Is Invalid

You will also run into an error with access violation while trying to write to 4141413D. This is because the instruction at 7C93FEBA writes the content of ESI to [EBP-4]. The current situation for us is that EBP is not a valid address. It is 41414141. No wonder it cannot write there.

Now our task is to make sure EBP points to a valid address. Since EDI is close to the beginning of our buffer, we will copy the address of EDI to EBP. This can be achieved with the following instructions

PUSH EDI
POP EBP

We can search for that instructions in immunity debugger by

Right Click -> Search for -> All sequences in all modules and put those instructions.

Find sequences

It takes a few seconds, and you will see something like this pop up.

The green fonts are the ones that match our search sequence. I will be using module NTMARTA.dll address 776978C7.

NTMARTA.dll at 776978C7

Modify our exploit again to include that address, before jumping to 7C91D3F8, we jump to the PUSH EDI instruction. This is what it looks like.

Run the exploit, don’t forget the breakpoint at 7C952080 and see the difference 😊.

If you did all those steps correctly, you should see the NX is successfully bypassed. You can verify this by checking the EAX register when the call to ZwSetInformationProcess is done. Check the screenshot below.

NX bypassed, EAX is 0

You may have noticed, when you resume the execution, you are greeted with this error.

The Final Payload

We are so close to getting remote code execution. If you pay attention and step into slowly, you will reach this point.

Before RETN 4
After RETN 4

If you look closely at ESP, you can see that at 030EF450 it is AAAA (41414141), which is one of the buffers we send in the beginning of our payload. Do another pattern of 18 to know which exact offset that is.

This is what the exploit looks like now

Run it again, don’t forget to set the breakpoint at 7c91d443, at the RETN 4 command.

EIP is 31614130 and that is the 2nd offset. Now we want to change that to a JMP ESP instruction. Search that on ntdll.dll, and we find the following

7C941EED   FFE4             JMP ESP

This is the exploit now.

Run it again and inspect again.

We made it there! Getting closer!

From the dump, we can see the code to be executed is the 5th-8th part of the CC buffer. The 40 CC bufer (line 64 of the exploit) is at address 011CF46C which is 24 bytes away (18 in hex). So we can replace that with a short jump of 18 bytes. The operand for that is EB 18. So hopefully this should land on our payload at line 64. 🙏

Run again and inspect again. Don’t get tired of this 😃

Hard work gives results, we got there!

Now, just 2 more things to do.

  1. Replace the CC buffers with an egghunter
  2. Replace the server UNC buffer content with a choice of payload.

This is the same as what we did in the previous post.

This is what the exploit looks like now

Now you can run it again. This time we don’t need to set a payload, because our UNC buffer content already has xCC which is a breakpoint. The program will pause when it reaches there. Just wait for it 😉

YES! WE MADE IT!

Ok final step, PROMISE! just replace the Server UNC buffer content with an actual payload. Don’t forget to adjust the Server UNC Max buffer content and actual content. I’ll be using the same payload as the previous post again.

And as usual, I will be printing the netstat -ano command to see the open ports before and after the exploit ran.

Here is the output

Congratulations! 🥳 Port 4444 successfully opened. You can also see the Data Execution Protection is set to OptOut. In the next write up we will bypass the AlwaysOn mode, stay tuned and have fun!

References

--

--