root@thehacksparrow:~/writeups$ SYSTEM ONLINE
root@sparrow:~/writeups$ cat emdee-five-for-life.md
// writeups

Emdee five for life

21 May 2019 · 8 min read
Emdee five for life — HTB challenge
The site serves a random string inside an

Challenge overview

FieldValue
PlatformHack The Box · Challenge
CategoryMisc
DifficultyVery Easy
StateRetired

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]

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://TARGET

The 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 -c and resend it on the final POST with -b. grep isolates the line containing the h3 tag; sed extracts just the content between the tags with a capture group, using -n plus the p flag to print only the substituted line.
curl -s -c cookies.txt http://TARGET | grep h3
sed -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: echo appends a newline that changes the resulting hash. Use echo -n so it isn't included.
# wrong:  echo TEXT | md5sum
# right:  echo -n TEXT | md5sum

MD5 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

md5sum doesn'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' ' -f1
curl -s -X POST -b cookies.txt -d "hash=$MD5" http://TARGET

cut -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" $IP

Every 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.sh
HTB{...}

Chain summary

PhaseComponentVulnerabilityImpact
ReconHTML response (form + <h3>)Predictable, time-boxed valueConfirms full automation is required
Extractioncurl -c + grep + sedSession-bound random stringExact value captured under the right cookie
Hashingecho -n + md5sumTrailing newline changes the hashCorrect MD5 of the exact string
Output parsingcut -d' ' -f1md5sum's "hash -" formatClean hash value for the POST body
Submissioncurl -b -X POSTAnswer tied to the session cookieValid hash accepted → flag returned