Bcrypt Breaking Passwords: How Hashes with Dragonica Are Leaked and Why It’s Easier Than It Seems

Depov

Activist
ULTIMATE
SUPREME
PREMIUM
MEMBER
Joined
Feb 18, 2025
Messages
126
Reaction score
115
Deposit
0$
At the CTF last year, the dump of the database of the private server Dragonica appeared - about 40 thousand accounts, bcrypt-hashi with cost factor 10. The organizers laid two days for the cracking stage. Two RTX 3090, rockyou dictionary plus custom-made gamelist with mutation rules - and in 14 hours managed to restore about 1500 passwords. Four percent of the base. It sounds little until you make the consequences: for the credential stuffing, the attack on Steam, Discord and Gmail of these 1500 pairs of login-password with a margin. Bcrypt is a good algorithm. But “good algorithm” and “safe password storage” are not synonymous when the cost cost is in default, and gamers put passwords like like dragonica2023.
Leak of the game database: from fingerprinting to password hash dump
Private servers Dragonica, Lunaris and similar projects are reversed server emulators, hung by self-written web panels. Typical stack: PHP 5.x–7.x, MySQL/MariaDB, phpMyAdmin for database management, sometimes WordPress or self-written CMS for landing. Safety here is the tenth thing: the developers are busy with gameplay and donat, not the infrastructure hardening.

Fingerprinting of such servers is a task for five minutes. Standard nmap -sV Identifies open ports of MySQL (3306) and phpMyAdmin (80/443). HTTP response headers give PHP version, availability X-Powered-By, sometimes debug information. Shodan, on request with the game name, displays dozens of private servers with predictable infrastructure.

[Applicable: external fittest, legacy-infrastructure]

Typical vectors through which the pairs of the game server leaks:

SQL injections in control panels (Exploit Public-Facting Application, T1190, Initial Access) Registration, password recovery, voting for the server - any form that works with the database. On private helper files, prepared are less common than direct concentrating of user input in SQL queries. One UNION-based SQLi in the form of a login - and table accounts with hashs on the screen.

Open phpMyAdmin (A05:2021, Security Misconfimuration by OWASP). It is surprisingly often. Admin puts phpMyAdmin "for himself", forgets to limit access - and /phpmyadmin/ hanging on the whole Internet. Connection with root without password or with standard root:root - and the whole base in the palm of your hand.

Weak Configu (MySQL) (Credentials In Files, T1552.001, Credential Access) MySQL listens to 0.0.0.0:3306, root password is empty or standard. Remote connection through mysql -h target -u root - and the dump tables with hash takes seconds.

Obsolete Components (A06:2021Vulnerable and Outdated Components by OWASP). PHP 5.6 with known RCE, old versions of phpMyAdmin, unstopped CMS plugins - standard entry points for initial access.

After accessing the database (Databases, T1213.006, Collection) the attacker exports a table with the account data. In Dragonica-like projects usually accounts or users - login, email, bcrypt-hash password. Then the offline work begins, which is no longer possible to detect on the server side.
The Complete Attack Chain
Recon (fingerprinting web panels, stacking) -> initial access (SQLi, open phpMyAdmin) -> collection (dump of tables with hashs) -> credential access (Password Cracking, T1110.002 - offline-cracking bcrypt) -> use of reduced passwords (Valid Accounts, T1078) for credential stuffing on third-party services. Each stage after the dump is discussed below.
Analysis by piece (based on the specification of bcrypt and Wikipedia data):
• $2a$- identifier of the algorithm and version. Options: $2a$, $2b$(Farm bug with password length >255 bytes in OpenBSD, February 2014) $2y$(Froming 8-bit character processing bug in PHP-implementation crypt_blowfish, June 2011). For hacking passwords has no difference - Hashcat and JtR process all three equally.
• 10- cost factor (fact factor). Means 2^10 = 1024 iteration of the key EksBlowfish schedule. This is a default in most implementations: Go bcrypt uses DefaultCost = 10(according to pkg.go.dev), PHP password_hash()- Also 10.
• 22 characters - base64-coded 128-bit salt (bcrypt uses its own base64 alphabet, different from RFC 4648).
• 31 characters - base64-encoded hash (the first 23 bytes from a 24-byte result).
Bcrypt is designed by Niels Provos and David Mazières based on the Blowfish cipher and unveiled at USENIX in 1999 (according to Wikipedia). The key mechanism - EksBlowfishSSetup: the 2^cost algorithm once drives ExpandKey with alternating password and salt, then encrypts the string OrpheanBeholderScryDoubt 64 times in ECB mode. The result is the final hash.
Three properties of bcrypt critical for password cracking
Limiting in 72 bytes. Bcrypt handles only the first 72 bytes of the password - the rest is silently discarded. In bcrypt 5.0.0 for Python (according to PyPI), the password transfer is longer than 72 bytes ValueError Instead of quiet truncation. For game servers, this is uncritical - gamers passwords are rarely longer than 15 characters. But if the developer has decided to hash through sha256(password) + bcrypt, 72-byte restriction ceases to be a problem - at the entrance there are always 44 characters base64.

Built-in salt. Each hash contains a unique 128-bit salt. Rainbow table attack is completely ineffective. Pre-calculated tables are useless - each password is crippled individually.

