Descripción

El Proyecto IoTGoat es un firmware deliberadamente inseguro basado en OpenWrt y mantenido por OWASP como una plataforma para educar a los desarrolladores de software y profesionales de ciberseguridad mediante pruebas de vulnerabilidades comúnmente encontradas en dispositivos IoT.
La maquina virtual de IoTGoat presenta las 10 principales vulnerabilidades del IoT de OWASP.

Dirección IP: 192.168.172.129

Sistema operativo: Linux

Dificultad: Media

Técnicas Vistas:

• Hardcoded user credentials compiled into firmware
• Insecure Network Services
• Information Leakage
• Cracking with John
• Unshadow passwd & shadow files
• Insecure Ecosystem Interfaces
• XSS
• Wireshark to sniff plaintext credentials
• Lack of Secure Update Mechanism
• Insecure Data Transfer and Storage
• Insecure Default Settings
• OWASP Firmware Security Testing Methodology

IoT Goat

En este writeup, les mostraré mis soluciones a este Laboratorio. Este Laboratorio ofrece diferentes maneras de iniciarse en el hacking de IoT. En mi caso, descargué el firmware precompilado IoTGoat-x86.img.gz para el análisis estático y también descargué IoTGoat-x86.vmdk para realizar pruebas dinámicas usando VMware.

Agradecimientos

Quiero agradecer a fen1x1a por compartirme esta guía práctica para la extracción y análisis de firmware de routers. Su documentación fue la base del procedimiento que muestro a continuación, donde se explica paso a paso cómo realizar el volcado del firmware desde un dispositivo físico utilizando un programador CH341A y herramientas como flashrom y binwalk.

Nota sobre el alcance y relación con IoTGoat

La guía que sigue documenta únicamente el proceso de extracción y análisis estático del firmware de un router TP-Link TL-WR840N. Este procedimiento se presenta como una sección independiente del laboratorio IoTGoat, aunque ambos trabajos están estrechamente relacionados por su enfoque en la seguridad de dispositivos IoT y firmware embebido.

En el caso de IoTGoat, yo partí de un firmware ya disponible (el archivo IoTGoat-x86.img.gz) y comencé el análisis directamente desde la fase de extracción con binwalk y exploración del sistema de archivos. Es decir, los pasos que se muestran aquí —desde la extracción con binwalk -Me y la inspección del contenido del firmware— son prácticamente los mismos que utilicé en el laboratorio de IoTGoat, solo que en ese caso no fue necesario extraer físicamente el firmware desde el hardware.


Extracción del firmware de un router - guía práctica (TP-Link TL-WR840N)

Requisitos previos:

  • Sistema GNU/Linux con los siguientes paquetes instalados: flashrom, binwalk.
  • Programador SPI: CH341A con pinzas de 8 pines (o equivalente).

programador ch341a.jpg

  • Equipo objetivo: router (en este caso: TP-Link TL-WR840N).

router.jpg

Preparación y localización de componentes

  • Abre el router con cuidado y localiza el chip FLASH (EEPROM / SPI flash).

uart.png

  • Identifica pines útiles: UART (Tx/Rx/GND/Vcc) y pines SPI (CS, MISO, MOSI, SCLK, Vcc, GND).

epprom.png

Conexión del programador CH341A

  • Coloca las pinzas en modo SPI y alinea el cable rojo con el pin CS del chip.
  • Conecta GND entre programador y placa; confirma el voltaje (habitualmente 3.3 V).
  • Si el CH341A no es detectado, revisa la orientación/posición de las pinzas y vuelve a intentar.

spi.png

spi2.jpg

conectado.jpg

Precaución: una mala conexión puede corromper la lectura o dañar el chip. Toma medidas ESD.

Lectura de la ROM (volcado)

Volca la memoria a un archivo binario local:

1
2
sudo flashrom -V -r firmware.bin -p ch341a_spi --progress
# firmware.bin es el archivo resultante

Para verificar, si procede:

1
sudo flashrom -V -v firmware.bin -p ch341a_spi

extract.png

exxtract2.png

Nota: si el dispositivo no detecta el CH341A, revisa la presión/orientación de las pinzas antes de volver a conectar.

Extracción y análisis estático con binwalk

Extrae el contenido y busca sistemas de archivos:

