⏱️ Lectura: 13 min
Un investigador de seguridad extrajo el firmware de una cámara Hanwha Vision y encontró, duplicado en cerca de 30 archivos distintos, un token de GitHub con permisos de administrador sobre cientos de repositorios privados de la empresa.
📑 En este artículo
- TL;DR
- Introducción
- Qué pasó: el token de GitHub en el firmware
- Contexto e historia
- Detalles técnicos y rendimiento
- Cómo empezar a auditar tu propio firmware
- Impacto y análisis
- Qué sigue
- Preguntas frecuentes
- ¿Qué es trufflehog y por qué lo usan los investigadores de seguridad?
- ¿Por qué el token de GitHub tenía permisos de administrador sobre cientos de repositorios?
- ¿Cómo evito que Vite exponga process.env completo en el bundle final?
- ¿Hanwha Vision respondió públicamente al hallazgo?
- ¿Qué relación real tiene Hanwha Vision con el Departamento de Defensa de EE. UU.?
- ¿Cómo protejo los secretos de mi pipeline de CI/CD para que no terminen en un build de frontend?
- Referencias
El hallazgo no vino de un ataque sofisticado: el token quedó embebido en el bundle JavaScript de la interfaz de administración que la propia cámara sirve a quien entra a su panel de configuración. Cualquiera con acceso a esa pantalla de login pudo haber recibido el secreto sin saberlo.
TL;DR
- Un investigador extrajo el firmware de una cámara Hanwha Vision y halló un token de GitHub duplicado en unos 30 archivos.
- El token tenía permisos de administrador sobre cientos de repositorios privados de la organización de Hanwha en GitHub.
- La causa raíz: la build de Vite volcó todo process.env, incluido el token, al bundle JS de la interfaz admin de la cámara.
- Para llegar al bundle, el investigador tuvo que desofuscar una capa de cifrado AES-256-CBC dentro del binario fwupgrader.
- El investigador escaneó cerca de 500 firmwares distintos de Hanwha para confirmar que el problema no era un caso aislado.
- El firmware también reveló variables de entorno con IPs asignadas al Departamento de Defensa de EE. UU., sin explicación oficial.
- Hanwha Vision nació como Samsung Techwin y es parte de Hanwha Group, con hermanas en defensa como Hanwha Aerospace.
Introducción
Las cámaras de seguridad con Linux embebido dejaron de ser electrodomésticos aislados hace rato. Fabricantes como Axis empujan a que cada cámara corra aplicaciones Linux completas, lo que las convierte en objetivos serios dentro de una red corporativa: necesitan gestión de vulnerabilidades y de credenciales igual que cualquier servidor. Un investigador que venía siguiendo ese movimiento se topó con Hanwha Vision, una marca con firmwares públicos y descargables para cada modelo de cámara, y decidió mirar qué había adentro.
Qué pasó: el token de GitHub en el firmware
El investigador bajó la imagen de firmware y la pasó por binwalk, la herramienta estándar para extraer sistemas de archivos embebidos. Dentro apareció un tarball separado con componentes de IA para la cámara y un archivo fwimage.tgz que binwalk marcó como cifrado.
Una investigación previa de otro investigador de seguridad, Matt Brown, ya había documentado que la contraseña de cifrado de estas cámaras sigue el patrón HTW más el número de modelo (por ejemplo HTWXNP-9300RW). Ese primer nivel se abrió sin problema. Pero adentro había un segundo fwimage.tgz, cifrado con un esquema distinto, que ya no respondía a la técnica de Brown.
La pieza que faltaba estaba en un binario llamado fwupgrader, encargado de aplicar la actualización. Ahí Hanwha había metido una capa de ofuscación: la clave AES quedaba partida contra una tabla estática dentro del binario y se reconstruía en tiempo de ejecución (el IV, en cambio, viajaba en texto plano). El propio fwupgrader no implementaba el cifrado a mano: invocaba al CLI de openssl, y hasta los fragmentos del comando estaban ofuscados con el mismo truco XOR.
Con el comando reconstruido y la clave recompuesta, el investigador pudo descifrar el segundo fwimage.tgz y llegar por fin a un rootfs completo. El primer paso, ahí, fue correr trufflehog sobre el sistema de archivos para buscar secretos obvios. Apareció un token de GitHub repetido en cerca de 30 archivos. Al consultar los permisos de ese token contra la API de GitHub, confirmó que tenía privilegios de administrador sobre cientos de repositorios de la organización de Hanwha.
Contexto e historia
No era la primera vez que el investigador encontraba un token de GitHub filtrado en firmware ajeno, aunque esta vez el detalle que llamó la atención fue el porqué. El token no estaba en un solo archivo de configuración: aparecía repetido porque la interfaz de administración de la cámara se construye con Vite, y alguien había configurado el build para volcar el objeto process.env completo dentro de una variable del bundle. Eso significa que todo lo que existía en el entorno del job de CI (no solo las variables pensadas para el cliente) terminó copiado, archivo por archivo, en el JavaScript que la cámara sirve a cualquiera que llegue a su login.
Entre esas variables había también un puñado de IPs asignadas al Departamento de Defensa de Estados Unidos, en direcciones como las de un supuesto SWARM_MASTER_NFS_ADDRESS u OTEL_ELASTIC_URL internos. Podría ser coincidencia (empresas que reservan rangos de IP internos que nunca van a chocar con tráfico real es una práctica más común de lo que debería), o podría reflejar que la infraestructura de CI de Hanwha Vision es compartida con otras unidades del grupo. Hanwha Vision nació como Samsung Techwin y hoy es subsidiaria de Hanwha Group, un conglomerado surcoreano cuyas otras empresas incluyen fabricantes de artillería autopropulsada y del robot centinela armado SGR-A1. El propio investigador marcó esta parte de su análisis como especulación: no hay evidencia de que Hanwha Vision tenga vínculos operativos directos con el Pentágono, solo la coincidencia de esas direcciones IP en variables de entorno de su CI.
📌 Nota: el hallazgo de las IPs asociadas al DoD es circunstancial. El propio autor de la investigación original lo etiquetó como especulación, no como prueba de un vínculo directo.
Detalles técnicos y rendimiento
El problema de fondo no es exótico: es un patrón conocido de mala configuración en builds de frontend con Vite. Cuando un proyecto usa define para exponer variables al código de cliente, es fácil terminar copiando el objeto process.env entero en lugar de listar solo lo necesario.
// vite.config.js (INSEGURO)
import { defineConfig } from 'vite'
export default defineConfig({
define: {
'process.env': JSON.stringify(process.env)
}
})
Con esa configuración, cualquier variable presente en el entorno del job de CI (tokens de npm, credenciales de despliegue, claves de terceros) queda serializada dentro del archivo JavaScript que se sirve al navegador (o, en este caso, a la interfaz web embebida en la cámara). No hace falta que el código la use: alcanza con que exista en el proceso donde corre vite build.
// vite.config.js (seguro)
import { defineConfig } from 'vite'
export default defineConfig({
define: {
__APP_VERSION__: JSON.stringify(process.env.npm_package_version),
__BUILD_DATE__: JSON.stringify(new Date().toISOString())
}
})
La alternativa recomendada por Vite es su propio mecanismo de variables de entorno con prefijo VITE_: solo esas variables llegan a import.meta.env en el cliente, y todo lo demás queda fuera del bundle por defecto.
| Método en Vite | Qué termina en el bundle del cliente | Riesgo |
|---|---|---|
define: { 'process.env': JSON.stringify(process.env) } | Todas las variables del entorno de CI, incluidos tokens | Alto: cualquier secreto del job queda en el JS público |
Prefijo VITE_ + import.meta.env | Solo las variables que empiezan con VITE_ | Bajo: expone solo lo que el equipo marcó explícitamente como público |
define con claves puntuales | Solo los valores listados a mano (versión, fecha de build, etc.) | Bajo: control explícito, sin volcado accidental |
El diagrama siguiente resume el camino que siguió el secreto: de una variable de entorno del pipeline de CI a un archivo público servido por cada cámara vendida.
flowchart TD
A["CI/CD del fabricante"] --> B["Variable de entorno: GITHUB_NPM_TOKEN"]
B --> C["vite build vuelca process.env completo"]
C --> D["Bundle JS de la interfaz admin"]
D --> E["Firmware de la camara"]
E --> F["Panel admin servido por la camara"]
F --> G["Quien accede al panel recibe el token"]
Cómo empezar a auditar tu propio firmware
No hace falta tener una cámara Hanwha a mano para aplicar la misma técnica sobre tus propios artefactos de build. La receta básica es: extraer, decodificar si hace falta, y escanear con una herramienta de detección de secretos.
Instalar trufflehog
# Linux (script oficial)
curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh | sh -s -- -b /usr/local/bin
# macOS (Homebrew)
brew install trufflehog
# Windows (con Scoop, desde PowerShell)
scoop install trufflehog
Con el binario instalado, el escaneo mínimo sobre un directorio extraído es directo:
trufflehog filesystem ./firmware-extraido --results=verified,unverified
Ese comando busca patrones de credenciales conocidos (tokens de GitHub, claves de AWS, credenciales de npm, entre decenas de formatos) y, cuando puede, verifica contra la API del servicio si el secreto sigue activo. Para auditar tu propio repositorio antes de cada build, conviene correrlo también como parte del pipeline de CI, no solo de forma manual.
💡 Tip: corré el escaneo de secretos sobre el artefacto final de build (el bundle, la imagen de contenedor, el firmware), no solo sobre el código fuente. Muchos leaks de este tipo no están en el repo: aparecen recién en el paso de empaquetado.
Si trabajás con Vite, un chequeo rápido y gratuito es buscar en el bundle generado si aparece el string process.env completo en lugar de nombres de variables puntuales:
npm run build
grep -c "process.env" dist/assets/*.js
Un resultado alto en ese grep es señal de que vale la pena revisar el vite.config.js antes de publicar.
Impacto y análisis
El investigador no se quedó con un solo caso: para confirmar que no era una casualidad, scrapeó el sitio de Hanwha y descargó cerca de 500 firmwares distintos, cubriendo gran parte de la línea de cámaras de la marca. La causa raíz (la configuración de Vite volcando process.env completo) es del tipo de bug que, una vez introducido en una plantilla de build compartida entre modelos, se replica automáticamente en cada release nueva sin que nadie lo note.
El riesgo real no es solo que alguien vea el token: es qué puede hacer con permisos de administrador sobre cientos de repositorios privados. Eso incluye, potencialmente, empujar cambios a esos repos, rotar colaboradores, o insertar código malicioso en una futura build, exactamente el tipo de acceso que interesa en un ataque a la cadena de suministro. El propio investigador señaló que no era la primera vez que encontraba un token de GitHub filtrado en el firmware de una empresa, lo que sugiere que el patrón (variables de CI volcadas sin filtro a un build de cliente) es más común de lo que la industria de IoT quisiera admitir.
Qué sigue
Lo esperable tras un hallazgo así es la rotación inmediata del token expuesto y una auditoría de qué se hizo con él mientras estuvo activo, algo que solo Hanwha puede confirmar puertas adentro. Para el resto de la industria, el caso es otro recordatorio de que la seguridad de un dispositivo IoT no termina en el hardware: el pipeline que compila y firma el firmware es parte de la superficie de ataque, y cualquier variable de entorno del job de CI puede terminar, sin que nadie lo pida, dentro del producto final.
📖 Resumen en Telegram: Ver resumen
Probalo vos: corré trufflehog filesystem . sobre el bundle de tu último build antes de publicarlo y confirmá que no arrastra ninguna variable de tu CI.
Preguntas frecuentes
¿Qué es trufflehog y por qué lo usan los investigadores de seguridad?
Es un escáner de secretos de código abierto que busca patrones de credenciales (tokens, claves API, contraseñas) en código fuente, sistemas de archivos y repositorios, y que además intenta verificar contra la API del servicio correspondiente si el secreto encontrado sigue activo.
¿Por qué el token de GitHub tenía permisos de administrador sobre cientos de repositorios?
El artículo original no detalla la política interna de Hanwha para generar el token, pero el alcance amplio (admin sobre cientos de repos) es consistente con usar un único token de organización para múltiples pipelines de CI, en lugar de tokens de vida corta y permisos acotados por repositorio.
¿Cómo evito que Vite exponga process.env completo en el bundle final?
Evitá usar define: { 'process.env': JSON.stringify(process.env) }. Usá en cambio variables con el prefijo VITE_, que Vite expone de forma explícita a través de import.meta.env, o listá a mano las claves puntuales que necesitás inyectar.
¿Hanwha Vision respondió públicamente al hallazgo?
El artículo original, publicado en hhh.hn, no reporta una respuesta pública de Hanwha Vision al momento de la publicación de esta nota.
¿Qué relación real tiene Hanwha Vision con el Departamento de Defensa de EE. UU.?
Ninguna confirmada. El hallazgo de IPs asociadas a rangos del DoD en variables de entorno de su CI es circunstancial y el propio investigador lo marcó como especulación, no como evidencia de un vínculo operativo.
¿Cómo protejo los secretos de mi pipeline de CI/CD para que no terminen en un build de frontend?
Usá variables de CI con alcance mínimo (un token por pipeline, no uno compartido para toda la organización), rotalas periódicamente, y agregá un escaneo de secretos como trufflehog o gitleaks como paso obligatorio antes de publicar cualquier artefacto, sea un bundle web o una imagen de firmware.
Referencias
- hhh.hn: My security camera shipped a GitHub admin token in its login page: el análisis original del investigador, con el proceso completo de extracción y desofuscación del firmware.
- GitHub: trufflesecurity/trufflehog: repositorio del escáner de secretos usado para detectar el token filtrado.
- Vite: Env Variables and Modes: documentación oficial sobre el prefijo VITE_ y cómo Vite decide qué variables exponer al cliente.
- Wikipedia: Hanwha Vision: historia de la empresa, antes Samsung Techwin, y su relación con Hanwha Group.
- OWASP Secrets Management Cheat Sheet: guía de referencia para evitar que secretos de CI terminen en artefactos de build.
📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.
Imagen destacada: Foto de Harrison Broadbent en Unsplash
0 Comentarios