mcpField
H
hash-attack-techniques

hash-attack-techniques

github.com/yaklang安全2.6k3.6k 次安装6 周前更新
代码仓库

关于 hash-attack-techniques

hash-attack-techniques 是面向 CTF 参与者和安全评估人员的哈希攻击技能,按场景整理攻击方法,并说明适用条件、工具及防御要点。

主要功能

  1. 01长度扩展攻击
  2. 02MD5 和 SHA-1 碰撞技术
  3. 03HMAC 时序攻击
  4. 04生日攻击与中间相遇攻击
  5. 05哈希工作量证明求解
  6. 06彩虹表与密码哈希

适用场景

  1. 01为哈希类 CTF 题目选择攻击方法
  2. 02评估秘密前缀 MAC 是否易受长度扩展攻击
  3. 03生成或分析哈希碰撞场景
  4. 04检查 HMAC 比较与密码哈希防御

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yaklang/hack-skills --skill hash-attack-techniques

安装后在 Claude Code 中输入/hash-attack-techniques确认已加载。

详细介绍

技能:哈希攻击技术 — 密码分析专家手册

AI LOAD INSTRUCTION:面向 CTF 和安全评估的专家级哈希攻击技术。涵盖长度扩展攻击、MD5/SHA1 碰撞生成、中间相遇哈希攻击、HMAC 时序侧信道、生日攻击和工作量证明求解。基础模型经常错误地将长度扩展攻击用于 HMAC 或 SHA-3,或无法区分相同前缀碰撞和选定前缀碰撞。

0. 相关路由

快速选择攻击方式
场景攻击工具
已知 H(secret || msg),需要扩展消息长度扩展HashPump、hash_extender
需要两个 MD5 相同的文件相同前缀碰撞fastcoll
需要匹配指定 MD5 前缀选定前缀碰撞hashclash
逐字节比较 HMAC时序攻击自定义脚本
寻找任意碰撞生日攻击O(2^(n/2))
工作量证明:寻找前导零哈希暴力破解hashcat、Python

1. 长度扩展攻击

1.1 易受攻击与不易受攻击的算法
哈希是否易受攻击原因
MD5是Merkle-Damgard 构造
SHA-1是Merkle-Damgard 构造
SHA-256是Merkle-Damgard 构造
SHA-512是Merkle-Damgard 构造
SHA-3 / Keccak否海绵构造
HMAC-*否双重哈希可防止扩展
SHA-256 截断版否(若已截断)缺少内部状态位
BLAKE2否不同的构造
1.2 攻击机制
Given:   MAC = H(secret || original_message)
Known:   original_message, len(secret), MAC value
Compute: H(secret || original_message || padding || extension)
         WITHOUT knowing the secret!

How: The MAC value IS the internal hash state after processing
     (secret || original_message || padding).
     Initialize hash with this state, continue hashing extension.
1.3 填充计算(MD5/SHA)
def md5_padding(message_len_bytes):
    """Calculate MD5/SHA padding for given message length."""
    bit_len = message_len_bytes * 8

    # Pad with 0x80 + zeros until length ≡ 56 (mod 64)
    padding = b'\x80'
    padding += b'\x00' * ((55 - message_len_bytes) % 64)

    # Append original length as 64-bit little-endian (MD5)
    # or big-endian (SHA)
    padding += bit_len.to_bytes(8, 'little')  # MD5
    # padding += bit_len.to_bytes(8, 'big')    # SHA

    return padding
1.4 工具用法
# HashPump
hashpump -s "known_mac_hex" \
         -d "original_data" \
         -k 16 \            # secret length
         -a "extension_data"

# Output: new_mac, new_data (original + padding + extension)

# hash_extender
hash_extender --data "original" \
              --secret 16 \
              --append "extension" \
              --signature "known_mac_hex" \
              --format md5
1.5 Python 实现
import struct

def md5_extend(original_mac, original_data_len, secret_len, extension):
    """
    Perform MD5 length extension attack.
    original_mac: hex string of H(secret || original_data)
    """
    # Parse MAC into MD5 internal state (4 × 32-bit words, little-endian)
    h = struct.unpack('<4I', bytes.fromhex(original_mac))

    # Calculate total length after padding
    total_original = secret_len + original_data_len
    padding = md5_padding(total_original)
    forged_len = total_original + len(padding) + len(extension)

    # Continue MD5 from saved state with extension
    # (requires MD5 implementation that accepts initial state)
    from hashlib import md5
    # Most stdlib md5 doesn't expose state setting
    # Use: hlextend library or custom MD5

    import hlextend
    sha = hlextend.new('md5')
    new_hash = sha.extend(extension, original_data, secret_len,
                          original_mac)
    new_data = sha.payload  # includes original + padding + extension

    return new_hash, new_data

2. MD5 碰撞攻击

2.1 相同前缀碰撞(fastcoll)

两个消息具有相同前缀但内容不同,却产生相同的 MD5。

# Generate collision pair
fastcoll -p prefix_file -o collision1.bin collision2.bin