1
binwalk -Me firmware.bin
  • M búsqueda recursiva; e extrae automáticamente.
  • En Arch Linux puede aparecer Failed to execute command sasquatch; la solución habitual es instalar sasquatch desde AUR (actúa con precaución).

bin1.png

bin2.png

bin3.png

Búsqueda de credenciales y hashes

Revisa /etc, passwd.bak, shadow.bak, etc

etc.png

Identifica el tipo de hash con hashid u otra herramienta.

hashid.png

Ejemplo de crack con hashcat (MD5crypt — modo 500):

1
sudo hashcat -m 500 hash.txt /usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt

hashcat.png

Acceso dinámico vía UART

Conecta un adaptador USB-TTL (CP2102, FTDI, Flipper Zero, etc.) a los pines UART y usa screen o minicom:

1
screen /dev/ttyUSB0 115200

Prueba las credenciales encontradas o logins por defecto para obtener una consola.

flipper.jpg

i2c.jpg

cp21.jpg

Conclusión práctica

El proceso (localizar chip → conectar CH341A → volcar con flashrom → extraer con binwalk → inspeccionar credenciales → usar UART) permite trasladar un firmware cerrado a un entorno controlado para análisis estático y pruebas. En el TP-Link TL-WR840N estudiado se identificó un rootfs con BusyBox, un kernel obsoleto y hashes MD5crypt, lo que ejemplifica por qué muchos dispositivos IoT son riesgosos si no reciben actualizaciones.


IoT GOAT

IoT_Goat.jpg

IP de la Maquina

192.168.172.129

1. Credenciales de usuario incrustadas en el firmware (Hardcoded user credentials compiled into firmware)

Las credenciales por defecto o hardcodeadas en firmware permiten acceso inicial sin necesidad de explotación sofisticada. En dispositivos IoT esto es crítico: se convierten en una puerta de entrada para los ciberdelincuentes.

Lo primero que hacemos es descargar el firmware y extraerlo usando binwalk.

img-gz.png

Una vez descargado el firmware lo descomprimimos.

1
gunzip IoTGoat-x86.img.gz

img-decompress.png

Ahora extraemos el sistema de archivos de la imagen del firmware con binwalk.

1
binwalk -e IoTGoat-x86.img

binwalk.png

filesystem.png

Como no está cifrado, podemos acceder al sistema de archivos. Una vez extraído el sistema de archivos procedemos a buscar los archivos donde se almacenan las contraseñas en Linux.

Buscamos el /etc/passwd y comprobamos que usuarios poseen una shell /bin/ash

1
find . -name "passwd"

passwd.png

Observamos que los usuarios root y iotgoatuser poseen una shell

1
cat ./squashfs-root/etc/passwd

etc-passwd.png

Buscamos las contraseñas en el /etc/shadow

1
2
find . -name "shadow"
cat ./squashfs-root/etc/shadow

algoritm-hash.png

En este archivo encontramos las contraseñas hasheadas de los usuarios del sistema. Ahora vamos a identificar el tipo de hash para intentar crackearlas.

Identificamos el tipo de hash

1
hash-identifier

md5.png

Ahora procedemos a crackear ambos hashes con john usando un diccionario especial de Seclist el cual descubrí que la botnet Mirai uso con las contraseñas predeterminadas comunes de los dispositivos IoT, que se encuentra en la siguiente ruta en mi sistema: /usr/share/seclists/Passwords/Malware/mirai-botnet.txt

En este caso el diccionario tiene un formato de user:pass y a nosotros solo nos interesa la contraseña, así que vamos a usar awk para filtrar únicamente por la contraseña

1
cat /usr/share/seclists/Passwords/Malware/mirai-botnet.txt

miraibotnet.png

1
cat /usr/share/seclists/Passwords/Malware/mirai-botnet.txt | awk '{print $2}' > mirai-botnet-pass.txt

miraibotnet-pass.png

Ahora tenemos el diccionario listo, para proceder necesitamos 2 archivos a los cuales tenemos acceso: /etc/passwd y /etc/shadow. Debemos guardar ambos en archivos de texto.

1
2
cat ./_IoTGoat-x86.img.extracted/squashfs-root/etc/passwd > passwd.txt
cat ./_IoTGoat-x86.img.extracted/squashfs-root/etc/shadow > shadow.txt

passwdtxt.png

shadowtxt.png

Una vez guardados vamos a usar una herramienta propia de John llamada unshadow para unir ambos archivos, este debe llevar un orden especifico, de lo contrario nos guardara mal el archivo. Primero va el passwd y luego el shadow.

