
Pi Zero 2W를 BadUSB로 구성하세요
Raspberry Pi Zero 2 W를 기반으로 제작된 프로그래밍 가능한 BadUSB / HID 공격 플랫폼입니다. Pi는 USB 복합 장치(키보드 + 선택적인 읽기 전용 대용량 저장 볼륨)로 인식되며, 연결된 호스트를 대상으로 Ducky-Script 스타일의 페이로드를 실행합니다. 공인 레드팀 모의 침투, 침투 테스트, CTF를 위해 설계되었습니다.
⚠️ 법적 고지. 소유하고 있거나 명시적인 서면 허가를 받은 시스템에서만 사용하십시오. 허가되지 않은 접근은 대부분의 국가에서 불법이며, 몰랐다고 해도 변명이 되지 않습니다.
configured 상태를 활용하므로
부팅 시 페이로드가 오작동으로 실행되지 않습니다.LAYOUT 지시어 사용.IF / ELSE, WHILE, HOLD / RELEASE, INJECT_MOD,
RANDOM_* 생성기, STRING_BLOCK / STRINGLN_BLOCK, DEFINE 지원.ExecStop이 가젯을 깔끔하게 해체합니다.
configfs 상태가 남지 않으며, 재부팅 없이도 재시작이 가능합니다./dev/hidg0 권한 — 전 세계 쓰기 가능한 디바이스 노드가 없습니다.+----------------+ USB cable +-------------+
| Raspberry Pi | ===================>>> | Host PC |
| Zero 2 W | (Pi emulates HID + | (target) |
| (this device) | optional drive) | |
+----------------+ +-------------+
|
| /home/pi/pi-badusb/
|
+-- badusb.service ----> monitor_and_run.py
|
| on `state == configured`:
v
run_payload.py
|
v
/dev/hidg0 (USB HID gadget)
badusb.service systemd 유닛이 gadget_setup.sh를 실행합니다.
이 스크립트는 configfs/libcomposite를 사용해 HID 키보드 기능과
(선택적으로) /var/badusb/storage.img의 플랫 이미지 파일을 백업으로 하는
대용량 저장소 LUN을 가진 USB 가젯을 구성합니다.monitor_and_run.py를 실행합니다. 이 스크립트는
/sys/class/udc/<udc>/state를 폴링하며 configured 상태를 기다립니다 —
이는 USB 규격상 호스트가 가젯을 성공적으로 열거(enumeration)했음을 뜻합니다.
(/dev/hidg0의 존재 여부를 신호로 사용하지 않습니다: 해당 노드는
부팅 시 가젯이 UDC에 바인딩되는 순간, 케이블 연결 여부와 관계없이 생성되기 때문입니다.)run_payload.py를 실행합니다.
이 스크립트는 payload.txt를 파싱하고 HID 리포트를 /dev/hidg0에 기록합니다.configured
전환을 기다립니다.| 구성 요소 | 설명 |
|---|---|
| Raspberry Pi Zero 2 W | 2026-05 하드웨어 개정판에서 테스트 완료. BCM2835 dwc_otg 드라이버를 사용하는 구형 Pi Zero W도 원리적으로는 동작하지만, 이 README는 dwc2를 사용하는 2 W 기준입니다. |
| micro-USB to USB-A 케이블 | 또는 Pi를 호스트 포트에 직접 꽂을 수 있는 "USB 스틱" 폼팩터 어댑터. |
| 선택 사항: 별도 충전기 | 타깃에 꽂기 전에 리스너가 부팅될 수 있도록 호스트가 아닌 전원으로 Pi에 전원을 공급하려는 경우 (그렇지 않으면 호스트 포트가 전원을 공급합니다). |
Pi Zero 2 W에는 micro-USB 포트가 두 개 있습니다:
PWR IN — 전원 전용. USB 데이터 라인이 dwc2 OTG 블록에 노출되지 않습니다.USB — OTG 데이터 포트. 타깃에 연결하는 포트입니다.| 요구 사항 | 이유 |
|---|---|
| Raspberry Pi OS (Debian Bookworm 또는 Trixie, 64비트 Lite 권장) | 설치 스크립트는 Bookworm 이상에서는 /boot/firmware/...에 쓰고, 구형 이미지에서는 /boot/...로 대체됩니다. |
| Python 3 | Pi OS에 기본 포함되어 있습니다. |
mkfs.vfat | 첫 실행 시 대용량 저장소 백업 이미지를 포맷하는 데 사용. 대용량 저장소를 비활성화하면 건너뜁니다. |
| 설치를 위한 루트 권한 | systemd, udev, /boot/firmware/config.txt를 수정합니다. |
저장소를 Pi에 클론하거나 복사한 후 설치 프로그램을 실행합니다:
git clone http://your-gitea/admin/Pi-Zero-2W-Bad-USB.git /home/pi/pi-badusb
cd /home/pi/pi-badusb
sudo ./install.sh
sudo reboot
재부팅 후 서비스를 활성화하고 시작합니다:
sudo systemctl enable --now badusb.service
journalctl -u badusb -f
install.sh는 멱등(idempotent) 입니다 — 프로젝트 파일을 변경할 때마다
다시 실행하면 됩니다. 이 스크립트는:
/boot/firmware(Bookworm+)와 /boot(구형)를 자동 감지합니다.config.txt의 [all] 블록 아래에 dtoverlay=dwc2,dr_mode=otg가
활성화되도록 보장합니다. Raspberry Pi Imager 기본값은 이 줄을 Pi Zero 2 W에
적용되지 않는 [cm5] 필터 안에 넣기 때문에, 설치 프로그램은 재실행 시
중복되지 않도록 표식(sentinel)이 있는 오버라이드를 추가합니다.cmdline.txt에 modules-load=dwc2가 포함되도록 보장합니다.cmdline.txt에 g_ether가 남아 있으면 경고합니다 (g_ether가
libcomposite에서 UDC를 가로채 가젯 모드를 망가뜨립니다)./etc/systemd/system/badusb.service에 설치합니다./etc/udev/rules.d/99-badusb-hidg.rules에 udev 규칙을 설치하여
/dev/hidg0가 plugdev 그룹에 의해 그룹 쓰기 가능하도록 합니다.pi 사용자를 plugdev 그룹에 추가합니다./var/badusb/ 디렉터리를 생성합니다.# 시작 / 중지 / 재시작
sudo systemctl start badusb
sudo systemctl stop badusb
sudo systemctl restart badusb # 연결된 상태에서도 안전합니다
# 실시간 로그 보기
journalctl -u badusb -f
# 부팅 시 자동 시작 비활성화
sudo systemctl disable badusb
# 타이밍 조정 (override drop-in 생성)
sudo systemctl edit badusb
# (Environment="BADUSB_REARM_COOLDOWN_S=8" 등이 포함된 [Service] 블록을 붙여넣으세요)
sudo systemctl restart badusb
이 서비스는 sys-kernel-config.mount와 UDC의 존재에 의존하므로,
가젯이 실제로 준비되기 전에는 페이로드를 실행할 수 없습니다.
페이로드를 수정해도 재시작할 필요가 없습니다 — payload.txt는
꽂을 때마다 새로 읽습니다.
payload.txt는 설치 디렉터리에 있습니다. 전체 명령어 레퍼런스는
payload_commands.md에 있습니다.
REM Open Run dialog and type a greeting via Notepad
LAYOUT US
GUI r
DELAY 1500
STRING notepad
ENTER
DELAY 2500
STRINGLN Hello from the Pi Zero 2 W
VAR $USER="alice"
VAR $COUNT=0
WHILE $COUNT < 3
STRINGLN Hello $USER (iteration $COUNT)
VAR $COUNT = $COUNT + 1
END_WHILE
IF $USER == "alice"
STRINGLN matched
ELSE
STRINGLN missed
END_IF
VAR의 수식은 ast 워커 기반 안전 평가기(safe evaluator)를 거칩니다 —
이름, 호출, 속성 접근은 허용되지 않으며 숫자 리터럴과
+ - * / // % **만 허용됩니다.
HOLD SHIFT
STRINGLN this line is in capitals
RELEASE SHIFT
REM Hold Ctrl+Shift (0x01 + 0x02) and tap A
INJECT_MOD 0x03
STRING a
REM Release all modifiers
INJECT_MOD 0x00
RANDOM_LETTER 12 # 12 random mixed-case letters
RANDOM_NUMBER 6 # 6 random digits
RANDOM_SPECIAL 4 # 4 random ASCII symbols
LAYOUT UK # switch to UK ISO mappings for subsequent STRING/STRINGLN
STRING @ " # ~ £ \ | # types correctly on a UK-locale host
keymaps/ 디렉터리(us.py, uk.py 옆)에 다른 파일을 추가하면
LAYOUT <name> 지시어가 importlib로 해당 파일을 불러옵니다.
gadget_setup.sh 상단)| 변수 | 기본값 | 의미 |
|---|---|---|
ENABLE_MASS_STORAGE | 1 | 0이면 HID 전용 가젯. |
BACKING_FILE | /var/badusb/storage.img | 호스트에 노출되는 플랫 이미지. |
BACKING_SIZE_MB | 64 | 첫 실행 시 생성됨. |
BACKING_LABEL | BADUSB | FAT 볼륨 레이블. |
MASS_STORAGE_RO | 1 | 기본적으로 읽기 전용. |
이 값들은 gadget_setup.sh를 수동으로 실행할 때 환경 변수로 설정해
호출별로 덮어쓰거나, 유닛의 Environment= 지시어로 전역 설정할 수 있습니다.
monitor_and_run.py)| 환경 변수 | 기본값 | 의미 |
|---|---|---|
BADUSB_POST_PAYLOAD_FLUSH_S | 0.5 | 페이로드 종료 후 언바인딩 전에 대기하여 HID 쓰기가 완전히 전송되도록 함. |
BADUSB_REARM_COOLDOWN_S | 5 | 언바인딩과 재바인딩 사이에 가젯이 호스트에 보이지 않는 시간. |
BADUSB_MIN_INTER_FIRE_S | 10 | 두 페이로드 실행 사이의 최소 시간(초). 이보다 짧으면 실행이 억제되고 가젯이 다시 언바인딩됨. |
BADUSB_MAX_FIRES_PER_MINUTE | 6 | 하드 상한. 초과 시 BADUSB_RATELIMIT_PAUSE_S 동안 일시 중지. |
BADUSB_RATELIMIT_PAUSE_S | 60 | 속도 제한 발동 후 일시 중지 시간. |
다음과 같이 덮어씁니다: