Entrada

Mirai

Linux Easy en la que un Pi-hole delata que debajo hay una Raspberry Pi: las credenciales de fábrica (pi/raspberry) abren el SSH y un sudo sin contraseña regala root al instante. Lo bueno llega después, con una root.txt borrada de un USB que hay que recuperar leyendo el dispositivo en bruto.

Mirai

Publicado por Jaime Hereza Niño

Publicado 14/10/2026
9 min de lectura
Mi puntuación
28729 votos
MáquinaSODificultadIP
MiraiLinuxEasy10.129.83.244

A tener en cuenta...

┌──(jaime㉿kali)-[~]└─$ sudo nano /etc/hosts
10.129.83.244 mirai

Resumen

Mirai, de la mitad para abajo, es tan corta como Jerry. Hay un Pi-hole corriendo sobre una Raspberry Pi, la Raspberry conserva el usuario y la contraseña que trae de fábrica, y ese usuario puede ejecutar cualquier cosa con sudo sin que le pidan contraseña. Entre abrir la sesión por SSH y ser root pasa menos de medio minuto.

Lo que la hace memorable es la otra mitad. Al ir a leer /root/root.txt no hay flag: hay una nota diciendo que el fichero original se perdió y que quizá haya una copia en un USB. Y en el USB tampoco está, porque alguien la borró.

A partir de ahí la máquina deja de ir de pentesting y se convierte en un ejercicio de análisis forense: hay que entender qué le pasa de verdad a un fichero cuando se borra y leer el dispositivo por debajo del sistema de ficheros para recuperarlo.

Es la primera máquina en la que he tenido que pelearme con puntos de montaje, discos en bruto y un dispositivo que se niega a desmontarse, y de la que he salido sabiendo cosas que no tenían nada que ver con explotar un servicio.

Vulnerabilidad

Aquí tampoco hay ningún CVE. Hay tres descuidos de configuración encadenados y, al final, un cuarto problema que no es culpa del administrador sino de cómo funcionan los discos.

01 · La Raspberry conserva las credenciales de fábrica

Las imágenes clásicas de Raspbian se entregan con un único usuario, pi, con la contraseña raspberry, y con el servicio SSH aceptando esa pareja. La instalación asume que lo primero que hará quien la monte es cambiarla. Aquí no se cambió, así que entrar no es ni fuerza bruta: es escribir la contraseña que viene en la documentación.

02 · El usuario pi puede usar sudo sin contraseña

Esto también viene de serie en Raspbian: el usuario pi está en el sudoers con NOPASSWD: ALL, pensando en que una Raspberry de escritorio no debe estorbar a su dueño. El efecto práctico es que no existe escalada de privilegios: quien consigue la sesión de pi ya tiene root, solo tiene que pedirlo.

03 · El panel de Pi-hole está publicado sin autenticación

El dashboard de administración responde en /admin a cualquiera que pase por el puerto 80, sin pedir nada. No es la vía de entrada de esta máquina, pero sí es lo que delata qué tenemos delante: un Pi-hole implica casi siempre una Raspberry Pi, y una Raspberry Pi implica unas credenciales por defecto que probar.

04 · Los datos borrados siguen estando en el disco

Este último no es un fallo de configuración, es cómo funciona cualquier sistema de ficheros. Borrar un fichero no borra sus bytes: el sistema se limita a quitar la entrada que apuntaba a ellos y a marcar esos bloques como libres. El contenido sigue físicamente donde estaba hasta que algo lo pise.

Por eso un borrado no es una forma de proteger nada. Quien tenga acceso al dispositivo en bruto, por debajo del sistema de ficheros, puede seguir leyendo lo que supuestamente ya no existe.

Reconocimiento

Barrido completo de puertos contra la víctima, con detección de sistema operativo

┌──(jaime㉿kali)-[~]└─$ sudo nmap -p- -n -Pn -sS --max-retries 1 -O -osscan-guess mirai
PuertoServicio
22ssh
53domain
80http
1982estamp
32400plex
32469unknown

Seis puertos abiertos, que para una máquina Easy ya es bastante superficie. El reparto es llamativo: 65.463 puertos cerrados (responden con un reset) y solo 66 filtrados. Es justo lo contrario de lo que pasaba en Jerry, donde un cortafuegos tragaba todo en silencio; aquí la máquina contesta a todo, así que no hay nada bloqueando el tráfico.

El fingerprinting apunta a un Linux con kernel 3.10 – 4.11, y los puertos ya cuentan media historia por sí solos: el 53 abierto significa que esto sirve DNS, y el 32400 es el puerto de siempre de Plex. Un DNS propio y un servidor multimedia doméstico en la misma caja huele a aparato de casa, no a servidor.

Escaneo completo de puertos
Figura 1: Escaneo completo de puertos

Enumeración

Enumeración de versiones sobre los seis puertos, con la intensidad al máximo

┌──(jaime㉿kali)-[~]└─$ sudo nmap -p 22,53,80,1982,32400,32469 -sCV --version-intensity 9 -n mirai
22/tcp open ssh OpenSSH 6.7p1 Debian 5+deb8u3 (protocol 2.0) 53/tcp open domain dnsmasq 2.76 80/tcp open http lighttpd 1.4.35 |_http-title: Website Blocked 1982/tcp open upnp Platinum UPnP 1.0.5.13 (UPnP/1.0 DLNADOC/1.50) 32400/tcp open http Plex Media Server httpd 32469/tcp open upnp Platinum UPnP 1.0.5.13 (UPnP/1.0 DLNADOC/1.50)
Enumeración de versiones de los servicios
Figura 2: Enumeración de versiones de los servicios

Cada línea suma una pieza al retrato. El OpenSSH 6.7p1 Debian 5+deb8u3 sitúa el sistema en Debian 8 (jessie), que es la base sobre la que se construía Raspbian de esa época. El dnsmasq del puerto 53 es el servidor DNS ligero que usan los routers y los aparatos pequeños. Y los dos UPnP más el Plex confirman que esto es un trasto doméstico conectado a la tele.

Pero lo que de verdad importa está en el puerto 80. El título de la página es Website Blocked: no es un servidor web que sirva un sitio, es un servidor web que sirve bloqueos. Lo confirmo con whatweb

┌──(jaime㉿kali)-[~]└─$ whatweb http://mirai
http://mirai [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[lighttpd/1.4.35], IP[10.129.83.244], JQuery, PasswordField[pw], Script, Title[Website Blocked], UncommonHeaders[x-pi-hole], lighttpd[1.4.35]
Tecnologías detectadas en el servidor
Figura 3: Tecnologías detectadas en el servidor

Ahí está la confirmación, y viene regalada: la cabecera x-pi-hole. El servidor se identifica solo. Esto es un Pi-hole, el bloqueador de publicidad que se instala en una Raspberry Pi y que hace de DNS para toda la casa — lo cual explica de paso el dnsmasq del puerto 53, porque Pi-hole se apoya precisamente en él.

Pi-hole publica su panel de administración en una ruta fija, así que la pruebo

http://mirai/admin/index.php

Dashboard de Pi-hole accesible sin credenciales
Figura 4: Dashboard de Pi-hole accesible sin credenciales

El dashboard entero, sin pedir nada. No hace falta ni tocarlo: lo que acabo de ganar no es acceso al panel, es la certeza de que debajo hay una Raspberry Pi. Y eso cambia por completo la siguiente pregunta, que ya no es «qué exploit tiene esta versión» sino «¿habrán cambiado la contraseña de fábrica?».

Explotación

Con un Pi-hole identificado, lo barato es probar antes de complicarse. Toda imagen de Raspbian se entrega con las mismas credenciales, y el puerto 22 está abierto

usuario: pi
contraseña: raspberry

┌──(jaime㉿kali)-[~]└─$ ssh pi@mirai

Y entra a la primera. Ni fuerza bruta, ni diccionario, ni un solo intento fallido: la contraseña estaba publicada en la documentación del fabricante.

El prompt lo confirma sin disimulo — pi@raspberrypi — y la flag de usuario está donde más a mano queda, en el escritorio

┌──(jaime㉿kali)-[~]└─$ cd Desktop
┌──(jaime㉿kali)-[~]└─$ ls
┌──(jaime㉿kali)-[~]└─$ cat user.txt
Sesión abierta como pi y flag de usuario
Figura 5: Sesión abierta como pi y flag de usuario

Toda la explotación de esta máquina cabe en una línea. Lo interesante empieza ahora.

Escalada de privilegios

Lo primero al aterrizar en un Linux es mirar qué puede hacer el usuario con sudo

┌──(jaime㉿kali)-[~]└─$ sudo -l
User pi may run the following commands on localhost: (ALL : ALL) ALL (ALL) NOPASSWD: ALL
El usuario pi puede ejecutar cualquier cosa sin contraseña
Figura 6: El usuario pi puede ejecutar cualquier cosa sin contraseña

(ALL) NOPASSWD: ALL. Cualquier comando, como cualquier usuario, sin que le pidan la contraseña. Esto no es una escalada de privilegios, es un cambio de sombrero

┌──(jaime㉿kali)-[~]└─$ sudo bash
┌──(jaime㉿kali)-[~]└─$ whoami
root
Sesión como root
Figura 7: Sesión como root

Y ahí es donde la máquina se pone interesante, porque al ir a por la flag no hay flag

┌──(jaime㉿kali)-[~]└─$ cat /root/root.txt
I lost my original root.txt! I think I may have a backup on my USB stick...
La flag de root no está donde debería
Figura 8: La flag de root no está donde debería