1
sudo unshadow passwd.txt shadow.txt > unshadow.txt

unshadow.png

Una vez listo el archivo debe quedarnos así:

unshadowtxt.png

Ahora si procedemos a craquearlo con John usando la lista personalizada de contraseñas que creamos

1
sudo john -w=mirai-botnet-pass.txt unshadow.txt

pass-iotgoatuser.png

Obtenemos la contraseña para el usuario iotgoatuser.

Descifrando la contraseña root

El diccionario utilizado para descifrar las contraseñas no fue suficiente para la contraseña de root , así que descargué una herramienta llamada princeprocessor para generar contraseñas con diferentes palabras y utilicé el diccionario rockyou con la adición de la palabra iotgoat . Pero tarda bastante en generarlo y luego en crackearla la pass. Guía detallada que explica el uso de princeprocessor.

Para generar el diccionario empleamos la herramienta princeprocessor con el siguiente comando:

1
2
3
4
**./pp64.bin "rockyou.txt" --pw-min 8 --pw-max 24 > iot_list.txt** 

# pp64 ****generará combinaciones de las palabras (concatenaciones, repeticiones y permutaciones según su algoritmo).
# --pw-min/--pw-max incluyen la longitud de la contraseña objetivo mínima/máxima esperada), la concatenación aparecerá en el nuevo diccionario.

princeprocessor.png

Con la lista generada procedemos a obtener la clave del usuario root haciendo uso de John

1
2
sudo john -w=iot_list.txt ../unshadow.txt --format=md5crypt-long
# --format=md5crypt-long es el formato del hash del usuario root, de lo contrario no lo va a crackear, de igual manera john nos lo indica

pass-root.png

Obtenemos la contraseña para el usuario root.

Para fines prácticos y ya que esto lo usare en una demo una vez obtenida la pass decidí crear un diccionario con las palabras que contiene la contraseña y generar un diccionario mas pequeño con princeprocessor para ahorrar tiempo.

1
./pp64.bin mini-dic.txt --pw-min 8 --pw-max 24 > iot_list.txt

IoT-List.png

IoT-List2.png

2. Servicios de Red Inseguros (Insecure Network Services)

Servicios de red innecesarios o inseguros que se ejecutan en el propio dispositivo, especialmente aquellos expuestos a Internet, que comprometen la confidencialidad, integridad/autenticidad o disponibilidad de la información, o que permiten el control remoto no autorizado.

Primero, ejecutamos nmap para descubrir los diferentes puertos TCP abiertos. En esta ocasión no hacemos uso del típico escaneo rápido
nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn IP_Victim -oG scanP Ya que genera perdida de paquetes y no encuentra 3 puertos, el 5000, 5515 y el 65534

1
2
3
4
5
nmap -p- -sT 192.168.172.129 -vvv -oG scanP 
# -p- Para que escanee todo el rango de puertos disponible (65,535)
# -sT para indicarle que es un escaneo TCP
# -vvv Nos reporte por consola a medida nos vaya descubriendo cosas
# -oG Para guardar en formato Grep

open-ports.png

Empleamos una utilidad llamada extractPorts, que nos permite sacar la información mas relevante de la captura Grep de nmap y copiar los puertos directamente a la clipboard, por eso guardamos en ese formato, para poder aprovechar esta utilidad y agilizar nuestro trabajo. Fue hecha por s4vitar, Para usarla la deben incorporar en su .zshrc o .bashrc y instalar xclip.

1
2
3
4
5
# Instalar xclip
apt install xclip

# Uso de la herramienta
extractPorts scanP

extractPorts.png

Ahora hacemos un escaneo detallado para esos puertos encontrados

1
2
3
4
nmap -sCV -p22,53,80,443,5515,65534 192.168.172.129 -oN scanS
# -sCV Lanzamos scripts básicos de reconocimiento y detectamos versiones para esos servicios
# -p Indicamos los puertos
# -oN Guardamos en formato normal o nmap (tal como se muestra por consola)

scanS.png

scanS2.png

Encontramos varios servicios interesantes.

Como el servicio SSH esta abierto, probamos entrar con las credenciales obtenidas

1
ssh iotgoatuser@192.168.172.129

ssh-success.png

Nos conectamos con éxito.

Como dato extra en la carpeta SSHde nuestro usuario debemos crear un archivo de configuración llamado config que contenga las siguientes líneas:

