pico-bit is an open source MicroPython project for the Raspberry Pi Pico 2 W. It combines a USB HID DuckyScript runtime, a Wi-Fi-hosted operator portal, and an optional Rust agent delivery flow for authorized security research, lab automation, and defensive validation.
The Pico types payloads over USB, serves a browser UI at http://192.168.4.1, and can stage one uploaded executable on the Pico filesystem for USB-based delivery.
payload.ddpayload.exe or payload.binloot.json downloadRPI_PICO2_W) only| What | Value |
|---|---|
| Wi-Fi SSID | PicoBit |
| Wi-Fi password | PicoBit24Net |
| Portal URL | http://192.168.4.1 |
| Portal username | admin |
| Portal password | PicoBit24Admin |
BOOTSEL while connecting the Pico.pico-bit-RPI_PICO2_W-<version>.uf2 from the releases page.RPI-RP2 drive.PicoBit Wi-Fi network and open http://192.168.4.1.On first boot, Pico Bit creates payload.dd if it is missing.
3.11 to 3.14uv24 for frontend buildsmpremote if you want to copy local builds directly to a PicoInstall dependencies:
uv sync
npm ci --prefix web
This creates:
dist/boot.pydist/boot.mpydist/mpy/**/*.mpyuv run python scripts/build.py
If frontend assets are already up to date, you can skip the Vite step:
uv run python scripts/build.py --skip-frontend
mpremoteInstall mpremote once:
python3 -m pip install mpremote
Copy the bundled boot file:
mpremote connect auto fs cp dist/boot.py :boot.py
mpremote connect auto reset
If you also want to seed a local payload file manually:
mpremote connect auto fs cp payload.dd :payload.dd
Install firmware build prerequisites:
sudo apt-get update
sudo apt-get install -y build-essential cmake gcc-arm-none-eabi libnewlib-arm-none-eabi ninja-build
Then build the release UF2:
uv run python scripts/release.py build-uf2 \
--micropython-ref v1.28.0 \
--board RPI_PICO2_W \
--release-version v0.0.2
Useful release options:
--usb-profile default|generic-composite|generic-keyboard|hobbyist--ap-ssid ...--ap-password ...--portal-username ...--portal-password ...Artifacts land in dist/, including .uf2 files and release.json.
The Rust agents live under agent/. Available binaries are:
reconexfilpersistwipecargo check --manifest-path agent/Cargo.toml --bins
cargo build --manifest-path agent/Cargo.toml --release --bin exfil
cargo build --manifest-path agent/Cargo.toml --release --bin persist
cargo build --manifest-path agent/Cargo.toml --release --bin wipe
cargo build --manifest-path agent/Cargo.toml --release --bin recon --features with-sysinfo
rustup target add x86_64-unknown-linux-musl aarch64-unknown-linux-musl
python3 -m pip install ziglang
cargo install cargo-zigbuild
cargo zigbuild --manifest-path agent/Cargo.toml --release --target x86_64-unknown-linux-musl --bin exfil
cargo zigbuild --manifest-path agent/Cargo.toml --release --target x86_64-unknown-linux-musl --bin persist
cargo zigbuild --manifest-path agent/Cargo.toml --release --target x86_64-unknown-linux-musl --bin wipe
cargo zigbuild --manifest-path agent/Cargo.toml --release --target x86_64-unknown-linux-musl --bin recon --features with-sysinfo
Swap the target to aarch64-unknown-linux-musl for arm64.
Run the portal locally with mock Pico APIs:
npm --prefix web run dev
To test the Vite frontend against real hardware:
PICOBIT_PROXY=http://192.168.4.1 npm --prefix web run dev
npm --prefix web run build
npm --prefix web run check
npm --prefix web run lint
npm --prefix web run test
uv run python -c "from scripts.helpers.assets import sync_web_assets; sync_web_assets(check=True, skip_build=True)"
uv run ruff format --check .
uv run ruff check scripts src tests
uv run pyright
uv run pytest
uv run python scripts/build.py --skip-frontend
src/web_assets.py is generated from dist/web/ and should not be edited by hand/, /assets/index.css, and /assets/index.jspayload.dd is writable on the Pico filesystem and is not frozen into firmwarepayload.exe for Windows agents or payload.bin for Linux/macOS agents1 MBsrc/usb.py is the source of truth for the shared machine.USBDevice singleton, MSC capability detection, runtime active() state, and staged binary filenamessrc/keyboard.py owns the HID keyboard runtime and keyboard layout metadata; src/boot.py initializes USB first, then keyboardNo Name, so USB stagers search for payload.exe or payload.bin by filenameloot-usb.json to the Pico drive; the portal imports it into canonical loot.jsonGitHub releases publish:
RPI_PICO2_Wrelease.json with release metadata, file sizes, and SHA-256 checksumsManual release runs can build firmware and agent bundles independently, and partial reruns preserve checksum metadata for unchanged assets.
See CONTRIBUTING.md.
Use Pico Bit only on systems you own or are explicitly authorized to test. Unauthorized access to computer systems is illegal and out of scope for this project.
GPL-3.0-only. See LICENSE.