Emdee five for life
The site serves a random string inside an
and demands its MD5 back before it expires, tied to the same session cookie. Solving it by hand is impossible — the real skill being tested is turning the whole read → hash → resend cycle into one reliable curl script.
Challenge overview
| Field | Value |
|---|---|
| Platform | Hack The Box · Challenge |
| Category | Misc |
| Difficulty | Very Easy |
| State | Retired |
Attack map
[Web] random string in <h3>
│
▼
[curl -c] read string + cookie
│
▼
[grep+sed] isolate the exact value
│
▼
[md5sum -n] hash without newline
│
▼
[cut -d' '] clean the output
│
▼
[curl -b POST hash] same session
│
▼
[FLAG]La web sirve un string aleatorio dentro de un
y exige devolver su MD5 antes de que expire, atado a la misma cookie de sesión. Resolverlo a mano es imposible: la habilidad real que se pone a prueba es convertir todo el ciclo leer → calcular hash → reenviar en un único script fiable con curl.
Ficha del challenge
| Campo | Valor |
|---|---|
| Plataforma | Hack The Box · Challenge |
| Categoría | Misc |
| Dificultad | Very Easy |
| Estado | Retirado |
Mapa del ataque
[Web] string aleatorio en <h3>
│
▼
[curl -c] leer string + cookie
│
▼
[grep+sed] aislar el valor exacto
│
▼
[md5sum -n] hash sin salto de línea
│
▼
[cut -d' '] limpiar la salida
│
▼
[curl -b POST hash] misma sesión
│
▼
[FLAG]
1. Understand the objective
The app plainly asks to "MD5 encrypt this string" and enforces a timeout: read the displayed string, compute its MD5, and POST it back before it expires, all inside the correct session. The real difficulty isn't the algorithm — MD5 is trivial — it's automating the whole read → hash → send cycle inside the window the server allows.
2. Observe the changing value
Opening the page by hand shows a different string on every load, embedded inside an
. Trying to solve it manually — read it, compute the MD5 in another terminal, copy-paste the answer back — always arrives too late: the server has already rotated the value and the session has expired.
<h3 align='center'>RlH5U3VxEdOk7QUH2t9L</h3>That fragment is exactly what needs to be isolated from the page's full HTML — no forms, headers or styling, just the content between the
tags.
3. Enumerate the page with curl
Before writing any automation we need to confirm precisely what the server returns and expects: the exact name of the form field, and the exact tag the string travels in. A script that guesses the parameter name will fail every single request.
curl -s http://TARGETThe response is a small HTML page: a POST form with a single field named hash, and the random string sitting inside an
. Both details feed the rest of the script — the parameter name for the final submission, and the tag to extract the value from.
4. Extract the string and keep the session
The server validates the answer against the same session that served the string, so we save the cookie on the first request with-cand resend it on the final POST with-b.grepisolates the line containing theh3tag;sedextracts just the content between the tags with a capture group, using-nplus thepflag to print only the substituted line.
curl -s -c cookies.txt http://TARGET | grep h3sed -n "s:.*<h3 align='center'>\(.*\)</h3>.*:\1:p"Using : instead of / as the sed delimiter avoids escaping any slashes that might show up in the HTML; \1 references the captured group in parentheses — the string itself.
5. The newline trap
Here's the point that breaks most attempts:echoappends a newline that changes the resulting hash. Useecho -nso it isn't included.
# wrong: echo TEXT | md5sum
# right: echo -n TEXT | md5sumMD5 operates byte for byte: one extra character — the \n that echo appends by default — produces a completely different hash than the one the server expects. -n suppresses that trailing newline.
6. Clean up md5sum's output and submit
md5sumdoesn't return just the hash: it prints<hash> -when reading from stdin (the dash marks standard input as the "file"). We need to keep only the first field before sending it, or the server will receive garbage alongside the hash.
echo -n "$HASH" | md5sum | cut -d' ' -f1curl -s -X POST -b cookies.txt -d "hash=$MD5" http://TARGETcut -d' ' -f1 splits on the first space and keeps field 1: the clean hash, ready to travel as the value of the hash parameter in the POST.
7. Assemble the full script
IP="http://TARGET"
HASH=$(curl -s -c cookies.txt $IP | grep h3 | sed -n "s:.*<h3 align='center'>\(.*\)</h3>.*:\1:p")
MD5=$(echo -n "$HASH" | md5sum | cut -d' ' -f1)
curl -s -X POST -b cookies.txt -d "hash=$MD5" $IPEvery line reuses exactly what was validated in the previous steps: the saved cookie, the string extracted with grep+sed, the hash computed without a newline and trimmed with cut, and the resend using the same cookie. Nothing runs by hand, so there's no dead time for the session to expire in.
8. Run it and read the flag
Running the full script takes well under a second, so the session is still valid when the POST arrives: the server compares the received hash against the real MD5 of the string it served and, on a match, returns the flag straight in the response.
bash solve.shHTB{...}Chain summary
| Phase | Component | Vulnerability | Impact |
|---|---|---|---|
| Recon | HTML response (form + <h3>) | Predictable, time-boxed value | Confirms full automation is required |
| Extraction | curl -c + grep + sed | Session-bound random string | Exact value captured under the right cookie |
| Hashing | echo -n + md5sum | Trailing newline changes the hash | Correct MD5 of the exact string |
| Output parsing | cut -d' ' -f1 | md5sum's "hash -" format | Clean hash value for the POST body |
| Submission | curl -b -X POST | Answer tied to the session cookie | Valid hash accepted → flag returned |
Lessons learned
echo -navoids the newline that ruins a hash — a detail that trips up many first-time solvers.- When a challenge validates per session, you must persist cookies (
-c/-b) between the GET request and the final POST. sedwith a capture group lets you pull exact text out of raw HTML without reaching for a full parser.md5sum's output format ("hash -" or "hash file") almost always needscutorawkbefore it can be compared or sent anywhere.- Timeout challenges don't really test the hash itself — they test whether you can script the entire flow end-to-end with no manual steps.
1. Entender el objetivo
La aplicación pide literalmente "MD5 encrypt this string" y castiga con un timeout: hay que leer el string mostrado, calcular su MD5 y enviarlo por POST antes de que expire, manteniendo la sesión correcta. La dificultad no está en el algoritmo — MD5 es trivial — sino en automatizar el ciclo completo lectura → hash → envío dentro del margen que da el servidor.
2. Observar el valor cambiante
Al abrir la página a mano se ve un string distinto en cada carga, incrustado en un
. Si se intenta resolver manualmente —leerlo, calcular el MD5 en otra terminal, copiar y pegar la respuesta— siempre se llega tarde: el servidor ya ha rotado el valor y la sesión ha expirado.
<h3 align='center'>RlH5U3VxEdOk7QUH2t9L</h3>Ese fragmento es justo lo que hay que aislar del HTML completo de la página: nada de formularios, cabeceras ni estilos, solo el contenido entre las etiquetas
.
3. Enumerar la página con curl
Antes de escribir cualquier automatización hay que confirmar con precisión qué devuelve el servidor y qué espera recibir: cómo se llama el campo del formulario y en qué etiqueta exacta viaja el string. Un script que adivine el nombre del parámetro fallará todas las peticiones.
curl -s http://TARGETLa respuesta es una página HTML pequeña: un formulario POST con un único campo llamado hash, y el string aleatorio dentro de un
. Ambos detalles alimentan el resto del script: el nombre del parámetro para el envío final y la etiqueta para extraer el valor.
4. Extraer el string y conservar la sesión
El servidor valida la respuesta contra la misma sesión que sirvió el string, así que hay que guardar la cookie en la primera petición con-cy reenviarla en el POST final con-b.grepaísla la línea con la etiquetah3;sedextrae solo el contenido entre las etiquetas con un grupo de captura, usando-nmás el flagppara imprimir únicamente la línea sustituida.
curl -s -c cookies.txt http://TARGET | grep h3sed -n "s:.*<h3 align='center'>\(.*\)</h3>.*:\1:p"Usar : en vez de / como delimitador de sed evita tener que escapar barras que puedan aparecer en el HTML; \1 referencia el grupo capturado entre paréntesis, es decir, el string en sí.
5. La trampa del salto de línea
Aquí está el punto que rompe la mayoría de intentos:echoañade un salto de línea que cambia el hash resultante. Hay que usarecho -npara no incluirlo.
# wrong: echo TEXT | md5sum
# right: echo -n TEXT | md5sumMD5 opera byte a byte: un carácter de más —el \n que echo añade por defecto— produce un hash completamente distinto al que el servidor espera. -n suprime ese salto de línea final.
6. Limpiar la salida de md5sum y enviar
md5sumno devuelve solo el hash: imprime<hash> -cuando lee de la entrada estándar (el guion marca stdin como "archivo"). Hay que quedarse solo con el primer campo antes de enviarlo, o el servidor recibirá basura además del hash.
echo -n "$HASH" | md5sum | cut -d' ' -f1curl -s -X POST -b cookies.txt -d "hash=$MD5" http://TARGETcut -d' ' -f1 corta por el primer espacio y se queda con el campo 1: el hash limpio, listo para viajar como valor del parámetro hash en el POST.
7. Ensamblar el script completo
IP="http://TARGET"
HASH=$(curl -s -c cookies.txt $IP | grep h3 | sed -n "s:.*<h3 align='center'>\(.*\)</h3>.*:\1:p")
MD5=$(echo -n "$HASH" | md5sum | cut -d' ' -f1)
curl -s -X POST -b cookies.txt -d "hash=$MD5" $IPCada línea reutiliza exactamente lo validado en los pasos anteriores: cookie guardada, string extraído con grep+sed, hash calculado sin salto de línea y recortado con cut, y reenvío con la misma cookie. Nada se ejecuta a mano, así que no hay tiempo muerto en el que la sesión pueda expirar.
8. Ejecutar y leer la flag
Al ejecutar el script completo en menos de un segundo, la sesión sigue siendo válida cuando llega el POST: el servidor compara el hash recibido con el MD5 real del string que sirvió y, si coincide, devuelve la flag directamente en la respuesta.
bash solve.shHTB{...}Resumen de la cadena
| Fase | Componente | Vulnerabilidad | Impacto |
|---|---|---|---|
| Recon | Respuesta HTML (formulario + <h3>) | Valor predecible y acotado en el tiempo | Confirma que se necesita automatización completa |
| Extracción | curl -c + grep + sed | String atado a la sesión | Valor exacto capturado bajo la cookie correcta |
| Cálculo del hash | echo -n + md5sum | El salto de línea cambia el hash | MD5 correcto del string exacto |
| Limpieza de salida | cut -d' ' -f1 | Formato "hash -" de md5sum | Valor de hash limpio para el POST |
| Envío | curl -b -X POST | Respuesta atada a la cookie de sesión | Hash válido aceptado → flag devuelta |
Lecciones aprendidas
echo -nevita el salto de línea que arruina un hash: un detalle que rompe muchos solvers primerizos.- Cuando un reto valida por sesión, hay que persistir las cookies (
-c/-b) entre la petición GET y el POST final. sedcon un grupo de captura permite extraer texto exacto de HTML crudo sin recurrir a un parser completo.- El formato de salida de
md5sum("hash -" o "hash archivo") casi siempre necesitacutoawkantes de poder compararse o enviarse. - Los retos con timeout no miden el hash en sí, miden tu capacidad de scriptar el flujo completo end-to-end sin intervención manual.