Exponential cost. Increase the cost by 1 doubles the calculation time. Cost 10 - 1024 iterations. Cost 12 - 4096, 4 times slower. Cost 14 - 16384, 16 times slower. According to the data from the article on Habr, at cost 12, the generation of one hash takes 0.2–0.3 seconds – this is the lower threshold of the OWASP recommendation (the hash calculation should take less than one second, but not less than ~250 ms). Most private game servers sit on a default cost = 10 - 0.05 seconds per hash, 4-6 times faster than the recommended minimum. By the standards of 2025 - just a gift for the attacker.
Realistic time of hacking of passwords hashes

On one RTX 3090 at cost=10 is a realistic speed of about 25–30 H/s (hashes per second). The RTX 4090 yields twice as much. It's not billions of H/s, as in MD5/SHA-256. But for a vocabulary attack with mutations according to the dictionary of 500 thousand records - 5-6 hours of work. Hashcat checks each candidate against all hashes in the file in parallel, so that the size of the dam affects the total time less than the size of the dictionary.
Hashcat: 3200 mode
Hashcat uses mode 3200 for all options bcrypt ($2a$, $2b$, $2y$) Dictionary attack with the rules of mutation:
Bash:
hashcat -m 3200 -a 0 hashes.txt rockyou.txt -r rules/best64.rule -w 3 --status --status-timer=60
Here -a 0 - vocabulary attack, -r rules/best64.rule - set of rules of mutation (addition of numbers, symbol replacement, register change), -w 3 - maximum load GPU, --status-timer=60 - progress every minute. File hashes.txt contains one hash on the string.

The most effective approach - cascading rules: first best64.rule (64 rules, quick verification of basic mutations), then d3ad0ne.rule (~34 thousand rules for deep study). Order is important: with 30 H/s, each unnecessary rule costs real time.
John the Ripper
JtR in the jumbo version supports bcrypt natively and automatically determines the prefix format:
Bash:
john --format=bcrypt --wordlist=rockyou.txt --rules=All hashes.txt
On the JtR CPU, it is more convenient for small lists (dozens of hashes), but for serious volumes, the GPU through Hashcat wins an order of magnitude. I usually run JtR to quickly check "what if someone put password123» - and if there are hits in the first minutes, switch to Hashcat with heavy rules.
Gamer passwords: why a vocabulary attack works better than ruthforseas
Pure Brutbling Bcrypt is a bad strategy. A complete selection of an 8-symbolic password with a mixed charset at 30 H/s will take centuries. A vocabulary attack with mutations is another matter.

Typical gamer passwords are predictable to pain: nick + year of birth (darkelf1998), the name of the class or server + digits (warrior123, lunaris2023, dragonica!), standard game terms (guildmaster, pvpking) The combination of rockyou with a customized gamer and mutation rules covers a significant share of the base in the first hours.

To form a custom wordlist: the names of classes and races from Dragonica, popular guilds from server forums, nicknames from top ratings. Add the rules of mutation - and the probability of hit grows multiples compared to pure rockyou. In practice, I always spend 20-30 minutes on the reconnaissance of the forum before cracking - this pays off with the first hits.
Restrictions of technology
Works if: cost=10 or lower, passwords are predictable, GPU with CUDA is available.

It does not work if: cost=12+, passwords are random or longer than 12 characters with special symbols. At cost = 14 even RTX 4090 gives about 3-4 H/s. Bcrypt burglary breakup is effective only if two conditions coincide: Low cost factor and Predictable passwords.
Credential stuffing attack: from hashs to real accounts
Recovered passwords are not the ultimate goal, but a resource for credential stuffing (Valid Accounts, T1078) Gamers reuse passwords everywhere: the same password on the game server, in Discord, Steam and Gmail.

Unlike corporate system leaks, game server dumpings often contain email addresses that users consider the main ones. Gamers do not introduce separate mailboxes for each server - this is the same Gmail or Mail.ru, through which Steam, Discord is tied, sometimes working mail. One recovered password can access an entire account chain.

Chain after cracking: from the dump takes an email, compared with the restored password. Automated tools check pairs on dozens of services. Access to Gmail opens passwords on other platforms. Discord account with Nitro subscription is monetized on black marketplaces. And all this - because of the password warrior123 on a forgotten private server.

According to OWASP A02:2021 (Cryptographic Failures), weak cryptographic protection of passwords leads to the compromise of sensitive data. Leaking a game database with bcrypt-hashes is the first link in a chain that ends far beyond the game server.
The vast majority of leaks from private servers are not due to the bcrypt vulnerabilities, but because of trivial configuration errors: open ports, default passwords, no prepared. Bcrypt with the right setting is a serious obstacle. Bcrypt with cost=10 and passwords from the dictionary is a formality.

There is a strong opinion that bcrypt does not break. Formally - true: at cost = 12+ and a random 14-sympoline password, complete oversize is unstoppable on any available gland. But in a few years of participation in the CTF and the analysis of game projects leaks, I have never met a base where all passwords would be random and long. Each time one picture: 60-70% of the base - dictionary words with numbers at the end, another 15-20% - variations of the nick, and only the remaining 10-15% - really resistant passwords that are not amenable to cracking.

The administrators of private servers put bcrypt and consider the issue closed. Cost factor? Default. The minimum password length? Six symbols. Rate limiting? Absent. Bcrypt in this configuration protects not the user, but self-assessment of the administrator. At the same time, cost = 10 OWASP no longer recommends - 0.05 seconds per hash too quickly for 2025.
 
Top Bottom