Athena Wiki

Hash Functions

cryptobeginner

Understand cryptographic hash functions and their properties for CTF crypto challenges.

cryptohashmd5sha-1sha-256collisionpreimagebirthday

Hash Functions

Cryptographic hash functions take arbitrary-length input and produce a fixed-length output (the hash/digest). They're fundamental to CTF crypto - for verifying inputs, generating tokens, and as building blocks for MACs and HMACs.

Hash Function Concept

Input (any length):  "Hello World"

                        [Hash Function]

Output (fixed length): SHA-256 Hash (256-bit)
                     2a4d9a96... (64 hex chars)

A hash function is a one-way function:

  • Easy to compute: Hash("password") = d3c8...
  • Hard to reverse: Given d3c8..., can't find the original
  • Deterministic: Same input = same output every time

Core Properties

PropertyDefinitionBroken When
Pre-image resistanceGiven hash H, can't find m where H(m)=HYou can reverse the hash
Second pre-image resistanceGiven m1m_1, can't find m2m1m_2 \neq m_1 with H(m1)=H(m2)H(m_1)=H(m_2)You can forge an alternate input
Collision resistanceCan't find any m1m2m_1 \neq m_2 with H(m1)=H(m2)H(m_1)=H(m_2)Collisions found

Common Hash Algorithms: Security Status

AlgorithmOutputStatus
MD5128 bits (32 hex)Broken - collisions trivial
SHA-1160 bits (40 hex)Broken - collisions found (SHAttered)
SHA-256256 bits (64 hex)Secure
SHA-512512 bits (128 hex)Secure
SHA-3/KeccakVariableSecure (different construction)
bcrypt60 charsSecure (slow, for passwords)
BLAKE2VariableFast and secure

Python Hash Generation

import hashlib

# MD5
h = hashlib.md5(b"hello").hexdigest()
print(h)  # → 5d41402abc4b2a76b9719d911017c592

# SHA-256
h = hashlib.sha256(b"hello").hexdigest()
print(h)  # → 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

# SHA-512
h = hashlib.sha512(b"hello").hexdigest()

# HMAC (keyed hash)
import hmac
h = hmac.new(b"secret_key", b"message", hashlib.sha256).hexdigest()

MD5 Collision Attacks

MD5 collisions are computationally feasible. Two different files with the same MD5:

# Download pre-computed collision files
# from: https://md5collision.cr.yp.to/

# Verify:
md5sum file1 file2
# → same hash, different content!

CTF application: bypassing MD5 equality checks

// Vulnerable: strcmp checks MD5, not content
if (md5($file1) === md5($file2) && $file1 !== $file2) {
    echo "Flag: " . $flag;
}

Use two MD5-colliding files that hash to the same value.


MD5 Magic Hashes (PHP Type Juggling)

In PHP with loose comparison (==), a hash starting with 0e[digits] is treated as scientific notation (equals 0 in comparison):

"0e123" == "0e456"  // TRUE in PHP! Both = 0 * 10^123 = 0
md5("240610708") = "0e462097431906509019562988736854"
md5("QNKCDZO")   = "0e830400451993494058024219903391"
// Both start with "0e" → PHP loose comparison says they're equal!

Magic hash values for common algorithms:

Hash / InputResult (Magic Hash)
md5("240610708")0e462097431906509019562988736854
md5("QNKCDZO")0e830400451993494058024219903391
sha1("aaroZmOk")0e66507019969427134894895893711890
sha256("34250003024812")0e08f71...

Hash Extension Attack

See: Length Extension Attack page


HMAC

HMAC is not vulnerable to length extension attacks (unlike plain Hash(secret || message)):

import hmac, hashlib

# HMAC with SHA-256
mac = hmac.new(
    key=b"secret_key",
    msg=b"message",
    digestmod=hashlib.sha256
).hexdigest()

# Verify
expected = "..."
hmac.compare_digest(mac, expected)  # timing-safe comparison

Birthday Attack

In a CTF context, the birthday paradox means collision probability is much higher than expected:

For a hash of n bits, expect a collision after ~2^(n/2) attempts:

  • MD5 (128 bits): ~2^64 attempts
  • SHA-1 (160 bits): ~2^80 attempts
  • SHA-256 (256 bits): ~2^128 attempts (infeasible)
# Finding MD5 prefix collisions (simplified)
import hashlib, random, string

target_prefix = "0000"  # find input whose MD5 starts with "0000"
for _ in range(10**7):
    candidate = ''.join(random.choices(string.ascii_letters, k=10))
    h = hashlib.md5(candidate.encode()).hexdigest()
    if h.startswith(target_prefix):
        print(f"Found: {candidate}{h}")
        break

See also

  • RSA Basics - How RSA uses hashes for signatures and key derivation.
  • ECC Basics - How ECC uses hashes in ECDSA and protocols.

Last updated on

On this page