CtrlK
BlogDocsLog inGet started
Tessl Logo

hardcoded-creds

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.

63

Quality

75%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Critical

Do not install without reviewing

Fix and improve this skill with Tessl

tessl review fix ./packages/decepticon/decepticon/skills/standard/iot/hardcoded-creds/SKILL.md
SKILL.md
Quality
Evals
Security

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   # set once; referenced throughout

Phase 1 — Account Databases

/etc/passwd + /etc/shadow

# Check for non-standard shells (telnetd, /bin/sh) and disabled-but-present accounts
grep -v "nologin\|false" "$ROOT/etc/passwd"

# Extract hashed passwords
cat "$ROOT/etc/shadow" 2>/dev/null || echo "shadow not present"

# Identify hash types
# $1$ = MD5, $5$ = SHA-256, $6$ = SHA-512, $y$ = yescrypt, no-$ = DES
awk -F: '{print $1, $2}' "$ROOT/etc/shadow" | grep -v '^\*\|^!\|^:$'

# Crack with hashcat (shadow format)
hashcat -m 1800 "$ROOT/etc/shadow" /usr/share/wordlists/rockyou.txt   # $6$ SHA-512
hashcat -m 500  "$ROOT/etc/shadow" /usr/share/wordlists/rockyou.txt   # $1$ MD5
hashcat -m 1500 "$ROOT/etc/shadow" /usr/share/wordlists/rockyou.txt   # DES

# john fallback (handles multi-type auto)
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

# BusyBox httpd uses /etc/httpd.conf for auth
find "$ROOT/etc" -name "httpd.conf" -o -name ".htpasswd" | xargs cat 2>/dev/null

# BusyBox udhcpd / telnetd startup stanzas
grep -r "telnetd\|login\|password" "$ROOT/etc/inittab" "$ROOT/etc/init.d/" \
    "$ROOT/etc/rc.d/" 2>/dev/null | grep -v "^Binary"

# BusyBox shadow format check (some use MD5 without $1$ prefix)
grep -E '^[^:]+:[^:!*]{3,}' "$ROOT/etc/shadow" 2>/dev/null

Phase 2 — SSH / Dropbear Keys

# Host keys (baked into firmware = same key across all units of same model)
find "$ROOT" -name "dropbear_*_host_key" -o -name "ssh_host_*_key" 2>/dev/null

# Convert Dropbear key to OpenSSH PEM for use
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

# Authorized keys embedded for backdoor accounts
find "$ROOT" -path "*/.ssh/authorized_keys" | xargs cat 2>/dev/null

# Check if root has a passwordless authorized_key → instant SSH root on any unit
grep -r "authorized_keys\|ssh-rsa\|ecdsa-sha2" "$ROOT" 2>/dev/null | head -10

Phase 3 — Web Interface Credentials

# CGI / Lua / PHP / lighttpd configs
find "$ROOT" -name "*.lua" -o -name "*.cgi" -o -name "*.php" | \
    xargs grep -l "password\|passwd\|credential\|secret\|admin" 2>/dev/null | head -20

# Plaintext credentials in web config files
grep -rn "admin\|password\|passwd\|secret\|token" \
    "$ROOT/etc/lighttpd/" "$ROOT/etc/nginx/" "$ROOT/etc/httpd/" 2>/dev/null

# Hardcoded credentials in Lua/CGI scripts
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

# Broad strings dump: capture all printable sequences ≥ 8 chars
find "$ROOT" -type f -executable | while read f; do
    strings "$f" 2>/dev/null
done > /tmp/all_strings.txt

# Filter credential-like patterns
grep -iE 'password|passwd|secret|api.?key|token|credential|auth' /tmp/all_strings.txt \
    | grep -vE '^(#|//|<!|<html|<head)' | sort -u | head -100

# AWS / GCP / Azure key patterns
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

# JWT tokens
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 works on directories — point at rootfs
trufflehog filesystem "$ROOT" --only-verified 2>/dev/null
# Without --only-verified for broader sweep:
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

# MQTT broker credentials
grep -rn "mqtt\|MQTT\|mosquitto" "$ROOT" --include="*.conf" --include="*.cfg" \
    --include="*.json" --include="*.lua" 2>/dev/null | head -30

# Cloud platform tokens (Tuya, HomeKit, AWS IoT, Azure IoT Hub)
grep -rn "tuya\|homekit\|awsiot\|azure.*iot\|device_key\|productKey\|deviceSecret" \
    "$ROOT" --include="*.json" --include="*.conf" 2>/dev/null | head -30

# PCB-serial-derived default PSK (check if device ID used as secret)
grep -rn "serial\|SerialNum\|MAC\|mac_addr" "$ROOT/etc/config/" 2>/dev/null | head -20

Phase 6 — Default Credential Matrix Cross-Reference

# Extract all discovered usernames
USERS=$(grep -v 'nologin\|false\|halt\|sync\|shutdown' "$ROOT/etc/passwd" | \
    awk -F: '{print $1}' | tr '\n' ' ')
echo "Accounts found: $USERS"

# Cross-reference against routersploit / seclists default creds
# RouterSploit default cred wordlist path (if installed):
DFLT=/usr/share/routersploit/resources/wordlists/default_passwords.txt
[ -f "$DFLT" ] && echo "Default wordlist available: $DFLT"

# SecLists IoT default creds
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

VendorUsernamePasswordProtocol
TP-Link (pre-2022)adminadminHTTP / Telnet
NetgearadminpasswordHTTP
D-Linkadmin(blank)HTTP
Asus (stock)adminadminHTTP
MikroTikadmin(blank)SSH / Winbox
Hikvisionadmin12345RTSP / HTTP
DahuaadminadminHTTP
Ubiquiti AirOSubntubntSSH
Western Digital MyCloudadmin(blank)HTTP
Seagate NASadminadminHTTP

Phase 7 — TLS Certificate Private Keys

# Find PEM-encoded private keys
grep -rl "BEGIN.*PRIVATE KEY\|BEGIN RSA PRIVATE KEY" "$ROOT" 2>/dev/null

# Find DER-format keys (binary — look for SEQUENCE headers)
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

# Verify if vendor CA cert is self-signed (same key on all units = MitM vector)
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

# Check if the private key matches the certificate
openssl x509 -noout -modulus -in "$ROOT/etc/ssl/server.crt" | openssl md5
openssl rsa  -noout -modulus -in "$ROOT/etc/ssl/server.key" | openssl md5
# Matching MD5 = key pair is valid and present on device

Evidence

EVDIR=/workspace/evidence/iot/<target>/credentials
mkdir -p "$EVDIR"

# Save cred findings
john /tmp/unshadowed.txt --show > "$EVDIR/cracked_passwords.txt"
cp /tmp/all_strings.txt "$EVDIR/strings_all.txt"

# Record each finding as a credential node
# kg_add_node(
#     kind="credential",
#     label="Hardcoded admin credential in /etc/shadow",
#     props={
#         "key": "iot-cred::<target>::admin",
#         "secret_type": "unix_password",
#         "username": "admin",
#         "hash": "<hash>",
#         "plaintext": "<if cracked>",
#         "source": "firmware /etc/shadow",
#     },
# )

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
Repository
PurpleAILAB/Decepticon
Last updated
First committed

Is this your skill?

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.