16 May 2017

Leveraging the new RPi0w to build a WiFi enabled keystroke injection tool (a.k.a. USB Rubber Ducky with WiFi).

We've already seen things like PoisonTap take advantage of the data port on the RPi0 to attack a computer via network over USB. Recently the Raspberry Pi Zero W was released (and they're a little easier to obtain than their predecessor). Incase it wasn't obvious, the W stands for WiFi (or Wireless – it includes Bluetooth too).


This is all possible, because the Raspberry Pi Zero and Zero W both support an OTG, or USB slave mode – which allows the Raspberry Pi to actually be a USB device.

We're going to cover building a WiFi enabled USB Rubber Ducky. If you're not sure what a USB Rubber Ducky is, then take a look and come back when you're done.

Obtaining the Pi

I bought this starter kit. I chose this because it contained things I planned on getting anyway (case, SD card, HDMI, and regular sized USB adapter). But you can grab just the Pi itself for much less, if you don't need the extra equipment. But the most important reason I chose this one: cool RGB LEDs! 😉

RPi0w with lights on

In all seriousness, these are invaluable as a method of output (if you don't have a spare screen nearby).

Grab a recent version of Raspbian Jessie

Download here, lite version is all we need. This is because current versions of Raspbian now include the relevant kernel drivers to enable OTG mode out of the box.

Set up an initial communication channel

If you don't have a screen or keyboard this may be useful to get started. (Initially use the OTG USB port as an ethernet device to facilitate communication with the Pi).

SSH is not enabled by default. So you'll have to either create a file named ssh in the root of your SD card, or remember to enable it when you've got a screen and keyboard connected.

Set up hostapd to broadcast a WiFi network

We'll want to maintain remote access. You could instead set the Pi up to just connect to a WiFi network, but broadcasting a network ensures that you'll be able to send commands even when you're not around your home network.

There are already quite a few guides, like this one, on doing this, so I won't bother here. Note that you can skip any steps regarding IP forwarding, since we won't require that the Pi actually provides a working internet connection.

Enable OTG mode on the data port

echo "dtoverlay=dwc2" | sudo tee -a /boot/config.txt
echo "dwc2" | sudo tee -a /etc/modules

See https://gist.github.com/gbaman/50b6cca61dd1c3f88f41 for more info on the other OTG modes.

Setup the RPi0 as a HID device

I'd seen some reports of success doing this (from a while ago) using the original RPi0, using just echo "g_hid" | sudo tee -a /etc/modules.

If you reboot, and see a /dev/hidg0 device then you had more luck than me!

If you don't, vi/nano into /etc/modules and remove the line g_hid.

Next, I created a file called hid.sh in my home directory:


This will set up the Pi as a HID device.

I used the following wrapper script for calling on boot (so that if the data port is in use e.g. to connect a mouse/keyboard) then the Pi will not attempt this mode (I found this caused the Pi to be unable to use the device I had plugged in).

Assuming henceforth that you're rolling with the default pi user account:



if [ "$(lsusb)" == "Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub" ]; then
  sudo /home/pi/hid.sh

I haven't tested this on a different board, so you should check your own lsusb output to check that the ID portion of the above is correct.

Make it happen on boot

I added these lines to my /etc/rc.local file

sudo /home/pi/enableHid.sh
sudo chmod -R 777 /dev/hidg0

Sending keystrokes

If all went well, upon reboot you should see /dev/hidg0.

You can now use hid-gadget-test.c to send the device keystrokes.

To compile the program on the Pi, use the following:

gcc -o hid_gadget_test hid-gadget-test.c

You can then use a language of your choice to create a wrapper around this script (which sends keystrokes individually):

Keep in mind that you'll need to browse that c file to see which buttons are supported (don't worry, it's fairly readable). To give the gist:

To send the key press 'a', followed by return:

echo 'a' | /home/pi/hid_gadget_test /dev/hidg0 keyboard
echo 'return' | /home/pi/hid_gadget_test /dev/hidg0 keyboard

Lower-case letters are all their own values. An uppercase 'A' could be achieved with:

echo 'shift a' | /home/pi/hid_gadget_test /dev/hidg0 keyboard

Note that here we used a space to separate simultaneous keys.

While symbols tend to hold their wordy names: E.g. for (cmd/winkey) + space:

echo 'left-meta space' | /home/pi/hid_gadget_test /dev/hidg0 keyboard

Here's a demo wrapper program written in PHP (the translation function is far from complete): https://github.com/aidantwoods/RPi0w-keyboard/blob/master/src/home/pi/quack.php

If you're more for typing manually, then just use

/home/pi/hid_gadget_test /dev/hidg0 keyboard

This will enter an interactive mode which accepts keys in the same format as above, but you can press enter between each keystroke to send.

Does it Quack?

It quacks!

Here's a GitHub repo with all the necessary files mentioned above: https://github.com/aidantwoods/RPi0w-keyboard

Quacking like a duck

If you're looking to port ducky scripts directly onto the Pi, take a look at droidducky.sh from https://github.com/anbud/DroidDucky

31 May 2022


compactRepresentation is a public key output format, made available when using outputting public elliptic curve keys from within Apple's CryptoKit. compactRepresentation is comparable to a "compressed point", where the former is one byte shorter. These two representations are very similar, but not the same...[read more]

16 May 2017

Leveraging the new RPi0w to build a WiFi enabled keystroke injection tool (a.k.a. USB Rubber Ducky with WiFi)...[read more]

1 January 2017

Recently I've been working on a drop in class to manage certain "Secure Headers" in PHP.

By "Secure Headers", I'm of course talking about those mentioned in the OWASP Secure Headers Project.

The project, SecureHeaders is available on GitHub.


If you're familiar with PHP, you'll know that...[read more]

26 August 2016

Disclosure and Google's Response

This one feels very strange writing, because the vulnerability detailed below is currently exploitable. Google has been notified of this vulnerability, yet they have chosen to do nothing.
GoogleThanks for your bug report and research to keep our users secure! We've investigated your submission and made the decision not to track it as a security bug.
In hope that public disclosure will encourage Google to do otherwise, here goes.
...[read more]
1 May 2016
In this post I'll address one specific task: obtaining a manual certificate from Let's Encrypt.

Who is this for?

If you don't have direct command line access, or the necessary permissions to install Let's Encrypt on your webserver; then you won't be able to obtain a certificate using the automated process.
If you can install Let's Encrypt on your webserver, you should. It simplifies the process down to a single command. You'll also enjoy the benefits of being able to setup an auto renew process directly on the machine serving the certificate.
...[read more]