| name | hardcoded-creds |
| description | Systematic hunt for hardcoded credentials, API keys, certificates, and default passwords in extracted IoT firmware. Covers /etc/shadow and passwd parsing, busybox httpd configs, telnet/dropbear stanzas, MQTT/cloud API key extraction, and cross-referencing against known default-credential databases. |
| allowed-tools | Bash Read Write |
| metadata | {"subdomain":"iot","when_to_use":"hardcoded credentials, default password, busybox, telnet creds, SSH key, API key embedded, /etc/shadow, httpd config, dropbear key, hardcoded secret, firmware credentials, MQTT creds, default login","tags":"iot, credentials, hardcoded, shadow, passwd, busybox, httpd, telnet, dropbear, api-key, default-creds, embedded, firmware","mitre_attack":"T1552.001, T1078.001, T1110.001, T1552.004"} |
Hardcoded Credentials
Extracted rootfs often contains plaintext or weakly hashed credentials,
embedded TLS private keys, cloud API tokens, and hardcoded admin accounts.
This playbook covers the full triage path from raw rootfs to validated cred.
Prerequisites
- Extracted rootfs from
binwalk-extract skill (path: /tmp/squashfs_root or similar).
- Tools:
john, hashcat, openssl, trufflehog, strings, standard GNU utilities.
ROOT=/tmp/squashfs_root
Phase 1 — Account Databases
/etc/passwd + /etc/shadow
grep -v "nologin\|false" "$ROOT/etc/passwd"
cat "$ROOT/etc/shadow" 2>/dev/null || echo "shadow not present"
awk -F: '{print $1, $2}' "$ROOT/etc/shadow" | grep -v '^\*\|^!\|^:$'
hashcat -m 1800 "$ROOT/etc/shadow" /usr/share/wordlists/rockyou.txt
hashcat -m 500 "$ROOT/etc/shadow" /usr/share/wordlists/rockyou.txt
hashcat -m 1500 "$ROOT/etc/shadow" /usr/share/wordlists/rockyou.txt
unshadow "$ROOT/etc/passwd" "$ROOT/etc/shadow" > /tmp/unshadowed.txt
john /tmp/unshadowed.txt --wordlist=/usr/share/wordlists/rockyou.txt
john /tmp/unshadowed.txt --show
BusyBox-specific user configs
find "$ROOT/etc" -name "httpd.conf" -o -name ".htpasswd" | xargs cat 2>/dev/null
grep -r "telnetd\|login\|password" "$ROOT/etc/inittab" "$ROOT/etc/init.d/" \
"$ROOT/etc/rc.d/" 2>/dev/null | grep -v "^Binary"
grep -E '^[^:]+:[^:!*]{3,}' "$ROOT/etc/shadow" 2>/dev/null
Phase 2 — SSH / Dropbear Keys
find "$ROOT" -name "dropbear_*_host_key" -o -name "ssh_host_*_key" 2>/dev/null
dropbearconvert dropbear openssh "$ROOT/etc/dropbear/dropbear_rsa_host_key" \
/tmp/host_rsa.pem
openssl rsa -in /tmp/host_rsa.pem -text -noout | head -20
find "$ROOT" -path "*/.ssh/authorized_keys" | xargs cat 2>/dev/null
grep -r "authorized_keys\|ssh-rsa\|ecdsa-sha2" "$ROOT" 2>/dev/null | head -10
Phase 3 — Web Interface Credentials
find "$ROOT" -name "*.lua" -o -name "*.cgi" -o -name "*.php" | \
xargs grep -l "password\|passwd\|credential\|secret\|admin" 2>/dev/null | head -20
grep -rn "admin\|password\|passwd\|secret\|token" \
"$ROOT/etc/lighttpd/" "$ROOT/etc/nginx/" "$ROOT/etc/httpd/" 2>/dev/null
grep -rn '"admin"\|"root"\|"1234"\|"password"' "$ROOT/usr/lib/lua/" \
"$ROOT/www/" "$ROOT/usr/share/www/" 2>/dev/null | head -30
Phase 4 — Strings-Based Secret Sweep
find "$ROOT" -type f -executable | while read f; do
strings "$f" 2>/dev/null
done > /tmp/all_strings.txt
grep -iE 'password|passwd|secret|api.?key|token|credential|auth' /tmp/all_strings.txt \
| grep -vE '^(#|//|<!|<html|<head)' | sort -u | head -100
grep -E 'AKIA[0-9A-Z]{16}|AIza[0-9A-Za-z_-]{35}|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' \
/tmp/all_strings.txt
grep -oP 'eyJ[A-Za-z0-9+/=]+\.[A-Za-z0-9+/=]+\.[A-Za-z0-9+/=_-]+' \
/tmp/all_strings.txt | head -10
trufflehog filesystem scan
trufflehog filesystem "$ROOT" --only-verified 2>/dev/null
trufflehog filesystem "$ROOT" --json 2>/dev/null | \
python3 -c "import sys,json; [print(json.dumps(r, indent=2)) for r in map(json.loads, sys.stdin)]"
Phase 5 — MQTT / Cloud / IoT-Platform Tokens
grep -rn "mqtt\|MQTT\|mosquitto" "$ROOT" --include="*.conf" --include="*.cfg" \
--include="*.json" --include="*.lua" 2>/dev/null | head -30
grep -rn "tuya\|homekit\|awsiot\|azure.*iot\|device_key\|productKey\|deviceSecret" \
"$ROOT" --include="*.json" --include="*.conf" 2>/dev/null | head -30
grep -rn "serial\|SerialNum\|MAC\|mac_addr" "$ROOT/etc/config/" 2>/dev/null | head -20
Phase 6 — Default Credential Matrix Cross-Reference
USERS=$(grep -v 'nologin\|false\|halt\|sync\|shutdown' "$ROOT/etc/passwd" | \
awk -F: '{print $1}' | tr '\n' ' ')
echo "Accounts found: $USERS"
DFLT=/usr/share/routersploit/resources/wordlists/default_passwords.txt
[ -f "$DFLT" ] && echo "Default wordlist available: $DFLT"
SECLIST=/usr/share/seclists/Passwords/Default-Credentials/default-passwords.csv
[ -f "$SECLIST" ] && grep -iE 'admin|root|user' "$SECLIST" | head -20
Known vendor default credential matrix
| Vendor | Username | Password | Protocol |
|---|
| TP-Link (pre-2022) | admin | admin | HTTP / Telnet |
| Netgear | admin | password | HTTP |
| D-Link | admin | (blank) | HTTP |
| Asus (stock) | admin | admin | HTTP |
| MikroTik | admin | (blank) | SSH / Winbox |
| Hikvision | admin | 12345 | RTSP / HTTP |
| Dahua | admin | admin | HTTP |
| Ubiquiti AirOS | ubnt | ubnt | SSH |
| Western Digital MyCloud | admin | (blank) | HTTP |
| Seagate NAS | admin | admin | HTTP |
Phase 7 — TLS Certificate Private Keys
grep -rl "BEGIN.*PRIVATE KEY\|BEGIN RSA PRIVATE KEY" "$ROOT" 2>/dev/null
find "$ROOT" -name "*.der" -o -name "*.key" -o -name "*.pem" | while read f; do
openssl rsa -in "$f" -text -noout 2>/dev/null | head -3 && echo "FILE: $f"
done
find "$ROOT" -name "*.crt" -o -name "*.pem" | while read f; do
openssl x509 -in "$f" -noout -subject -issuer 2>/dev/null && echo " FILE: $f"
done
openssl x509 -noout -modulus -in "$ROOT/etc/ssl/server.crt" | openssl md5
openssl rsa -noout -modulus -in "$ROOT/etc/ssl/server.key" | openssl md5
Evidence
EVDIR=/workspace/evidence/iot/<target>/credentials
mkdir -p "$EVDIR"
john /tmp/unshadowed.txt --show > "$EVDIR/cracked_passwords.txt"
cp /tmp/all_strings.txt "$EVDIR/strings_all.txt"
OPSEC Notes
- Cracked shadow credentials are valid on every unit of the same firmware version
(until the vendor patches). Document model + firmware version precisely.
- Private key extraction enables MitM against the vendor's cloud API for all devices
using that firmware. Escalate finding severity accordingly.
- MQTT tokens with
# wildcard subscriptions allow full telemetry interception across
the vendor's entire fleet — flag as Critical if RoE scope allows cloud testing.
References
- SecLists default credentials:
https://github.com/danielmiessler/SecLists/tree/master/Passwords/Default-Credentials
- RouterSploit modules:
https://github.com/threat9/routersploit
- trufflehog:
https://github.com/trufflesecurity/trufflehog
- Hashcat hash-modes:
https://hashcat.net/wiki/doku.php?id=hashcat