Un USB. Toca mirar qué hay enchufado a este aparato, así que lo primero es ver todo lo que tiene montado el sistema

┌──(jaime㉿kali)-[~]└─$ mount
Sistemas de ficheros montados
Figura 9: Sistemas de ficheros montados
┌──(jaime㉿kali)-[~]└─$ df -h
Filesystem Size Used Avail Use% Mounted on /dev/sdb 8.7M 93K 7.9M 2% /media/usbstick
El USB montado enmedia/usbstick
Figura 10: El USB montado en /media/usbstick

df -h da la misma información que mount pero legible de un vistazo, y ahí aparece lo que buscaba: /dev/sdb, de ocho megas y medio, montado en /media/usbstick. Ese tamaño ridículo ya canta que es el pendrive de la historia y no un disco del sistema.

Confirmo la topología de discos con lsblk, que los dibuja como un árbol

┌──(jaime㉿kali)-[~]└─$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 10G 0 disk |-sda1 8:1 0 1.3G 0 part /mnt |-sda2 8:2 0 8.7G 0 part /lib/live/mount/persistence/sda2 sdb 8:16 0 10M 0 disk /media/usbstick
El dispositivo físico del USB esdev/sdb
Figura 11: El dispositivo físico del USB es /dev/sdb

Esto es lo que necesitaba separar bien, porque son dos cosas distintas que es fácil confundir: /media/usbstick es el punto de montaje, la carpeta por la que el sistema me deja ver el contenido; /dev/sdb es el dispositivo, el bloque de bytes de verdad. Van a hacer falta los dos.

Entro al punto de montaje a ver qué quedó

┌──(jaime㉿kali)-[~]└─$ cd /media/usbstick
┌──(jaime㉿kali)-[~]└─$ ls
┌──(jaime㉿kali)-[~]└─$ cat damnit.txt
Damnit! Sorry man I accidentally deleted your files off the USB stick. Do you know if there is any way to get them back? -James
La nota que explica dónde fue a parar la flag
Figura 12: La nota que explica dónde fue a parar la flag

El USB está vacío salvo por la nota y un lost+found. James borró la flag.

Y aquí está la idea que sostiene el resto de la máquina: borrar un fichero no borra su contenido. Cuando se elimina algo, el sistema de ficheros no pasa por encima de los bytes escribiendo ceros — eso sería lentísimo. Lo que hace es quitar la entrada que apuntaba a ese fichero y marcar los bloques que ocupaba como disponibles. Los datos siguen físicamente ahí, intactos, hasta que una escritura futura los pise.

Así que la flag no se ha ido a ninguna parte. Simplemente ya no hay nada que apunte a ella. Y si el sistema de ficheros ya no sabe encontrarla, hay que bajar un nivel y leer /dev/sdb directamente.

El procedimiento ortodoxo sería desmontar primero, para garantizar que nadie escriba en el dispositivo mientras lo analizo y acabe pisando justo lo que quiero recuperar

┌──(jaime㉿kali)-[~]└─$ umount /media/usbstick
umount: /media/usbstick: target is busy
El dispositivo está ocupado y no se deja desmontar
Figura 13: El dispositivo está ocupado y no se deja desmontar

Al principio pensé que el culpable era yo por estar dentro de la carpeta, pero salgo a / y sigue dando lo mismo: hay un proceso del sistema con el dispositivo cogido. Para desmontarlo de verdad habría que localizarlo con lsof o fuser y cerrarlo, y entonces sí pasarle una herramienta de recuperación como photorec, que reconstruye ficheros borrados buscando sus firmas de cabecera.

┌──(jaime㉿kali)-[~]└─$ sudo photorec /dev/sdb

Pero para lo que necesito aquí, todo eso sobra. Yo no quiero reconstruir un fichero: quiero leer 32 caracteres. Y para eso puedo leer el dispositivo en bruto sin desmontar nada.

Flags

La flag de usuario estaba a la vista en el escritorio de pi

┌──(jaime㉿kali)-[~]└─$ cat /home/pi/Desktop/user.txt
ff837707441b257a20e32199d7c8838d

La de root hay que sacarla del USB. strings recorre un fichero binario — y un dispositivo de bloques es un fichero binario — y escupe todas las secuencias de caracteres imprimibles que encuentra. Empiezo buscando a ciegas

┌──(jaime㉿kali)-[~]└─$ strings /dev/sdb | grep -i root
root.txt root.txt root.txt

Aparece el nombre del fichero tres veces, pero no su contenido. Es exactamente lo que cabía esperar: el nombre vive en los metadatos del sistema de ficheros y el contenido está en otro sitio del disco, en bloques que ahora figuran como libres. Están cerca, pero no pegados.

