Building a WiFi Enabled USB Rubber Ducky with a Raspberry Pi 0 w

17 Apr, 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 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 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/

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/
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):

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:

Quacking like a duck

If you're looking to port ducky scripts directly onto the Pi, take a look at from

17 Apr, 2017

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

28 Mar, 2017

The other day I noticed something cool in Chrome. I can disable JavaScript and cookies + local storage on HTTP!...[read more]

1 Jan, 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]

27 Aug, 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]
22 May, 2016
Biometric sensors are good at identity. They can tell you exactly who a fingerprint belongs to; who's face is in-front of the camera; even who's DNA was left at a crime-scene. But biometric sensors are not good authenticators.

Replay Attacks

Let's say Bob, thinks it's a good idea to add a voice activated lock to his house...[read more]
4 May, 2016


A little over a month ago I contacted my bank (Santander), asking them why they served me their homepage insecurely...[read more]
2 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]