1
2
Host 192.168.172.129
HostKeyAlgorithms +ssh-rsa

De esta manera podremos ingresar por SSHal IoTGoat, de lo contrario nos dará un error debido a que ese protocolo es considerado inseguro.

El puerto 53 suele estar vinculado a servicios DNS. En este caso, el análisis del puerto 53 arrojó el servicio utilizado: dnsmasq 2.73 He encontrado con searchsploity en internet que este servicio presenta múltiples vulnerabilidades críticas relacionadas con el envenenamiento de DNS y ataques DoS 

1
searchsploit dnsmasq 2.73

dnsmasq.png

dnsmasq2.png

Encontramos en el puerto80 HTTP una redirección al puerto 443 HTTPS , en el cual nos muestra una web

IoT-Web.png

Al parecer solo podemos ingresar con el usuario root, del cual ya tenemos credenciales, pero esto lo dejaremos para mas adelante, continuemos analizando los otros puertos.

Servicio desconocido (puerto 5515) parece haber una backdoor debido a la info que nos mostro nmap. Usaremos netcatpara tratar de conectarnos

1
nc nc 192.168.172.129 5515

backdoor.png

Obtenemos una shell como root

Telnetd (puerto 65534) Siguiendo el mismo procedimiento, Usamosnetcat para conectarnos al último puerto.

1
nc 192.168.172.129 65534

Telnet.png

Obtenemos una conexión. Este servicio es considerado obsoleto e inseguro debido a que toda la información que se transmite viaja en texto plano, incluyendo credenciales de acceso. Las cuales pueden ser interceptadas con un ataque MITM (Man In The Middle).

Vamos a interceptar el trafico con wireshark para ver las credenciales de acceso. Seleccionamos la interfaz de red y procedemos a capturar todo el trafico de red.

wireshark.png

wireshark2.png

Vemos que ahi entabla la conexión nuestra maquina con el IoTGoat en el cual nos iremos al ultimo paquete donde termina el 3-way handshake y analizar esa conexión.

Identificado ese paquete hacemos un seguimiento a la conexión que se establece por TCP y nos mostrara las credenciales en texto plano. Es por eso que no se debe usar Telnet.

wireshark3.png

3. Interfaces de ecosistema inseguras (Insecure Ecosystem Interfaces)

Interfaces web, API backend, nube o móviles inseguras, que permiten comprometer el dispositivo o sus componentes. Entre los problemas más comunes se incluyen la falta de autenticación/autorización, la falta o debilidad del cifrado y la falta de filtrado de entradas y salidas de texto.

Al revisar la estructura de datos, nos encontramos con un framework web MVC (Model-View-Controller) basado en Lua , el cual es usado para el portal web. Se revisaron manualmente varios archivos de configuración y no parecía haber mucha info interesante. decidí buscar por extension de archivos .lua .

Nos encontramos un archivo interesante el cual tiene el nombre del firmware en la siguiente ruta: /usr/lib/lua/luci/controller/iotgoat/iotgoat.lua

1
find . -name "*.lua"

IoT Goat-lua.png

Vemos la esturtura de archivos y al parecer se sirven desde esta ruta: /usr/lib/lua/luci

Revisamos el archivo iotgoat.lua y dentro vemos varias entradas interesantes, la que me llama la atención es cmdinject.

webui-controller.png

Decido buscar el archivo cmdinject

1
find . -name "cmd*"

find-cmd.png

Revisamos el archivo

1
cat ./usr/lib/lua/luci/view/iotgoat/cmd.htm

cmd-htm.png

Parece que nos da acceso a una “pagina secreta de diagnostico para desarrolladores”, la cual al observar su contenido, nos proporciona una webshell como el usuario root.

Nos dirigimos a esa ruta en la web para comprobar, recordemos que la ruta a la que se hace referencia en el iotgoat.lua es admin-iotgoat-cmdjinyect

secret-diagnostic-page.png

Obtenemos una webshell como el usuario root.

Mientras navegaba por la web, encontré múltiples entradas de texto e intenté realizar ataques XSS. En la siguientes parte de la aplicación pude realizar ataque XSS:

https://IoTGoat_IP/cgi-bin/luci/admin/network/firewall/rules En el campo name .

1
<script>alert("test");</script>

XSS1.png

Probe en otras entradas de texto pero no logre encontrar mas.

