
De uma PCB nua até root: hackeando o hardware de um ZyXEL P-870HN (BCM6368) via UART — CVE-2025-0890 + CVE-2024-40891, no meu próprio hardware.
Duas fotos de celular de uma placa de roteador sem etiqueta → console serial → bypass de autenticação → shell root — reproduzindo a cadeia real, ainda sem patch, CVE-2025-0890 (conta supervisor oculta) + CVE-2024-40891 (injeção de comando no CLI) no hardware que eu possuo.
por damik0 · 2026-08-13 · um passo a passo de hardware-hacking
📷 Fotos da PCB ─▶ 🔬 recon de chips ─▶ 🏷️ ID do modelo ─▶ 📍 encontrar UART (J2)
└─▶ 🔌 console serial ─▶ 🚪 conta oculta ─▶ ⛓️ escapar do CLI
└─▶ 🐚 shell root ─▶ 🔓 dump + quebrar todas as credenciais
Eu tinha uma placa de roteador aleatória em cima da mesa. Sem carcaça, sem etiqueta, sem ideia do que era. Partindo do nada além de duas fotos, li cada chip da PCB, identifiquei o modelo exato, encontrei o header serial (UART), liguei nele, entrei por uma conta de backdoor de fábrica, escapei de um menu do fornecedor bloqueado para um shell Linux root e extraí todas as senhas do equipamento — quebradas em menos de um segundo.
Nenhum desses bugs é meu. São problemas documentados da ZyXEL que o fornecedor disse que não vai corrigir. O que este repo mostra é o como, de ponta a ponta, e o raciocínio em cada etapa.
Descobri a identificação a partir do número da placa na serigrafia 45-402-000022 e do código de barras, cruzando com o TechInfoDepot, a tabela de hardware do OpenWrt e o FCC ID I88P870HN51B:
Por que o número da placa é a chave que destranca tudo: gateways ODM como este são projetos de referência. Quando o número de parte na serigrafia corresponde a uma placa documentada, você herda o dever de casa de outra pessoa — o chip de flash exato, a localização e o pinout da UART, as contas padrão. A identificação não é uma formalidade; é o que transforma sondagem às cegas em um ataque direcionado.
Primeiro, uma pequena melhoria de qualidade de vida: montei rapidinho um uploader de fotos via LAN (stdlib do Python, zero dependências) para fotografar a placa com o celular e as fotos caírem direto na minha máquina. Metade de uma boa sessão é eliminar esse tipo de atrito.
Fui chip por chip nas fotos em alta resolução. Os tipos de encapsulamento contam a história antes mesmo de você ler as marcações: o BGA no centro é o cérebro, o TSOP-48 quase sempre é a flash paralela, a latinha com o cabo coaxial é o rádio. O SoC estava escondido sob um escudo de RF (ali por causa de EMI + como dissipador de calor), então tirei a tampa para ler a marcação embaixo — um Broadcom BCM6368.

A placa mapeada: (1) SoC BCM6368, (2) RAM DDR2, (3) WiFi BCM43222, (4) transformador de linha DSL, (5) magnéticos Ethernet, (6) headers USB internos, (7)(8) marcações da placa, (9) header de console J2, (10) footprint JTAG não populado.
A serigrafia 45-402-000022 correspondeu exatamente à placa documentada, e cada chip — SoC, flash, WiFi, os 64 MB de RAM — bateu peça por peça com a variante -53b. Agora eu não sabia apenas o que era; eu sabia onde vivia a UART e qual conta me deixaria entrar.
Bem ao lado do SoC havia um header de 6 pinos em ângulo reto, populado, com serigrafia J2 e um triângulo marcando o pino 1. Confirmei na página do OpenWrt para o modelo:
115200 8N1, TTL de 3,3 V.