La solución es pedirle a grep que, además de la coincidencia, me enseñe el vecindario: cinco líneas por arriba y cinco por abajo

┌──(jaime㉿kali)-[~]└─$ sudo strings /dev/sdb | grep -i -A5 -B5 root.txt
/media/usbstick lost+found root.txt damnit.txt >r & 3d3e483143ff12ec505d026fa13e020b Damnit! Sorry man I accidentally deleted your files off the USB stick.
La flag de root recuperada del dispositivo en bruto
Figura 14: La flag de root recuperada del dispositivo en bruto

Ahí está, entre los restos de las entradas del directorio y el texto de la nota de James: 3d3e483143ff12ec505d026fa13e020b. Treinta y dos caracteres que llevaban todo este rato en el disco, sin nadie que supiera dónde estaban.

Otras maneras de llegar a lo mismo

  • Volcar el dispositivo entero y mirarlo a ojo: con un USB de 10 MB el strings /dev/sdb a pelo cabe en una pantalla y la flag se ve sin filtrar nada. Funciona aquí y no funcionará casi nunca: con un disco de verdad son millones de líneas.
┌──(jaime㉿kali)-[~]└─$ sudo strings /dev/sdb
Volcado completo del dispositivo
Figura 15: Volcado completo del dispositivo
  • Guardar el volcado y analizarlo con calma: lo mismo, pero a un fichero, para poder buscar dentro las veces que haga falta sin releer el disco cada vez. Es lo razonable cuando el volcado es grande o cuando no sabes aún qué estás buscando.
┌──(jaime㉿kali)-[~]└─$ sudo strings /dev/sdb > /tmp/dump.txt
┌──(jaime㉿kali)-[~]└─$ cat /tmp/dump.txt
El volcado guardado en un fichero para analizarlo
Figura 16: El volcado guardado en un fichero para analizarlo
  • Recuperar los ficheros de verdad con photorec: es la herramienta correcta si lo que quieres es el fichero entero y no un trozo de texto. El inconveniente es práctico: casi ningún equipo comprometido la tiene instalada, y rara vez vas a poder instalar nada.

Cómo se arregla

Nada que parchear otra vez: todo es configuración, y cualquiera de las dos primeras medidas por separado habría cerrado la máquina.

  • Cambiar las credenciales de fábrica: pi/raspberry es, probablemente, la pareja usuario-contraseña más conocida del mundo. Es lo primero que se hace al montar una Raspberry, antes de conectarla a nada. Las versiones modernas de Raspberry Pi OS ya obligan a crear un usuario propio precisamente por esto.
  • No permitir autenticación por contraseña en SSH: con PasswordAuthentication no y claves públicas, una contraseña filtrada deja de servir para entrar. Y si el servicio no necesita estar expuesto, mejor que no escuche a toda la red.
  • Quitar el NOPASSWD del sudoers: que pi pueda hacerlo todo sin contraseña convierte cualquier acceso en acceso root. Pedir la contraseña no es una barrera infranqueable, pero obliga al atacante a tenerla y deja rastro en los registros.
  • Proteger el panel de Pi-hole: el dashboard contaba qué era la máquina sin pedir credenciales. Debería estar detrás de su contraseña de administración y, a poder ser, accesible solo desde la red interna.
  • Borrar de verdad lo que se borra: esta es la lección de la segunda mitad. Un rm no destruye nada. Si en un medio extraíble hubo algo sensible, hay que sobrescribirlo (shred, o rellenar el espacio libre) o, mejor aún, cifrar el dispositivo desde el principio: en un USB cifrado los bloques huérfanos no son texto recuperable, son ruido.

Conclusiones

Me ha encantado esta máquina, y no por la parte de explotación — esa es un trámite: credenciales por defecto y un sudo sin contraseña. Me ha encantado por lo que viene después.

Hasta Mirai no había tenido que preocuparme nunca de cómo se monta y se desmonta un dispositivo, de dónde aparecen los USB físicos dentro del sistema, ni de la diferencia entre el punto de montaje y el dispositivo de bloques que hay detrás. Son cosas que suenan a administración de sistemas y no a seguridad, hasta que te hacen falta.

Y luego está la idea de fondo, que es la que me llevo: borrar no es destruir. Un fichero eliminado sigue entero en el disco hasta que algo lo pise, y basta con leer por debajo del sistema de ficheros para sacarlo. Visto desde el lado ofensivo es una vía de acceso a información que alguien dio por perdida; visto desde el defensivo, es la razón por la que un disco que se tira a la basura hay que borrarlo a conciencia o cifrarlo.

Es la primera vez que una máquina me ha hecho mirar hacia el trabajo de los analistas forenses, y he acabado entendiendo bastante mejor a qué se dedican.

Esta entrada está licenciada bajo CC BY 4.0 por el autor.