4. Actualizaciones Inseguras (Lack of Secure Update Mechanism)

Falta de capacidad para actualizar el dispositivo de forma segura. Esto incluye la falta de validación del firmware en el dispositivo, la falta de entrega segura (sin cifrar durante el tránsito), la falta de mecanismos anti-rollback y la falta de notificaciones de cambios de seguridad debidos a actualizaciones.

El firmware OpenWRT se puede actualizar o se le pueden instalar nuevos paquetes. En este paso, intenté encontrar diferentes CVE que afectaran a la seguridad del mecanismo de actualización. Durante la búsqueda, encontré múltiples vulnerabilidades críticas que afectan a OpenWRT.

La versión la podemos encontrar tanto en el github, también una vez ingresamos a la web nos muestra la versión y en la info del puerto 5000.

openWRT.png

openWrt-version.png

port5000.png

CVE’s encontrados en la siguiente pagina:

https://www.cvedetails.com/version/1306858/Openwrt-Openwrt-18.06.2.html

openWrt-vulns.png

Vemos que el CVE-2020-28951 afecta al mecanismo de actualización, ya que un nombre malicioso proporcionado puede provocar una vulnerabilidad «after free» que posteriormente puede explotarse para cargar código arbitrario en la memoria. Además, el mecanismo de copia de seguridad no comprueba la integridad de los archivos.

5. Transferencia y almacenamiento de datos inseguros (Insecure Data Transfer and Storage)

Falta de cifrado o control de acceso a datos confidenciales en cualquier parte del ecosistema, incluidos los datos en reposo, en tránsito o durante su procesamiento.

Al revisar el sistema de archivos y filtrar por diferentes tipos de extensión de archivo, la que mostro resultados fue .db con la cual encontré un archivo llamado sensordata.db . La cual era un archivo de base de datos SQLite.

1
find . -name "*db"

sensordata-db.png

Al revisar la base de datos vemos que los datos se almacenan sin cifrar y en texto plano.

1
2
3
4
5
#Para abrir la base de datos
sqlite3 ./squashfs-root/usr/lib/lua/luci/controller/iotgoat/sensordata.db

#Dumpeamos toda la info de la db
.dump

sensordata-dump.png

6. Configuraciones por defecto inseguras (Insecure Default Settings)

Dispositivos o sistemas con configuraciones predeterminadas inseguras, como contraseñas por defecto fáciles de adivinar, servicios innecesarios habilitados, puertos abiertos o funciones administrativas expuestas. Muchas veces, los fabricantes no permiten al usuario cambiar o reforzar esas configuraciones, lo que deja al dispositivo vulnerable desde el primer momento en que se conecta a la red.

Conclusiones

La máquina IoTGoat no pretende ser el típico CTF para escalar privilegios hasta root, sino más bien un laboratorio didáctico que concentra múltiples fallos típicos en dispositivos IoT. Durante el análisis he podido corroborar vulnerabilidades sencillas y a la vez muy comunes de la lista OWASP Top 10 IoT facilitan desde exposición de información sensible hasta ejecución remota de código; esto la convierte en una herramienta excelente para practicar detección, explotación y evaluación de riesgos en dispositivos IoT. Más allá de explotar fallos puntuales, el valor real de IoTGoat está en mostrar patrones repetibles: configuraciones inseguras, gestión deficiente de actualizaciones y fallas en el diseño de autenticación/autorización que deben corregirse en cualquier despliegue real y que estan presentes en muchos dispositivos IoT de uso cotidiano.

Metodología de pruebas de seguridad del firmware de OWASP (OWASP Firmware Security Testing Methodology)

Se ejecutó la metodología de pruebas de seguridad de firmware de OWASP (OWASP Firmware Security Testing Methodology) hasta el enunciado 7. Para cada etapa se aplicaron las pruebas y procedimientos recomendados (identificación, extracción y análisis del firmware, revisión estática y dinámicas controladas).

OWASP-security-testing2.png

OWASP-security-testing.png

¡Gracias por llegar hasta el final! Espero que este writeup te haya ayudado a comprender mejor las vulnerabilidades y técnicas que se emplean en dispositivos IoT, mediante este laboratorio de IoTGoat para que puedas aplicar lo aprendido en futuros escenarios.

Nos vemos en el próximo reto… ¡y recuerda, la mejor forma de aprender es practicando!

Happy Hacking!