Skip to main content

Overview

The HashCracker module provides fast MD5 password hash cracking using two techniques: known hash lookup and dictionary-based brute-forcing with common passwords. It integrates seamlessly with credential extraction from other modules like SQLMapInjector.
Ethical Use Only: Hash cracking should only be performed on credentials extracted from authorized penetration tests. Unauthorized password cracking is illegal.

Module Location

services/hash_cracker.py

Class Definition

class HashCracker:
    """Crackeo rápido de hashes MD5 con diccionario"""
    
    HASH_MD5_KNOWN = {
        '5f4dcc3b5aa765d61d8327deb882cf99': 'password',
        '21232f297a57a5a743894a0e4a801fc3': 'admin',
        '0192023a7bbd73250516f069df18b500': 'admin123',
        'e10adc3949ba59abbe56e057f20f883e': '123456',
        '63a9f0ea7bb98050796b649e85481845': 'root',
        '7813d1590d28a7dd372ad54b5d29571b': 'toor',
        '0d107d09f5bbe40cade3de5c71e9e9b7': 'letmein',
        '40be4e59b9a2a2b5dffb918c0e86b3d7': 'monkey',
        '8621ffdbc5698829397d97767ac13db3': 'dragon',
        'eb0a191797624dd3a48fa681d3061212': 'qwerty',
        'd8578edf8458ce06fbc5bb76a58c5ca4': 'qwerty',
    }
The class uses a static dictionary of pre-computed MD5 hashes for instant lookup of common passwords.

Core Methods

crack_md5()

Attempts to crack a single MD5 hash using two-stage approach.
@classmethod
def crack_md5(cls, hash_value):
    """Intentar crackear un hash MD5"""
    hash_lower = hash_value.strip().lower()
    
    # 1. Buscar en hashes conocidos
    if hash_lower in cls.HASH_MD5_KNOWN:
        return cls.HASH_MD5_KNOWN[hash_lower]
    
    # 2. Probar contraseñas comunes
    for pwd in Config.COMMON_PASSWORDS:
        if hashlib.md5(pwd.encode()).hexdigest() == hash_lower:
            return pwd
    
    return None
Stage 1: Known Hash Lookup O(1) dictionary lookup against pre-computed hashes:
if hash_lower in cls.HASH_MD5_KNOWN:
    return cls.HASH_MD5_KNOWN[hash_lower]
Pre-computed Hashes:
HashPassword
5f4dcc3b5aa765d61d8327deb882cf99password
21232f297a57a5a743894a0e4a801fc3admin
e10adc3949ba59abbe56e057f20f883e123456
63a9f0ea7bb98050796b649e85481845root
0d107d09f5bbe40cade3de5c71e9e9b7letmein
Stage 2: Dictionary Brute-Force Computes MD5 hash for each password in Config.COMMON_PASSWORDS:
for pwd in Config.COMMON_PASSWORDS:
    if hashlib.md5(pwd.encode()).hexdigest() == hash_lower:
        return pwd
Return Value:
  • String: Cracked password
  • None: Hash not cracked

crack_credentials()

Batch processes a list of credential dictionaries and updates them with cracked passwords.
@classmethod
def crack_credentials(cls, credentials):
    """Crackear todos los hashes en una lista de credenciales"""
    cracked = 0
    for cred in credentials:
        hash_val = cred.get('hash', '')
        # Si parece un hash MD5 (32 hex chars)
        if hash_val and len(hash_val) == 32 and all(c in '0123456789abcdefABCDEF' for c in hash_val):
            result = cls.crack_md5(hash_val)
            if result:
                cred['password'] = f"{result}"
                cred['cracked'] = True
                cracked += 1
                rprint(f"   [bold green]✅ CRACKED: {cred['user']}{hash_val[:16]}... = '{result}'[/bold green]")
            else:
                cred['cracked'] = False
                rprint(f"   [yellow]❌ No crackeado: {cred['user']}{hash_val[:16]}...[/yellow]")
    
    return cracked
MD5 Hash Validation:
if hash_val and len(hash_val) == 32 and all(c in '0123456789abcdefABCDEF' for c in hash_val):
Verifies:
  • Hash exists and is not empty
  • Exactly 32 characters (MD5 length)
  • All characters are hexadecimal (0-9, a-f, A-F)
Credential Update:
if result:
    cred['password'] = f"{result}"
    cred['cracked'] = True
    cracked += 1
else:
    cred['cracked'] = False
Modifies credentials in-place, adding cracked boolean flag. Output Examples: Success:
   ✅ CRACKED: admin → 5f4dcc3b5aa765d6... = 'password'
   ✅ CRACKED: user1 → e10adc3949ba59ab... = '123456'
Failure:
   ❌ No crackeado: user2 → 8f3a9bc4e2d1f5c7...
Return Value: Integer count of successfully cracked hashes.

Configuration Requirements

