Crypto Failures

Implementing your own military-grade encryption is usually not the best idea.

Recon

We start with a Nmap scan that reveals two open ports: port 22 (SSH)and port 80 (a web server).

Upon visiting the page, we find that we are logged in as a guest. The site mentions an SSO cookie, which is claimed to be secured using military-grade encryption.

We find the cookie as follows:

In the source code, we discover a comment stating that .bak files still need to be removed. Additionally, the word crypt is emphasized in bold.

We intercept a request to the index page using Burp and test if index.php can be accessed directly. The request is successful, and we receive the index page.

By requesting index.php.bak, we retrieve the source code of the index page, including the logic for generating the SSO cookie. Unfortunately, config.php is not available as a backup; otherwise, we might have gained access to the encryption key.

If the secure_cookie is not set, it is generated by generate_cookie(). The cookie follows the structure:

user:UserAgent:ENC_SECRET_KEY

This means we have control over the User-Agent parameter, but we'll explore that later.

The generate_cookie() function first calls generatesalt(), which creates a random 2-byte salt using an alphanumeric character set. This salt, along with the cookie string, is then passed to the make_secure_cookie function.

The make_secure_cookie() function applies the crypt() function to the provided cookie string in chunks of 8 characters, including the generated salt.

The verification process extracts the salt from the first two characters of the stored cookie using:

This extracted salt is then used to regenerate the secure cookie, which is compared against the provided one to verify its validity.

Once a valid cookie is verified, access is granted or denied based on the username. The username is determined by the user cookie. If the username is set to admin, a flag is displayed.

Initial Access

Since we can extract the salt from the hash and know that the crypt() function operates on 8-character chunks of the cookie string, impersonating the admin user becomes straightforward.

To do this:

  1. Extract the salt from the existing secure_cookie.

  2. Compute the hash of admin: using the same salt.

  3. Replace the first hashed chunk of the cookie with this new hash.

  4. Set the user cookie to admin.

This allows us to bypass authentication and access the flag.

Next, we replace the secure_cookie with our forged one and set the user cookie to admin. After reloading the page, we successfully log in as admin and retrieve the first flag.

Obtaining The Encryption Key

To extract the secret key, we take advantage of our control over the User-Agent and the fact that the hash operates in 8-character chunks.

Problem with Bruteforcing the Entire Key

  • The full brute-force approach would require 65⁸ permutations per chunk, which is infeasible.

  • Instead, we reduce the unknown portion to a single byte at a time.

Exploiting Controlled Input

  1. Since we control User-Agent, we craft a cookie string where we already know 7 out of 8 bytes in a chunk.

  2. We then brute-force the remaining single byte until we find a match in the generated secure_cookie.

  3. When the resulting hash appears in the secure_cookie, we know that the unknown byte is part of the secret key.

Step-by-Step Process

  1. Craft the attack string using User-Agent padding:

    • Example: guest:AAAAAAAAAA:_

    • Chunk A: guest:AA (first 8-character block)

    • Chunk B: AAAAAA:_ (7 known bytes + 1 unknown character from the key)

  2. Brute-force the unknown character:

    • Generate hashes for all possible last bytes (_ in Chunk B).

    • When a hash matches the corresponding chunk in the cookie, we recover that byte of the key.

  3. Iterate and reduce padding:

    • Use the previously found characters to refine the attack.

    • Slowly reveal the entire key by repeating the process with adjusted padding.

By continuously reducing the padding and updating our test string, we fully recover the secret key.

Unfortunately, the script crashes after running for some time.

Since we know the length of the leaked string and have the last 8 characters, we modify our script to resume from that point.

We combine both extracted parts, reconstructing the full key, and retrieve the final flag.

Last updated

Was this helpful?