# Result: MD5(collision1.bin) == MD5(collision2.bin)
# Files differ in exactly 128 bytes (two MD5 blocks)
2.2 选定前缀碰撞(hashclash)

两个消息具有不同的选定前缀,通过附加计算出的后缀产生碰撞。

# hashclash (Marc Stevens)
./hashclash prefix1.bin prefix2.bin

# Result: MD5(prefix1 || suffix1) == MD5(prefix2 || suffix2)
2.3 UniColl(单块近碰撞)

生成两个消息,它们在一个 MD5 块中只有一个字节不同,但哈希值相同。

Application: forge two PDF/PE files with same MD5
  - File 1: benign content
  - File 2: malicious content
  - Same MD5 hash
2.4 碰撞应用
应用技术影响
伪造证书选定前缀恶意 CA 证书(2008 年已得到证明)
二进制替换相同前缀 + 条件构造两个可执行文件的 MD5 相同,但行为不同
PDF 碰撞UniColl两个 PDF 显示不同内容
Git 提交碰撞选定前缀(SHA1 的 SHAttered)两个提交具有相同哈希
CTF:绕过 MD5 检查fastcoll两个不同输入被视为相同并接受
2.5 CTF MD5 碰撞技巧
// PHP: md5($_GET['a']) == md5($_GET['b']) && $_GET['a'] != $_GET['b']

// Method 1: Array trick (not real collision)
?a[]=1&b[]=2  // md5(array) returns NULL, NULL == NULL

// Method 2: Real collision (fastcoll output, URL-encoded binary)
?a=<collision1_urlencoded>&b=<collision2_urlencoded>

// Method 3: 0e magic hashes (loose comparison ==)
// md5("240610708") = "0e462097431906509019562988736854"
// md5("QNKCDZO")   = "0e830400451993494058024219903391"
// PHP: "0e..." == "0e..." is TRUE (both evaluate to 0 as floats)

3. SHA-1 碰撞

3.1 SHAttered 攻击(2017 年)

首次实用的 SHA-1 碰撞:两个 SHA-1 相同的 PDF 文件。

  • 复杂度:约 2^63 次 SHA-1 计算
  • 成本:在 GPU 集群上约 11 万美元(按 2017 年价格计算)
  • 工具:shattered.io 提供碰撞 PDF
3.2 SHA-1 选定前缀碰撞(2020 年)
  • 复杂度:约 2^63.4 次计算
  • 可用于攻击 PGP/GnuPG 密钥服务器
  • 证明 SHA-1 的抗碰撞性已被攻破
3.3 影响
SHA-1 should NOT be used for:
  ✗ Digital signatures
  ✗ Certificate fingerprints
  ✗ Git commit integrity (migration to SHA-256 in progress)
  ✗ Deduplication based on hash

SHA-1 is still OK for:
  ✓ HMAC-SHA1 (collision resistance not required)
  ✓ HKDF-SHA1 (PRF security suffices)
  ✓ Non-adversarial checksums

4. 生日攻击

4.1 通用生日界限
For n-bit hash: expected collisions after ~2^(n/2) hashes

Hash     Bits    Birthday bound
MD5      128     2^64
SHA-1    160     2^80
SHA-256  256     2^128

CTF application: if hash is truncated to k bits,
collision in ~2^(k/2) attempts
4.2 生日攻击实现
import hashlib
import os

def birthday_attack(hash_func, output_bits, max_attempts=2**28):
    """Find collision for truncated hash."""
    mask = (1 << output_bits) - 1
    seen = {}

    for _ in range(max_attempts):
        msg = os.urandom(16)
        h = int(hash_func(msg).hexdigest(), 16) & mask

        if h in seen and seen[h] != msg:
            return seen[h], msg  # collision!
        seen[h] = msg

    return None

# Example: find collision for first 32 bits of SHA-256
result = birthday_attack(hashlib.sha256, 32)

5. HMAC 时序攻击

5.1 易受攻击的比较方式
# VULNERABLE: early-exit string comparison
def verify_hmac(received, expected):
    return received == expected  # Python == compares left to right

# The comparison may short-circuit on first differing byte,
# leaking timing information
5.2 攻击策略
import requests
import time

