Writing Exploits for Win32 Systems from Scratch

Introduction

This post is aimed at those new to exploit development and wanting to understand the end-to-end process and types of techniques that need to be employed in order to realise a working exploit against a buffer overflow vulnerability. I acknowledge that there are more sophisticated techniques that can be employed in this area however for those looking to get into exploit development using a well-trodden road and against an older operating system helps simplify some of the concepts presented which aids understanding.

In this post, I will show the reader how to write an exploit for a stack-based buffer overflow vulnerability on a POP3 server called SLMAIL (version 5.5).

For the first version of the exploit, we are going to use a Windows XP SP3 English build with DEP in its default state (DEP is enabled by default for essential Windows programs only on Windows XP). We will then learn how to modify the exploit to work on the same system with DEP enabled, how to bypass ASLR to make the exploit work on a Windows 7 machine, and finally how to create a Metasploit module from our exploit and to customise it to cover different operating systems.

Our test lab consists of:

Windows XP SP3 English virtual machine with IP address 192.168.65.176

Windows 7 with IP address 192.168.65.177

Kali Linux with IP address 192.168.65.159

To help us on the development phase we are going to use the following tools:

Immunity Debugger (https://www.immunityinc.com/products/debugger/)

Mona.py (https://github.com/corelan/mona)

Notepad++

Metasploit Framework

First Exploit

The SLMAIL 5.5 POP3 Server has a public vulnerability (CVE-2003-0264) based on a buffer overflow on the stack that can be triggered by abusing the parameter “password” when a user attempts the authentication process.

This simple Python code triggers the vulnerability and makes the server crash:

In the next screenshot we see the effect of executing such code with the process attached to Immunity Debugger. Note that although the vulnerability is in a network service that we can exploit remotely, we use the same Windows virtual machine to develop the exploit to make things easy.

Highlighted in red, we can see that there is an access violation trying to execute the code at the address 41414141. That address is the hexadecimal representation of “AAAA” (four As from our buffer of 6000 As). It is clear that we can control the instruction pointer (EIP), so it is possible to change the program behavior.

Once the vulnerability is known, the next steps to write an exploit for it are listed below:

Find the offset on the buffer to the exact four bytes that overwrite the saved EIP on the stack, which lets us control the execution flow.

Find enough space in memory we can control to store our shellcode.

Find the bad characters that could affect our exploit.

Find the value we must put in the saved EIP to make the execution flow jump to our shellcode stored in memory

You can check if mona.py is working by typing “!mona” in the command bar of the Immunity Debugger. If everything works, the log window will show the help screen of mona.py.

Next, configure mona.py to store data in a folder other than the default. The default location is the Immunity Debugger application folder, and on Windows 7 installations if you don’t run Immunity as Administrator when mona.py tries to store results, it will fail.

!mona config -set workingfolder c:\logs\%p

The code above sets up mona.py to create a folder inside the folder c:\logs, with the name of the process being debugged.

Once mona.py is configured, it is time to start investigating the vulnerability we are trying to exploit.

First we need to find the offset to the bytes that could control EIP. The fastest method to do this is using a feature included in Metasploit, called Metasploit pattern. Inside the framework tools folder, we find the scripts pattern_create.rb and pattern_offset.rb. The former creates a string pattern where every three-character substring is unique (e.g..: Aa0Aa1Aa2Aa3Aa4). The second script is to calculate the offset once we know which four bytes fits inside the EIP when the program crashes.

To make things easier, mona.py can create a unique cyclic pattern like Metasploit does. To create a cyclic pattern 6000 bytes in length with mona.py, the following command must be typed in the Immunity Debugger command bar.

!mona pc 6000

The command creates the file c:\logs\slmail\pattern.txt with the cyclic pattern inside. The pattern must be copied into the Python code. Here is how the poc2.py file would look:

The next step is to attach the slmail process to the Immunity Debugger and run the poc2.py file. The process crashed and Immunity Debugger shows an access violation. We need to look at the EIP value and take note of its value at the crash moment.

To figure out the offset to the EIP control bytes, mona.py offers two options:

!mona pattern_offset 0x7A46317A (where 0x7A46317A is the value of EIP at the crash time)
!mona findmsp

The first method shows the distance to the four bytes that control EIP, in the log window of Immunity.

The second method will create the file c:\logs\slmail\findmsp.txt. The content of the file should look like:

As can be seen, this method offers lots of information. First of all, we can see that EIP contains bytes of the normal pattern at the offset 4654.We can see that ESP points to the cyclic pattern at the offset 4658 just behind the four bytes that control EIP, and mona.py also informs us that we have 430 bytes length to store data.

As a plus, mona.py offers information about several memory locations that contain the cyclic pattern, and several memory pointers that point directly to the cyclic pattern. We now have the information needed to write an exploit.

We can put the shellcode just behind the four bytes that control EIP (at offset 4658) because we know that the register ESP is pointing directly to this address. So to change the flow control of the process and control the execution, we just need to put the memory address of an instruction that makes a jump to the address ESP points to inyo EIP. So we need to find an instruction like jmp esp, call esp, or push esp; ret.

To find these instructions in memory, we are going to use mona.py again. In the Immunity Debugger command bar, after attaching it to the slmail process, we execute:

!mona jmp -r ESP

This command tells mona.py to search for an instruction to jump to ESP inside the process binary and the DLLs loaded in memory on execution time (by default it looks in all DLLs loaded in memory; we can use the -m switch to make it search in DLLs passed as parameters). The result is stored in the file c:\logs\slmail\jmp.txt. Here is part of the file created:

This command tells mona.py to compare the memory from the address given with the content of the bytearray.bin file (if no address is given, the compare function searches for the bytearray in all memory and performs the comparison).

There is corruption in the first byte. Create the byte array again excluding 0x00 and run the “compare” command again. To exclude 0x00 from the byte array use this command on mona.py:

!mona bytearray -cpb \x00

Update the exploit and execute it again with the process attached to the debugger Once the process crashes, execute the following command:

!mona compare -f c:\logs\slmail\bytearray.bin -a 0x01cea154

Now we have to exclude 0x0a:

!mona bytearray -cpb \x00\x0a

Update the exploit, attach the process to the debugger, run the exploit and then compare again:

!mona compare -f c:\logs\slmail\bytearray.bin -a 0x01cea154

The next bad char is 0x0d. Repeat the process:

!mona bytearray -cpb \x00\x0a\x0d

Update the exploit, attach the process to the debugger, run the exploit and then compare again:

!mona compare -f c:\logs\slmail\bytearray.bin -a 0x01cea154

Here is the mona.py result:

As can be seen, the comparison results window says “Unmodified”, which means the byte array in memory is equal to the content of the file bytearray.bin.

Now we know the bad characters affecting our exploit are 0x00 0x0a 0x0d. We just need to put together all the information we have in our proof-of-concept exploit:

In this version of the exploit we use the byte 0xcc that is the opcode of a breakpoint instruction as shellcode. That means that once the exploit is launched our process will stop on 0xcc.

For EIP we use an address extracted from the file c:\logs\slmail\jmp.txt. Remember that x86 architecture stores the values in memory using Little Endian, which means the memory address would have to be reversed byte by byte (for example 0x7c91fcd8 has to be converted to \xd8\xfc\x91\x7c).

Note: be careful with bad characters when you pick up the jmp esp instruction.

Now, attach the process to Immunity Debugger again, set a breakpoint to the address 0x7c91fcd8 (jmp esp) run the process and execute the exploit:

Once the flow stops on the breakpoint we set on jmp esp, move step-by-step in the debugger using the F7 key. Once you press F7, you can check that the next instruction to execute is a CC (the first byte of our shellcode).

That means we are controlling the execution flow.

Now we need to replace the current shellcode with a real one, maybe a Meterpreter bind tcp generated with Metasploit.

Avoid using bind shells in real-world exploits because anyone with the appropriate network access could connect to them and gain unauthorised access to the victim machine. For training conditions bind shells are fine. In the real world it is much safer to launch a reverse shell to a computer under our control.

Note that when you generate a Metasploit shellcode encoded to avoid certain bad characters, within the payload itself is a routine in charge to decode the payload. That routine uses the stack to push and pop values, so we need to move ESP to a location above the shellcode injected in memory (remember we were putting the shellcode just where ESP was pointing).

First, we use Kali Linux with Metasploit to generate the shellcode. The command to generate the shellcode is:

This shellcode will bind TCP port 4444 (default port on Metasploit that can be changed with the LPORT option) on the interface with the IP address 192.168.65.176 to connect a Meterpreter session:

Then, to ensure ESP is not pointing to the shellcode when the decoder routine is executed, we add an instruction to decrement ESP (sub esp 240h). To obtain the opcodes that represent the instruction, we use a tool from the Metasploit Framework, metasm_shell.rb.

In the following screenshot we see the use of metasm_shell.rb to generate the opcodes we need:

As we can see, if we generate the opcodes of “sub esp,240h” the opcodes generated contain bad characters (0x00). We solve this by adding to esp a negative number: “add esp,-240h”. The “h” in the operation indicates that we are adding 240 in hex, not in decimal.

Then we add the opcodes to the start of the shellcode and insert it in our exploit:

Then restart the process and execute the exploit. If all goes right, this is the result on the Windows box:

And now that port can be used to connect a Meterpreter session from our Kali Linux:

SLMail 5.5 got Pwned!!!

DEP Bypass

DEP stands for Data Execution Prevention and is a countermeasure that avoids code execution on the stack.

First we enable DEP for all programs on the Windows XP box (by default it is just enabled for essential Windows programs and processes). The box must be rebooted for the changes to take effect.

Once DEP is enabled, try to run the exploit with the process slmail attached to the debugger.

As we can see, there is an access violation when executing “add ESP,-240”, just the first instruction we used in our exploit to move ESP away from the shellcode.

This is because DEP forbids the execution of code in the stack; right now the stack just contains pointers to instructions that are in other parts of memory where the code execution is permitted.

To solve this, we can use the return to libc technique; simply look in memory for pointers to instructions we want to execute followed by a RET instruction to chain all the instructions on the stack.

This technique is known as ROP (return-oriented programming), the set of instructions referenced by the pointers are known as ROP gadgets, and the set of pointers to instructions is the ROP chain.

A little bit of ROP theory:

EIP is the instruction pointer, and its value is the address of the following instruction being executed.

A RET instruction just pops the top value on the stack and loads it in EIP, then the value on the top of the stack (pointed to by ESP) will be the next instruction to call.

If we overwrite EIP with a pointer to RET instructions and put a set of pointers to instructions that ends with a RET on the stack, we manage to chain all those instructions to perform the actions we want (take note that instructions like “push” or “pop” modify the stack, so it needs to be set up properly).

Here is an example of how ROP works:

We overwrite EIP with address 0x77c46027 (pop ecx, ret). Then we set up the stack to make sure the “pop ecx” instruction pops the “0xffffffff” value to ECX and the RET, and gets the pointer to the next instructions to execute.

This is the stack after executing those instructions:

We are ready to execute the next instruction in the chain.

Using ROP we can try to make an entire shellcode if we find enough gadgets to do it, but this very often is not possible. Luckily Windows offers some API calls that make our life easy. Using the API functions we can change the protection mode of a piece of memory or even allocate more memory for the process, making it executable. Once achieved, we can put our shellcode in that piece of memory and execute it.

There are many API functions we can use depending on Windows version, but VirtualAlloc and VirtualProtect are reliable and work in most Windows versions.

VirtualProtect changes the protection on a region of committed pages in the virtual address space of the calling process.

Syntax

Here we pass a pointer to an address that describes the start of the region, the size in bytes of the region whose protection attributes are to be changed, the type of protection desired (0x40), and a pointer to a variable that receives the current protection value. Ifs this parameter is null or points to a non-valid address the function fails.

After the theory about ROP and Windows API functions, let’s see how to use this to write an exploit with the help of mona.py.

In rop_chains.txt you can find some ready-to-use functions to make a rop chain calling VirtualAlloc or VirtualProtect to change the protection of the stack. You are going to need this in your exploit, and mona.py gives it to you in the form of functions in Python, Ruby, or other languages.

This is the Python function generated by mona.py to use VirtualAlloc in our exploit:

As can be seen, there are no missing pointers causing errors, and the opcodes do not contain bad characters.

This ROP chain to VirtualAlloc is going to make the stack executable, so we could execute our shellcode like when DEP was in OptIn mode (OptIn is only enabled for essential Windows programs and processes).

We add the chain just before the first instruction we need to execute on the stack.

Before the new exploit is finished, we must change the instruction we put in EIP for a ret instruction that loads in EIP the next pointer in the stack. Remember we use a jmp esp instruction, but now we can’t execute code in the stack, so when the jump lands in the stack, the data there are not opcodes, so it is not going to work. We can look in rop.txt for gadgets to use:

The gadget above extracts the first value in the stack to ECX and then makes a RET that loads the following value onto the stack on EIP. That means that we need to put four bytes between the EIP and the rop chain to avoid the first gadget of the chain being removed.

Now, let’s try the new version of the exploit. Once executed we can see the following in a command prompt:

And now let’s try to connect from Kali Linux:

As we can see, we have a Meterpreter shell on the remote Windows box.

Pwned!!!! again.

From exploit to Metasploit

Once we have our Python exploit working on systems with DEP and with no DEP, it’s time to port it to a Metasploit module. With the Metasploit module the process of exploiting this vulnerability will be fully automated.

Metasploit has its own modules by default on /usr/share/metasploit-framework/modules/. Here there is a folder structure for each class of module (e.g. exploits/windows/httpd) and inside these folders are the exploit files (such as shttpd_post.rb).

There are two ways of adding modules to Metasploit. You can put your own exploit files in this folder structure; but this is not recommended because when Metasploit updates you may lose your exploits. The other way is to create the same folder structure inside the .msf4 folder in the user’s home directory.

In this case, to add a module to Metasploit we are going to create the file slmail_pass.rb in the folder $HOME/.msf4/modules/exploits/windows/pop3/.

Every module needs at least two functions: “initialize” and “exploit”. There is a third and optional function “check”, which is used to fingerprint the victim box and check whether or not it is vulnerable to the exploit. Apart from this you can define more auxiliary functions to help achieve your goal, just like any Python or Ruby script.

Like Python, the indentation in Ruby is very important. Metasploit modules used to use two blank spaces instead of tabulations to indent (it is advisable to set the text editor of your choice to use two spaces when you press tab).

Here’s an example .vimrc file to set up a Vim editor:

filetype indent plugin on
syntax on
set shiftwidth=2
set softtabstop=2
set expandtab

If you use this .vimrc file, and you try to paste the exploit skeleton into a file using Vim, each new line you paste will be indented, and the exploit will lose the format. To solve this, you need to execute the “:set paste” command before you paste the content to the file. Once pasted, if the indent is more than two spaces you can type “gg=G” to re-indent the file using the configured values.

The line “include Msf::Exploit::Remote::TCP” is a Mixin which lets you include classes inside classes. Mixins add new functions and let you overload existing functions, changing their behavior.

Metasploit has many ready-to-use Mixins, which you can find in the folder lib/msf/core/ inside the Metasploit parent folder.

You can find lots of information about Mixins on the Internet, for example at

http://www.offensive-security.com/metasploit-unleashed/Exploit_Mixins, or simply by looking into the source code:

It is important to be very accurate with the “Space” and “BadChars” options for the payload, and specify in the target the Offset to control EIP and the address of the function we are going to use to get our shellcode.

All this information can be found in the file findmsp.txt. Be careful with the Space; you can see in the file we have 430 bytes for the payload, but the rop chain, the opcodes to move ESP away from the shellcode, and the padding we used to set up the stack properly use 98 bytes of space, so there are only 332 bytes left for the payload.

Next, we copy the function create_rop_chain() from the file rop_chains.txt that mona.py generated:

Time to try the module. Start msfconsole, select the exploit, configure it, and launch it.

We have a Meterpreter session, so the exploit is working fine (at least with the default options).

Let’s see the options of the exploit.

The payload has an EXITFUNC option by default set to “process” ; this means when the session is closed the process is terminated, so the vulnerability could not be exploited again until the process restarts. The other option is to set EXITFUNC to “thread” (this one works only if the service attacked uses threads, and in this case a POP3 server does, like an HTTP server or an SMTP server); this means that when the session is closed the thread is terminated, but the main process is still working and the vulnerability could be exploited again. More importantly, the victim doesn’t notice the attack because the service is working normally.

Let’s try to change the EXITFUNC to “thread” and exploit the box again:

The exploit fails because none of the encoders could encode the payload in the space available. Remember we only have 332 bytes for the payload, and this is not enough space.

We can get four extra bytes if we change the EIP gadget for 0x77c34281 (#0x77c34281 : # INC EAX # RETN ** [msvcrt.dll] **) and leave the padding we use to put in ECX, but this is not enough.

Let’s try to find more space available. First we check out the findmsp.txt file to look for a better place for the shellcode:

Here we have a good candidate highlighted in red. On the offset 4092 we have 996 bytes, but remember EIP was at offset 4654 so if we don’t want to corrupt our exploit, only 562 bytes can be used for the shellcode; this is still much better than the previous 332 bytes.

The new approach would be to use the 430 bytes after the EIP for the rop chain and then make a jump backwards to offset 4092, where we have 562 bytes more.

We will see this later; first let’s try to port the exploit to Windows 7.

Windows7 exploit (Python version)

For the demo, we used 64-bit Windows7 Professional with SLMAIL 5.5 installed.

We launched the poc2.py exploit, the one with the Metasploit cyclic pattern to make the application crash.

We then used mona.py to find the pattern in memory. Here is some of the output:

As can be seen highlighted in red, we can extract certain information from this file.

First we need to look for a module that doesn’t have ASLR or Rebase.

ASLR is a technique that randomizes the base address where the module loads in memory on every box reboot. Rebase is a technique to avoid multiple modules to be loaded at the same address in the process’ memory space. These two techniques make memory addresses unreliable to use in exploits.

In this case, we have three modules in memory with no ASLR or Rebase we can use to find the instructions or gadgets needed for our exploit.

We can see in the file output that the offset to control EIP is the same as the one in the Windows XP exploit.

So we need a jmp esp instruction inside one of the modules mentioned before to make the former exploit work.

We can use mona.py to find this instruction:

!mona jmp -r esp -m mfc42loc.dll,slmfc.dll,Openc32.dll

As can be seen, mona.py does not find any pointer to jmp esp in any of the analyzed modules.

There could be some instructions in the DLLs that mona.py could not find, so let’s try another approach using objdump just to make sure.

The SLMFC.DLL was copied to a Linux box and then analysed:

root@kali:/#objdump -D slmfc.DLL | grep jmp | grep esp

objdump finds multiple jmp esp instructions. Just to make sure, in Immunity Debugger we tried to go to the address 0x5f4a358f and watch which instructions are there.

Just right-click in the instructions windows, and choose “Go To -> Expression” in the pop-up menu. Then put the memory address in the expression form and click “OK”.

This was the result

The instruction “jmp esp” was in the SLMFC module, which was compiled with no ASLR and no Rebase.

Once the exploit is modified with this jump instruction, the exploit should look like this:

We then launch the exploit against the two Windows boxes to check it works on XP and on Win7.

First we configured the handler to not exit after a session is acquired, and to run it as a job:

Then the exploit was slightly modified to take the target IP from the command line. Here is what was changed:

- HOST = ‘127.0.0.1’
+ HOST = sys.argv[1]

Here are some screenshots showing what happened.

First the exploit launched against both boxes:

And here are the received Meterpreter sessions:

We have a reliable exploit for Windows XP and Windows 7 with DEP configured with the Optin (default) option.

This is because we are using an instruction from a module that installs with the SLMAIL server (SLMFC.DLL) to make the jump to the ESP register. This module should be the same in SLMAIL 5.5 across all Windows platforms.

Bypass DEP on Windows 7

Like in Windows XP, DEP on Windows 7 is OptIn by default. To change this setting and activate DEP for all processes, we can use a privileged command prompt to type:

bcdedit.exe /set nx AlwaysOn

After this, you need to restart the box.

To bypass DEP, we use ROP as on Windows XP.

The first step is to use mona.py to find gadgets and rop chains using modules with no ASLR and no Rebase.

!mona rop -m mfc42loc.dll,slmfc.dll,Openc32.dll -cpb '\x00\x0a\x0d'

Looking at the file rop_chains.txt we see chains to VirtualProtect and VirtualAlloc. The VirtualProtect chain is 600 bytes in length, too big for the space we have on the exploit (430 bytes). The VirtualAlloc one is smaller (96 bytes), but it is not complete because mona.py did not find a pointer to VirtualAlloc and did not find a gadget to put 0x1000 into EDX on any of the modules used to create the chains.

The command generates the files ropfunc.txt and ropfunc_offsets.txt. In ropfunc.txt there should be a list of pointers to interesting functions that can help bypass DEP. In ropfunc_offsets.txt there should be pointers to functions in modules which had pointers to VirtualAlloc, VirtualProtect, or other API functions to change or disable DEP.

Here is an example of ropfunc_offset.txt. There are plenty of valid pointers, so we take one with a small negative offset:

From that line we know that in 0x5f49a1cc there is a pointer to a pointer that points to the function multibytetowidehchar in the kernel32.dll module, and that pointer is at an offset of -216 bytes from a pointer to the VirtualAlloc function in the same module.

To obtain a pointer to VirtualAlloc on ecx we can do something like this:

move ecx,0x5f49a1cc # put the pointer to pointer to multibytetowidechar on ecx
move ecx,[ecx] # get the address on memory of the pointer to multibytetowidechar
sub ecx,0x00000d8 # add/sub the offset to get the address of the pointer to VirtualAlloc

So our goal now is to set up the stack as we saw in the previous table, with ESP pointing to the pointer to VirtualAlloc, and put a RET instruction into EIP.

First let’s set up the stack using the gadgets in rop.txt and rop_suggestions.txt.

We save ESP (stack pointer) in ECX and use it to store values on the stack:

The first gadget is trying to store a value in the address EAX points to (ADD DWORD PTR DS:[EAX],EAX), so we need to make sure there is a valid pointer in EAX. We can do this by adding this gadget at the top of the chain:

At the address pointed to by ECX we have a pointer to VirtualAlloc; now we need to put the return address in place. This address is where VirtualAlloc will return, and will usually be behind the rop chain. As we don’t know yet how many bytes in length the rop chain is, this value will be fixed later. At the moment, let’s just give 320 bytes (0x140) for the chain.

Next, the address where the allocation of memory starts. In exploits with enough space behind the rop chain the same value as returnTo can be used, but in this case we need to find another place to fit the shellcode.

From finsmsp.txt, we know that we can put the shellcode before the value that overwrites the saved EIP:

So at offset 4092 we have 562 bytes to use before overwriting the saved EIP (offset 4654). What we are going to try is to put the shellcode before EIP, then the rop chain after, and just behind the rop chain a jump backwards to the shellcode. So for lpAddress we need to calculate the bytes to remove from the stack to set it at the address where the jump will land. At first, let’s remove 400bytes (0x190) and later we will adjust the value.

The next value is dwSize, the size of the memory where we want to disable DEP. Here we know that the allocated space will start 400 bytes away (0x190), so we need a value which when added to lpAddress reaches the memory where the jump backwards instruction would be. For this value we are going to use 0x1FF:

The RETN instruction in the last gadget of the chain will launch the VirtualAlloc function, which will land after its execution somewhere on the buffer behind the chain (if we add enough space when calculating the return address)

Let’s put all this together to see if it’s working. Here is the first version of the current exploit:

In this version we use a chain of NOP instructions behind the rop chain because we don’t know the exact address to which VirtualAlloc is going to return. After the NOPs, we put just INT 3 instructions as shellcode, to create a breakpoint where the debugger will stop.

If the rop chain works as expected, then the NOP instructions will execute as well as the breakpoint. If not, the NOP instruction would generate an access violation error.

Attach the SLMAIL process to Immunity Debugger (started as administrator) and put a breakpoint on the last gadget of the rop chain:

B 0x5f452c0f

Then run the exploit, and if all goes well, the breakpoint should be reached:

Once the breakpoint is reached, we go step-by-step, pressing F7 in Immunity Debugger until the call to VirtualAlloc (16 steps):

Here is the stack at this point of execution:

Now we pass the VirtualAlloc function, pressing f8 to avoid going through the function step by step. Then we press F7 two more times and we should reach the NOPs we put before the shellcode:

As we can see, we reach the first NOP instruction (that was lucky…). Now to know if DEP is disabled just press F7 again. If all works well, the NOP instruction executes, and if not we will receive an access violation error.

Now that we know we can execute code on the stack, let’s try to find the place where the shellcode is, to calculate the distance of the backwards jump we need to make.

To achieve this, on Immunity we just double-click the memory address of the NOP to which VirtualAlloc returned. The view changes, and instead of memory addresses we start seeing offsets from the address we selected with the double click.

Now we just need to go backwards in the CPU window to find the “B”s (0x42) we put in the shellcode space, and look at the offset Immunity gives for the first “B”.

We need to jump backwards 0x37D bytes (893 bytes).

To make that jump, we return to the metasm_shell.rb script in the Metasploit framework:

We are going to add that jump just behind the rop chain (where VirtualAlloc returns) and put some NOPs and a breakpoint in the shellcode, to make sure we can execute code in that piece of stack. On the first run of the exploit, we need to look at the value of the lpAddress parameter, and then look at the address the jump goes to. Then we need to calculate the offset and fix the rop chain to make sure lpAddress is the same address where the jump lands, or at least an address before the jump address.

Once again, execute the exploit with a breakpoint on the last gadget of the rop chain and step forward to the VirtualAlloc call (16 steps with F7):

Looking at the stack, we can see the lpAddress in this execution (yours may differ because of the ASLR) is 0x01C79FA4.

Pass the VirtualAlloc with F8 and two more steps with F7 to gain the jump instruction:

Here we see the jump will land at 0x01C79EF3, an address that is before the address we use in lpAddress. This means if we try to exec a NOP here, in some cases there should be an access violation error. To make sure the exploit works we need to get the offset between 0x01C79FA4 and 0x01C79EF3 (0x01C79FA4 - 0x01C79EF3 = 0xB1) and fix the rop chain. We were adding -0x190, so now we need to change it to 0x241 (0x190 + 0xB1 = 0x241). The twos complement of 0x241 is 0xFFFFFDBF.

Now we just need to replace the shellcode witha reverse_tcp one from the Metasploit Framework, removing all the NOPs, because now we are landing on the first one and ensuring we have 562 bytes for a shellcode.

As we saw in the exploits before, remember to add the code to move away from ESP before executing the shellcode. This code length is six bytes, so we need 556 bytes for the final shellcode.

Save it as /root/.msf4/modules/exploits/windows/pop3/slmail_pass_win7.rb and launch msfconsole. Configure the module and run the exploit command:

As we can see, the exploit is sending the stage but the Meterpreter session never comes. The problem is the way Metasploit makes the payload.

In this case we said that we have 556 bytes for the payload (Space variable in the payload block) and what Metasploit does is to generate the payload (around 347 bytes in this case) and fill the remaining bytes with NOPs until the final payload size is 556 bytes.

In the Python exploit we used “B”s as padding and the exploit was working fine.

Adding the parameter DisableNops => True to the payload block of the exploit changes this behavior from Metasploit and the payload just fits its own size.

We can adapt the exploit to other win32 systems by just looking for the offset between “multibytetowidechar” and “virtualalloc” on kernel32.dll module.

Conclusions

Writing exploits for buffer overflow vulnerabilities on win32 is not an easy journey, but if you are reading this now, I guess you find it easier now than at the beginning.

The idea of this post was to help people starting in the exploit development world to get the concepts and the ideas quickly, and to make the learning curve less steep. Of course any software, library, or exploit will have its own complexity. Some of the tips in this post may help, but in other scenarios the exploiter will need to figure out how to solve some problems we have not covered here.