
Da un PCB nudo alla root: hardware-hacking di uno ZyXEL P-870HN (BCM6368) via UART — CVE-2025-0890 + CVE-2024-40891, sul mio stesso hardware.
Due foto dal telefono di una scheda router senza etichetta → console seriale → bypass dell'autenticazione → shell di root — riproduzione della catena reale, ancora non patchata, CVE-2025-0890 (account supervisor nascosto) + CVE-2024-40891 (command injection nella CLI) su hardware di mia proprietà.
di damik0 · 2026-08-13 · un walkthrough di hardware-hacking
📷 PCB photos ─▶ 🔬 chip recon ─▶ 🏷️ model ID ─▶ 📍 find UART (J2)
└─▶ 🔌 serial console ─▶ 🚪 hidden account ─▶ ⛓️ break out of CLI
└─▶ 🐚 root shell ─▶ 🔓 dump + crack every credential
Avevo una scheda router qualsiasi sulla scrivania. Niente case, niente etichetta, nessuna idea di cosa fosse. Partendo da nient'altro che due foto, ho letto ogni chip del PCB, ho individuato il modello esatto, ho trovato il connettore seriale (UART), mi ci sono collegato, sono entrato attraverso un account backdoor di fabbrica, sono uscito da un menu vendor bloccato in una shell Linux di root e ho estratto ogni password dal dispositivo — crackate in meno di un secondo.
Nessuna di queste vulnerabilità è farina del mio sacco. Sono problemi ZyXEL documentati che il vendor ha dichiarato di non voler patchare. Questo repo riguarda il come, dall'inizio alla fine, e il ragionamento dietro ogni passaggio.
Ho risalito all'ID partendo dal numero di scheda serigrafato 45-402-000022 e dal codice a barre, incrociando i dati con TechInfoDepot, la tabella hardware di OpenWrt e l'FCC ID I88P870HN51B:
Perché il numero di scheda è la chiave che sblocca tutto: i gateway ODM come questo sono reference design. Una volta che il numero di parte serigrafato corrisponde a una scheda documentata, erediti i compiti di qualcun altro — il chip di flash esatto, la posizione e il pinout della UART, gli account predefiniti. L'identificazione non è una formalità: è ciò che trasforma il probing alla cieca in un attacco mirato.
Prima una piccola miglioria di comodità: ho buttato giù un minuscolo uploader di foto via LAN (solo stdlib Python, zero dipendenze) così potevo fotografare la scheda col telefono e far arrivare le immagini direttamente sulla mia macchina. Metà di una buona sessione è eliminare attriti come questo.
Sono andato chip per chip partendo dalle foto ad alta risoluzione. I tipi di package raccontano la storia ancor prima di leggere le marcature: il BGA al centro è il cervello, il TSOP-48 è quasi sempre flash parallelo, la piccola scatoletta con il cavetto coassiale è la radio. Il SoC era nascosto sotto uno schermo RF (presente per l'EMI e come diffusore di calore), quindi ho aperto la scatoletta per leggere la marcatura sottostante — un Broadcom BCM6368.

La scheda, mappata: (1) SoC BCM6368, (2) RAM DDR2, (3) WiFi BCM43222, (4) trasformatore di linea DSL, (5) componenti magnetici Ethernet, (6) connettori USB interni, (7)(8) marcature della scheda, (9) connettore console J2, (10) footprint JTAG non popolato.
La serigrafia 45-402-000022 corrispondeva esattamente alla scheda documentata, e ogni chip — SoC, flash, WiFi, i 64 MB di RAM — combaciava pezzo per pezzo con la variante -53b. Ora non sapevo solo cosa fosse; sapevo dove viveva la sua UART e quale account mi avrebbe fatto entrare.
Proprio accanto al SoC c'era un connettore a 6 pin ad angolo retto, popolato, serigrafato J2, con un triangolo che marca il pin 1. Confermato incrociando la pagina di OpenWrt per il modello:
115200 8N1, 3,3 V TTL.

Come trovi una UART quando non c'è nessuna wiki che ti dice il pinout — la parte che dimostra che non è solo questione di seguire una ricetta:
- GND — continuità (beep) con il piano di massa / lo schermo, scheda non alimentata.
- VCC — un rail che si assesta su ~3,3 V stabili una volta alimentato.
- TX — riposa su livello alto a ~3,3 V (stato mark UART) e cala/sfarfalla visibilmente nell'istante in cui il dispositivo si avvia e inizia a sputare fuori il suo log. Quel sfarfallio è la console che parla.
- RX — di solito quella silenziosa: flottante o debolmente pullata, nessuna attività all'avvio.
E se non conoscessi il baud?
115200è il default del CFE Broadcom, ma alla cieca scorreresti le velocità comuni (9600 → 115200) finché la spazzatura non diventa ASCII, oppure misureresti il periodo di bit più stretto su un oscilloscopio e faresti1 / t.
Ho collegato un adattatore USB-TTL (HW-597, PL2303) con il jumper su 3,3 V. Questo è importante: la UART del BCM6368 è TTL a 3,3 V, non RS-232 (±12 V) — se ci appendi una vera porta seriale o un adattatore a 5 V friggi il pin. Prima la massa, poi RX/TX incrociati, VCC lasciato flottante così nulla alimenta la scheda all'indietro. Prima di dare tensione ho verificato GND e VCC con un multimetro, poi:
screen /dev/ttyUSB0 115200
L'ho alimentata, ho visto il CFE passare il controllo al kernel, ho visto partire l'init di BusyBox e sono finito su un prompt di login.
Il login è caduto su un account di fabbrica nascosto che ZyXEL non documenta mai per l'utente finale:
user: supervisor
pass: zyad1234
Privilegi di sistema completi. Questo è il cuore di CVE-2025-0890.
Quel login mi ha fatto finire in una CLI vendor bloccata (consoled, un prompt >): niente sh, nessuno dei soliti strumenti Linux — una gabbia avvolta attorno al sistema reale. Ma esponeva un comando diagnostico ping, e quel comando costruiva il suo argomento direttamente in una stringa di shell con zero sanitizzazione. Così gli ho passato un metacarattere di shell:
> ping 127.0.0.1; sh
…e sono finito in una shell BusyBox di root (#).
Perché un solo punto e virgola basta: il gestore della CLI fa l'equivalente di
system("ping " + userinput). Il;chiude il comandopinge ne avvia un secondo —sh— che eredita stdin/stdout della console, quindi ottieni una shell interattiva. L'account era già uid 0; la CLI era l'unica cosa tra me e una vera shell, e un input non sanitizzato ha abbattuto quel muro. Concatenare un'iniezione CLI autenticata all'account nascosto è esattamente il pattern tracciato come CVE-2024-40891.
Con la root, ho dato un'occhiata al sistema e alla memoria flash:
# cat /proc/version
Linux version 2.6.30 ... (Buildroot 2010.02) #1 Mon Jun 11 2012
# cat /proc/mtd
dev: size erasesize name
mtd0: 004f5000 004f5000 "Physically mapped flash" # 5,197,824 bytes = the whole firmware
Cosa ti sta dicendo
/proc/mtd: la memoria flash è NOR parallelo, mappato in memoria — la CPU la vede come un intervallo di indirizzi piatto (intorno a0xB8000000in MIPS KSEG1), esposta come una singola partizione MTD. Ottima notizia per un dump: il NOR si rilegge pulito, senza i byte spare/OOB e le stranezze ECC con cui devi lottare sul NAND./dev/mtdblock0è l'immagine del firmware.
Poi le password. Non c'è /etc/shadow — gli hash stanno proprio in /etc/passwd, con l'antico DES crypt:
supervisor:SuO7vycdWI/rU:0:0:Administrator:/:/bin/sh
support:xoKf506EVkGKw:1:0:Technical Support:/:/bin/sh
user:QWOftoXez8Goo:2:0:Normal User:/:/bin/sh
admin:OJGXQ9dWyb9m2:100:0:Administrator:/:/bin/sh
Le ho estratte e crackate offline con John the Ripper (--format=descrypt). Tutte e sei sono cadute in meno di un secondo:
Perché evaporano all'istante: il
crypt(3)DES usava solo i primi 8 caratteri della password e un salt a 12 bit, passati attraverso 25 round di DES. Su una CPU moderna un cracker DES bitslice mastica decine di milioni di candidati al secondo — quindi password di fabbrica banali comeadminosupportnon vengono nemmeno registrate come lavoro. Questo schema era obsoleto decenni fa; trovarlo in firmware in produzione è la vera scoperta.
Quattro account di fabbrica con privilegi a livello root, password banali, identici su ogni unità di questo modello.
L'intera catena, in una riga:
PCB photo → ID the SoC → find the UART (J2) → serial console
→ hidden account (F-1) → locked CLI → command injection (F-2)
→ root shell → dump + crack every credential (F-3)
Non ho scoperto nulla di tutto questo. È riproduzione, tramite accesso fisico, di bug pubblici e ancora attuali:
supervisor:zyad1234, su CPE DSL ZyXEL legacy. → F-1Questi colpiscono apparati end-of-life che ZyXEL ha dichiarato di non voler sistemare, e sono stati visti sfruttati in the wild — che è esattamente il motivo per cui mettere le mani sui meccanismi conta. Il valore qui non è un nuovo bug; è il workflow completo dal silicio alla shell, eseguito e documentato.
execve con un vettore di argomenti, non system())./etc/shadow con un hash moderno (bcrypt / SHA-512-crypt), non DES.mtd0 (/dev/mtdblock0, 5.197.824 byte) tramite il WiFi del router stesso + nc, poi spacchettalo con binwalk (attesi header CFE + kernel compresso LZMA + rootfs SquashFS + nvram). Metodo completo in evidence/dump-methods.md.Analisi del PCB dalle foto (ImageMagick), un multimetro, un adattatore USB-TTL PL2303 (HW-597) a 3,3 V, screen per la console seriale (115200 8N1), e John the Ripper (descrypt) per gli hash. Identificazione tramite OpenWrt, TechInfoDepot e il database FCC.
Identificazione del dispositivo
45-402-000022, flash MX29LV640EBTI-70G)Vulnerabilità
supervisor nascostoHardware e tecnica
Strumenti
Fatto su hardware di mia proprietà, in isolamento (air-gapped), senza coinvolgere sistemi di terze parti. I bug sono documentati pubblicamente e citati sopra. Ciò a cui metto il mio nome è il metodo di hardware-hacking end-to-end e la sua esecuzione — non la scoperta delle falle.
| Modello | ZyXEL P-870HN-53b — gateway WiFi VDSL2/ADSL2+, prodotto da MitraStar |
| Epoca | ~2013 (i date-code indicano la settimana 21 del 2013); unità distribuita da un ISP |
| SoC | Broadcom BCM6368UKPBG — MIPS dual-core (BMIPS4350), ~400 MHz |
| RAM | 2× Winbond W9425G6JH-5 — 256 Mbit DDR2 ×16 ciascuna = 64 MB su bus a 32 bit |
| Flash | Macronix MX29LV640EBTI-70G — 8 MB NOR parallelo, TSOP-48 |
| WiFi | Broadcom BCM43222 (802.11n; silicio dual-band, collegato solo a 2,4 GHz) |
| AFE DSL | Broadcom BCM6302 |
| Firmware | Linux 2.6.30 + BusyBox v1.00, bootloader Broadcom CFE (compilato il 2012-06-11) |
| Pin | Segnale |
|---|
| 1 | VCC 3,3 V | lasciarlo scollegato |
| 2 | Tx | → RX adattatore |
| 3 | Rx | → TX adattatore |
| 4 | GND | → GND adattatore |
| 5 | NC |
| Account | Password | UID | GID | Privilegi |
|---|
| supervisor | zyad1234 | 0 | 0 | root |
| support | support | 1 | 0 | gruppo root |
| user | user | 2 | 0 | gruppo root |
| admin | admin | 100 | 0 | gruppo root |
| nobody | zyad1234 | 99 | 99 | ftp |
| # | Riscontro | CWE | Gravità |
|---|
| F-1 | Account di fabbrica nascosti con privilegi di root (supervisor, support, user, admin) — credenziali hardcoded, identiche su ogni unità. | CWE-798 | Alta |
| F-2 | Command injection autenticata nel diagnostico CLI ping → evasione verso una shell di root, scavalcando il confine di privilegi della CLI. | CWE-78 | Alta |
| F-3 | Archiviazione debole delle credenziali — hash DES-crypt in /etc/passwd (senza shadow) → cracking offline immediato. | CWE-916 / CWE-256 | Media |