Como encontrar uma UART quando não há wiki informando o pinout — a parte que mostra que isto não é apenas seguir uma receita:
- GND — continuidade (bip) com o plano de terra / a blindagem, com a placa desenergizada.
- VCC — um trilho que se mantém estável em ~3,3 V quando energizado.
- TX — fica em nível alto em ~3,3 V (estado de marca da UART) e oscila/pisca visivelmente no instante em que o dispositivo inicia e começa a despejar o log. Essa oscilação é o console falando.
- RX — normalmente o quieto: flutuante ou com pull fraco, sem atividade no boot.
E se você não soubesse o baud?
115200é o padrão do CFE da Broadcom, mas às cegas você varreria as taxas comuns (9600 → 115200) até o lixo virar ASCII, ou mediria o período de bit mais estreito num osciloscópio e faria1 / t.
Liguei um adaptador USB-TTL (HW-597, PL2303) com o jumper em 3,3 V. Isso importa: a UART do BCM6368 é TTL de 3,3 V, não RS-232 (±12 V) — conecte uma porta serial de verdade ou um adaptador de 5 V nela e você queima o pino. Terra primeiro, depois RX/TX cruzados, VCC deixado flutuante para que nada realimente a placa. Antes de aplicar energia, confirmei GND e VCC com um multímetro e então:
screen /dev/ttyUSB0 115200
Liguei, vi o CFE passar o controle para o kernel, vi o init do BusyBox subir e parei em um prompt de login.
O login cedeu a uma conta de fábrica oculta que a ZyXEL nunca documenta para o usuário final:
user: supervisor
pass: zyad1234
Privilégio total do sistema. Esse é o núcleo da CVE-2025-0890.
Esse login me jogou em um CLI do fornecedor bloqueado (consoled, um prompt >): sem sh, nenhuma das ferramentas Linux usuais — uma jaula em volta do sistema real. Mas ele expunha um diagnóstico ping, e esse comando montava o argumento direto numa string de shell com zero sanitização. Então dei a ele um metacaractere de shell:
> ping 127.0.0.1; sh
…e caí em um shell BusyBox root (#).
Por que um ponto e vírgula é suficiente: o handler do CLI faz o equivalente a
system("ping " + userinput). O;encerra o comandopinge inicia um segundo —sh— que herda o stdin/stdout do console, então você obtém um shell interativo. A conta já era uid 0; o CLI era a única coisa entre mim e um shell de verdade, e a entrada não sanitizada derrubou essa parede. Encadear uma injeção de CLI autenticada na conta oculta é exatamente o padrão rastreado como CVE-2024-40891.
Com root, examinei o sistema e a 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
O que
/proc/mtdestá lhe dizendo: a flash é NOR paralela mapeada em memória — a CPU a enxerga como uma faixa plana de endereços (por volta de0xB8000000no KSEG1 do MIPS), exposta como uma única partição MTD. Isso é ótimo para um dump: a NOR faz leitura limpa, sem os bytes spare/OOB e as esquisitices de ECC com que você luta em NAND./dev/mtdblock0é a imagem do firmware.
Então, as senhas. Não há /etc/shadow — os hashes estão bem em /etc/passwd, usando o antigo crypt DES:
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
Extraí os hashes e os quebrei offline com o John the Ripper (--format=descrypt). Todos os seis caíram em menos de um segundo:
Por que elas evaporam instantaneamente: o
crypt(3)DES só usava os primeiros 8 caracteres da senha e um salt de 12 bits, passados por 25 rodadas de DES. Numa CPU moderna, um cracker DES em bitslice processa dezenas de milhões de candidatos por segundo — então senhas de fábrica triviais comoadminousupportnem contam como trabalho. Esse esquema já era obsoleto há décadas; encontrá-lo em firmware de produção é o verdadeiro achado.
Quatro contas de fábrica com privilégio de root, senhas triviais, idênticas em todas as unidades deste modelo.
A cadeia completa, em uma linha:
Foto da PCB → ID do SoC → encontrar a UART (J2) → console serial
→ conta oculta (F-1) → CLI bloqueado → injeção de comando (F-2)
→ shell root → dump + quebrar todas as credenciais (F-3)
Não fui eu que descobri nada disso. É reprodução, por acesso físico, de bugs públicos e atualmente relevantes:
supervisor:zyad1234, em CPE DSL legados da ZyXEL. → F-1Essas falhas atingem equipamentos em fim de vida que a ZyXEL disse que não vai corrigir, e já foram vistas sendo exploradas na natureza — exatamente por isso colocar as mãos na mecânica importa. O valor aqui não é um bug novo; é o fluxo de trabalho completo de silício até o shell, feito e documentado.
execve com um vetor de argumentos, não system())./etc/shadow com um hash moderno (bcrypt / SHA-512-crypt), não DES.mtd0 (/dev/mtdblock0, 5,197,824 bytes) pelo próprio WiFi do roteador + nc e depois desempacote com binwalk (espere header CFE + kernel comprimido em LZMA + rootfs SquashFS + nvram). Método completo em evidence/dump-methods.md.Análise da PCB a partir das fotos (ImageMagick), um multímetro, um adaptador USB-TTL PL2303 (HW-597) em 3,3 V, screen para o console serial (115200 8N1) e John the Ripper (descrypt) para os hashes. Identificação via OpenWrt, TechInfoDepot e o banco de dados da FCC.
Identificação do dispositivo
45-402-000022, flash MX29LV640EBTI-70G)Vulnerabilidades
supervisor ocultaHardware e técnica
Ferramentas
Feito no meu próprio hardware, isolado (air-gapped), sem sistemas de terceiros envolvidos. Os bugs são publicamente documentados e citados acima. Aquilo em que estou pondo meu nome é o método completo de hardware-hacking e sua execução — não a descoberta das falhas.
| Modelo | ZyXEL P-870HN-53b — gateway WiFi VDSL2/ADSL2+, fabricado pela MitraStar |
| Era | ~2013 (os códigos de data apontam para a semana 21 de 2013); unidade distribuída por ISP |
| SoC | Broadcom BCM6368UKPBG — MIPS dual-core (BMIPS4350), ~400 MHz |
| RAM | 2× Winbond W9425G6JH-5 — 256 Mbit DDR2 ×16 cada = 64 MB em um barramento de 32 bits |
| Flash | Macronix MX29LV640EBTI-70G — NOR paralela de 8 MB, TSOP-48 |
| WiFi | Broadcom BCM43222 (802.11n; silício dual-band, ligado apenas a 2,4 GHz) |
| DSL AFE | Broadcom BCM6302 |
| Firmware | Linux 2.6.30 + BusyBox v1.00, bootloader Broadcom CFE (compilado em 2012-06-11) |
| Pino | Sinal |
|---|
| 1 | VCC 3.3V | deixe-o desconectado |
| 2 | Tx | → RX do adaptador |
| 3 | Rx | → TX do adaptador |
| 4 | GND | → GND do adaptador |
| 5 | NC |
| Conta | Senha | UID | GID | Privilégio |
|---|
| supervisor | zyad1234 | 0 | 0 | root |
| support | support | 1 | 0 | grupo root |
| user | user | 2 | 0 | grupo root |
| admin | admin | 100 | 0 | grupo root |
| nobody | zyad1234 | 99 | 99 | ftp |
| # | Achado | CWE | Gravidade |
|---|
| F-1 | Contas de fábrica ocultas com privilégio de root (supervisor, support, user, admin) — credenciais fixas (hardcoded), idênticas em todas as unidades. | CWE-798 | Alta |
| F-2 | Injeção de comando autenticada no diagnóstico ping do CLI → escape para um shell root, pulando a fronteira de privilégio do CLI. | CWE-78 | Alta |
| F-3 | Armazenamento fraco de credenciais — hashes DES-crypt em /etc/passwd (sem shadow) → quebra offline instantânea. | CWE-916 / CWE-256 | Média |