Skip to main content
  1. CaptureTheFlags/

Entropy Overload — Bcrypt Length Limits in 'Entropyyyy…' (1753 CTF 2025)

·494 words·3 mins
CTF Writeups Web Exploitation Crypto 1753 CTF Bcrypt PHP Authentication Bypass Crypto Logic Password Hashing
Vaishnav Baraskar
Author
Vaishnav Baraskar
Penetration Tester @ Freelancer

Prologue — The Noise is the Signal
#

Some challenges are loud — stack traces, debug logs, binary dumps. This one wasn’t.

All I had was a login box. The title said “Entropyyyy…”, like it was mocking me. So I did what anyone would do: tried admin : admin and watched it reject me silently.

But it wasn’t silence. It was a setup.


Stage 1 — Observing the Login Logic
#

The backend source was partially provided, and it boiled down to this:

$password_hash = password_hash($entropy . $username . $password, PASSWORD_BCRYPT);

My initial thought was: okay, they’re salting with some giant entropy blob. Classic CTF noise. But there was something more subtle happening.

When I triggered the login form and watched the hash generation delay, I got curious.


Stage 2 — PHP Bcrypt Behavior
#

Digging into PHP’s bcrypt implementation led me to the 72-byte rule.

Bcrypt only considers the first 72 bytes of the input string when hashing.

Anything beyond that? Discarded. Ignored. Doesn’t matter.

Now let’s do the math:

$input = $entropy . $username . $password;

If $entropy . $username was already longer than 72 bytes — and it was — then $password didn’t even make it into the hash. Unless it started right at the cutoff point.

That meant: only the first character of the password had any effect. The rest? Dead weight.


Stage 3 — Reproducing It
#

Here’s how I tested the cutoff locally:

$entropy = str_repeat('A', 64);
$username = "admin";
$password = "Zpassword";

$combined = $entropy . $username . $password;
$hash = password_hash($combined, PASSWORD_BCRYPT);

echo $hash;

Now I tried changing everything after the "Z":

$password = "Zabc";

Same hash.

But if I changed "Z" to "B", hash changed.

It was clear: only the first character of the password matters.


Stage 4 — Brute-Forcing the First Character
#

So the logic turned into a simple loop:

import requests

url = "https://entropyyy.1753ctf.live/login"
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+"

for c in charset:
    password = c + "junk"
    data = {
        "username": "admin",
        "password": password
    }
    r = requests.post(url, data=data)
    if "Welcome" in r.text:
        print("Found:", password)
        break

And yeah — after a few tries:

Found: Bjunk

The server authenticated. The flag popped into view.


Result
#

1753CTF{php_bcrypt_cut_me_short_lol}

All that entropy. All that prepending. And it was the first byte of user input that mattered.


Reflection — Crypto, But Not Really
#

This wasn’t a cryptography challenge in the traditional sense. No AES, no RSA padding issues.

It was about implementation.

Crypto is easy to mess up, even when using “secure” primitives.

PHP did nothing wrong — it followed bcrypt spec. But the developer didn’t account for it. That’s what made this a beautiful logic bug masquerading as a secure system.


Epilogue — Beyond the Hash
#

I walked away from this one with a reminder:

  • Know your primitives.
  • Know your language wrappers.
  • And always, always, ask what happens when the input’s too long.

Sometimes all it takes is one byte to break the illusion.

Related

"PetCare" – CSRF in the Admin Panel: When One Click Made You an Admin
·906 words·5 mins
Bug Bounty Web Exploitation CSRF Authentication Bypass Admin Panel YesWeHack Web Security HTML Exploitation
JWT Hunt – Iron CTF 2024
·455 words·3 mins
CTF Iron CTF JWT Web Security Token Manipulation Authentication Bypass CTF 2024 Challenge Writeup Vaishnav Baraskar
Coffee, Curiosity & an API – JWT 'alg:none' Exploit in HealthTrack
·841 words·4 mins
Bug Bounty Writeups JWT Authentication Bypass Alg:none Burp Suite API Security