def hmac_timing_attack(url, data, hmac_len=32):
    """Byte-by-byte HMAC recovery via timing."""
    known = ""

    for pos in range(hmac_len * 2):  # hex chars
        best_char = ""
        best_time = 0

        for c in "0123456789abcdef":
            candidate = known + c + "0" * (hmac_len * 2 - len(known) - 1)
            times = []

            for _ in range(50):  # multiple samples for accuracy
                start = time.perf_counter_ns()
                requests.get(url, params={**data, "mac": candidate})
                elapsed = time.perf_counter_ns() - start
                times.append(elapsed)

            avg_time = sorted(times)[len(times)//2]  # median
            if avg_time > best_time:
                best_time = avg_time
                best_char = c

        known += best_char
        print(f"Position {pos}: {known}")

    return known
5.3 恒定时间比较(防御)
import hmac

# SECURE: constant-time comparison
def verify_hmac_secure(received, expected):
    return hmac.compare_digest(received, expected)

6. 中间相遇攻击(哈希)

6.1 概念

将哈希计算拆分为两半,预先计算其中一半,再与另一半进行匹配。

Hash computation: H = f(g(x₁), h(x₂))

Precompute: table[g(x₁)] = x₁  for all x₁ in space₁
Search:     for each x₂ in space₂:
              if h(x₂) in table:
                found! (x₁, x₂)

Time:  O(2^(n/2)) instead of O(2^n)
Space: O(2^(n/2))

7. 哈希工作量证明

7.1 常见 CTF PoW 格式
# Format 1: Find x such that SHA256(prefix + x) starts with N zero bits
import hashlib

def solve_pow_prefix(prefix, zero_bits):
    target = '0' * (zero_bits // 4)
    i = 0
    while True:
        candidate = prefix + str(i)
        h = hashlib.sha256(candidate.encode()).hexdigest()
        if h.startswith(target):
            return str(i)
        i += 1

# Format 2: Find x such that SHA256(x) ends with specific suffix
def solve_pow_suffix(suffix_hex, hash_func=hashlib.sha256):
    i = 0
    while True:
        h = hash_func(str(i).encode()).hexdigest()
        if h.endswith(suffix_hex):
            return str(i)
        i += 1
7.2 GPU 加速的 PoW
# hashcat for SHA256 PoW
hashcat -a 3 -m 1400 --hex-charset \
  "0000000000000000000000000000000000000000000000000000000000000000:prefix" \
  "?a?a?a?a?a?a?a?a"

8. 彩虹表与加盐

8.1 彩虹表攻击
Precomputed chain: password → hash → reduce → password₂ → hash₂ → ...
Lookup: given hash h, check if h appears in any chain
Time-memory tradeoff: less space than full table, more time than direct lookup
8.2 加盐可抵御彩虹表
Without salt: H(password) — same password always produces same hash
With salt:    H(salt || password) — different salt per user

Rainbow tables are password-specific, not (salt+password)-specific
Each unique salt requires a separate table → infeasible
8.3 现代密码哈希
算法盐值迭代次数内存困难型推荐
MD5否1否永不使用
SHA-256否1否永不用于密码
bcrypt是可配置否是
scrypt是可配置是是
Argon2是可配置是最佳选择
PBKDF2是可配置否可接受

9. 决策树

Hash-related challenge — what's the scenario?
│
├─ Have H(secret || message), need to extend?
│  ├─ Hash is MD5/SHA1/SHA256/SHA512?
│  │  └─ Yes → Length extension attack
│  │     └─ Need: MAC value, original message, secret length
│  │        └─ Tool: HashPump or hash_extender
│  │
│  └─ Hash is SHA3/HMAC/BLAKE2?
│     └─ Length extension doesn't work
│        └─ Look for other vulnerabilities
│
├─ Need two inputs with same hash?
│  ├─ MD5?
│  │  ├─ Same prefix → fastcoll (seconds)
│  │  ├─ Different prefixes → hashclash (hours)
│  │  └─ CTF PHP loose comparison → 0e magic hashes
│  │
│  ├─ SHA-1?
│  │  └─ SHAttered (expensive, use precomputed if possible)
│  │
│  └─ SHA-256+?
│     └─ No practical collision attack
│        └─ Look for logic flaws instead
│
├─ Need to forge HMAC?
│  ├─ Timing side channel available?
│  │  └─ Byte-by-byte timing attack
│  │
│  ├─ Key is short/weak?
│  │  └─ Brute force key with hashcat
│  │
│  └─ No weakness?
│     └─ HMAC is secure — look elsewhere
│
├─ Hash is truncated (short output)?
│  └─ Birthday attack — collision in 2^(bits/2)
│
├─ Proof of work?
│  └─ Brute force with parallel computation
│     ├─ Python multiprocessing for < 28 bits
│     ├─ hashcat/GPU for > 28 bits
│     └─ Optimize: pre-increment string, avoid re-encoding
│
└─ Password hash cracking?
   ├─ No salt → rainbow tables (pre-computed)
   ├─ Known salt → hashcat / John the Ripper
   └─ Memory-hard (Argon2/scrypt) → limited by memory, slow brute force

10. 工具

工具用途用法
HashPump长度扩展攻击hashpump -s MAC -d data -k secret_len -a extension
hash_extender长度扩展(多种算法)hash_extender --data D --secret L --append E --sig MAC
fastcollMD5 相同前缀碰撞fastcoll -p prefix -o out1 out2
hashclashMD5 选定前缀碰撞hashclash prefix1 prefix2
hashcat密码/哈希破解(GPU)hashcat -m MODE -a ATTACK hash wordlist
John the Ripper密码破解(CPU/GPU)john --wordlist=rockyou.txt hashes.txt
CyberChef快速计算哈希和编码基于 Web

评论

支持 Markdown