Config.COMMON_PASSWORDS = [
    'password', 'admin', 'root', '123456', 'qwerty',
    'letmein', 'welcome', 'monkey', 'dragon', '1234',
    'password1', 'admin123', 'root123', 'test', 'guest'
]
Expand this list for higher crack rates. Common sources:
  • Top 100 passwords from breach databases
  • Rockyou.txt top 1000
  • Context-specific passwords (company name, year, etc.)

Integration with SQLMapInjector

Typical workflow from SQL injection to hash cracking:
from services.sqlmap_inject import SQLMapInjector
from services.hash_cracker import HashCracker

# 1. Extract credentials via SQLMap
injector = SQLMapInjector(host)
vulns = injector.attack()

# host.credentials now contains:
# [
#   {'user': 'admin', 'hash': '5f4dcc3b5aa765d61d8327deb882cf99', 'password': '5f4dcc...', 'cracked': False},
#   {'user': 'user1', 'hash': 'e10adc3949ba59abbe56e057f20f883e', 'password': 'e10adc...', 'cracked': False}
# ]

# 2. Crack extracted hashes
cracked_count = HashCracker.crack_credentials(host.credentials)

# host.credentials now contains:
# [
#   {'user': 'admin', 'hash': '5f4dcc...', 'password': 'password', 'cracked': True},
#   {'user': 'user1', 'hash': 'e10adc...', 'password': '123456', 'cracked': True}
# ]

print(f"Cracked {cracked_count} passwords")

Expected Credential Format

Input dictionary structure:
{
    'source': 'SQLMap (DVWA)',      # Where hash was found
    'user': 'admin',                 # Username
    'password': '5f4dcc3b5aa765...',  # Initially contains hash
    'hash': '5f4dcc3b5aa765...',      # MD5 hash value
    'cracked': False                 # Status flag
}
After cracking:
{
    'source': 'SQLMap (DVWA)',
    'user': 'admin',
    'password': 'password',          # Replaced with plaintext
    'hash': '5f4dcc3b5aa765...',
    'cracked': True                  # Updated to True
}

Performance Characteristics

Known Hash Lookup:
  • Time Complexity: O(1)
  • Space Complexity: O(n) where n = size of HASH_MD5_KNOWN
  • Speed: Instant (dictionary lookup)
Dictionary Brute-Force:
  • Time Complexity: O(m) where m = len(Config.COMMON_PASSWORDS)
  • Space Complexity: O(1)
  • Speed: ~1000 hashes/second on modern CPU
Total per hash: Typically < 10ms

Limitations

  1. MD5 Only: Does not support bcrypt, SHA-256, SHA-512, or other algorithms
  2. Small Dictionary: Config.COMMON_PASSWORDS is limited; won’t crack strong passwords
  3. No GPU Acceleration: Uses CPU-based hashlib, not optimized for cracking
  4. No Rainbow Tables: Doesn’t use precomputed tables beyond HASH_MD5_KNOWN
  5. No Salts: Assumes unsalted MD5 hashes (common in old applications)

Extending the Module

Adding More Known Hashes

HASH_MD5_KNOWN = {
    # Existing hashes...
    'a94a8fe5ccb19ba61c4c0873d391e987': '12345',
    '81dc9bdb52d04dc20036dbd8313ed055': '1234',
    'c4ca4238a0b923820dcc509a6f75849b': '1',
}

Using External Wordlists

@classmethod
def crack_md5_with_wordlist(cls, hash_value, wordlist_path):
    hash_lower = hash_value.strip().lower()
    
    with open(wordlist_path, 'r', encoding='latin-1') as f:
        for line in f:
            pwd = line.strip()
            if hashlib.md5(pwd.encode()).hexdigest() == hash_lower:
                return pwd
    return None
Usage:
result = HashCracker.crack_md5_with_wordlist(
    '5f4dcc3b5aa765d61d8327deb882cf99',
    '/usr/share/wordlists/rockyou.txt'
)

Alternative Tools

For production hash cracking, consider: Hashcat (GPU-accelerated):
hashcat -m 0 -a 0 hashes.txt rockyou.txt
  • -m 0: MD5 mode
  • -a 0: Dictionary attack
  • Speeds: 10-50 billion hashes/second on modern GPU
John the Ripper:
john --format=raw-md5 --wordlist=rockyou.txt hashes.txt

Dependencies

  • hashlib: Python standard library (MD5 hashing)
  • rich: Terminal formatting for output

Security Considerations

  1. Weak Hashes: MD5 is cryptographically broken; modern applications use bcrypt/Argon2
  2. Storage: Never store cracked passwords in plaintext logs
  3. Reporting: Redact passwords in reports; demonstrate vulnerability without exposing credentials
  4. Legal: Possession of cracked credentials may have legal implications in some jurisdictions
  • SQLMapInjector: Extracts MD5 hashes from databases
  • WPForceBrute: Obtains plaintext passwords (no cracking needed)
  • NmapScanner: No direct integration (doesn’t extract credentials)

Build docs developers (and LLMs) love