hash-attack-techniques
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSKILL: Hash Attack Techniques — Expert Cryptanalysis Playbook
SKILL:哈希攻击技术——专家级密码分析手册
AI LOAD INSTRUCTION: Expert hash attack techniques for CTF and security assessments. Covers length extension attacks, MD5/SHA1 collision generation, meet-in-the-middle hash attacks, HMAC timing side channels, birthday attacks, and proof-of-work solving. Base models often incorrectly apply length extension to HMAC or SHA-3, or fail to distinguish between identical-prefix and chosen-prefix collisions.
AI加载说明:适用于CTF和安全评估的专家级哈希攻击技术,涵盖长度扩展攻击、MD5/SHA1碰撞生成、中间相遇哈希攻击、HMAC时序侧信道、生日攻击以及工作量证明求解。基础模型通常会错误地将长度扩展攻击应用于HMAC或SHA-3,或者无法区分相同前缀碰撞和选择前缀碰撞。
0. RELATED ROUTING
0. 相关路由
- rsa-attack-techniques when hash weaknesses affect RSA signature schemes
- symmetric-cipher-attacks when hash is used in key derivation
- classical-cipher-analysis when analyzing hash-like constructions in classical ciphers
- 当哈希漏洞影响RSA签名方案时,参考rsa-attack-techniques
- 当哈希用于密钥派生时,参考symmetric-cipher-attacks
- 当分析古典密码中的类哈希构造时,参考classical-cipher-analysis
Quick attack selection
快速攻击选择
| Scenario | Attack | Tool |
|---|---|---|
| Length extension | HashPump, hash_extender |
| Need two files with same MD5 | Identical-prefix collision | fastcoll |
| Need specific MD5 prefix match | Chosen-prefix collision | hashclash |
| Byte-by-byte HMAC comparison | Timing attack | Custom script |
| Find any collision | Birthday attack | O(2^(n/2)) |
| Proof of work: find hash with leading zeros | Brute force | hashcat, Python |
| 场景 | 攻击方式 | 工具 |
|---|---|---|
| 已知`H(secret | msg)`,需要扩展消息 | |
| 需要两个MD5相同的文件 | 相同前缀碰撞 | fastcoll |
| 需要匹配特定MD5前缀 | 选择前缀碰撞 | hashclash |
| 逐字节HMAC比较 | 时序攻击 | 自定义脚本 |
| 查找任意碰撞 | 生日攻击 | O(2^(n/2)) |
| 工作量证明:查找带前导零的哈希 | 暴力破解 | hashcat, Python |
1. LENGTH EXTENSION ATTACK
1. 长度扩展攻击
1.1 Vulnerable vs Non-Vulnerable
1.1 易受攻击 vs 不受影响的哈希算法
| Hash | Vulnerable | Why |
|---|---|---|
| MD5 | Yes | Merkle-Damgard construction |
| SHA-1 | Yes | Merkle-Damgard construction |
| SHA-256 | Yes | Merkle-Damgard construction |
| SHA-512 | Yes | Merkle-Damgard construction |
| SHA-3 / Keccak | No | Sponge construction |
| HMAC-* | No | Double hashing prevents extension |
| SHA-256 truncated | No (if truncated) | Missing internal state bits |
| BLAKE2 | No | Different construction |
| 哈希算法 | 是否易受攻击 | 原因 |
|---|---|---|
| MD5 | 是 | Merkle-Damgard 构造 |
| SHA-1 | 是 | Merkle-Damgard 构造 |
| SHA-256 | 是 | Merkle-Damgard 构造 |
| SHA-512 | 是 | Merkle-Damgard 构造 |
| SHA-3 / Keccak | 否 | Sponge 构造 |
| HMAC-* | 否 | 双重哈希防止扩展 |
| 截断版SHA-256 | 否(如果截断) | 缺失内部状态位 |
| BLAKE2 | 否 | 不同的构造逻辑 |
1.2 Attack Mechanism
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.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 Padding Calculation (MD5/SHA)
1.3 填充计算(MD5/SHA)
python
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 paddingpython
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 padding1.4 Tool Usage
1.4 工具使用
bash
undefinedbash
undefinedHashPump
HashPump
hashpump -s "known_mac_hex"
-d "original_data"
-k 16 \ # secret length -a "extension_data"
-d "original_data"
-k 16 \ # secret length -a "extension_data"
hashpump -s "known_mac_hex"
-d "original_data"
-k 16 \ # secret length -a "extension_data"
-d "original_data"
-k 16 \ # secret length -a "extension_data"
Output: new_mac, new_data (original + padding + extension)
Output: new_mac, new_data (original + padding + extension)
hash_extender
hash_extender
hash_extender --data "original"
--secret 16
--append "extension"
--signature "known_mac_hex"
--format md5
--secret 16
--append "extension"
--signature "known_mac_hex"
--format md5
undefinedhash_extender --data "original"
--secret 16
--append "extension"
--signature "known_mac_hex"
--format md5
--secret 16
--append "extension"
--signature "known_mac_hex"
--format md5
undefined1.5 Python Implementation
1.5 Python实现
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_datapython
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_data2. MD5 COLLISION ATTACKS
2. MD5碰撞攻击
2.1 Identical-Prefix Collision (fastcoll)
2.1 相同前缀碰撞(fastcoll)
Two messages with same prefix but different content, producing identical MD5.
bash
undefined两个前缀相同但内容不同的消息,生成相同的MD5值。
bash
undefinedGenerate collision pair
Generate collision pair
fastcoll -p prefix_file -o collision1.bin collision2.bin
fastcoll -p prefix_file -o collision1.bin collision2.bin
Result: MD5(collision1.bin) == MD5(collision2.bin)
Result: MD5(collision1.bin) == MD5(collision2.bin)
Files differ in exactly 128 bytes (two MD5 blocks)
Files differ in exactly 128 bytes (two MD5 blocks)
undefinedundefined2.2 Chosen-Prefix Collision (hashclash)
2.2 选择前缀碰撞(hashclash)
Two messages with different chosen prefixes, appended with computed suffixes to collide.
bash
undefined两个带有不同选择前缀的消息,附加计算出的后缀后产生碰撞。
bash
undefinedhashclash (Marc Stevens)
hashclash (Marc Stevens)
./hashclash prefix1.bin prefix2.bin
./hashclash prefix1.bin prefix2.bin
Result: MD5(prefix1 || suffix1) == MD5(prefix2 || suffix2)
Result: MD5(prefix1 || suffix1) == MD5(prefix2 || suffix2)
undefinedundefined2.3 UniColl (Single-Block Near-Collision)
2.3 UniColl(单块近碰撞)
Produces two messages differing in a single byte within one MD5 block, with same hash.
Application: forge two PDF/PE files with same MD5
- File 1: benign content
- File 2: malicious content
- Same MD5 hash生成两个在单个MD5块内仅相差一个字节的消息,拥有相同的哈希值。
应用场景:伪造两个MD5相同的PDF/PE文件
- 文件1:良性内容
- 文件2:恶意内容
- 相同MD5哈希2.4 Collision Applications
2.4 碰撞应用场景
| Application | Technique | Impact |
|---|---|---|
| Certificate forgery | Chosen-prefix | Rogue CA certificate (proven in 2008) |
| Binary substitution | Identical-prefix + conditional | Two executables, same MD5, different behavior |
| PDF collision | UniColl | Two PDFs showing different content |
| Git commit collision | Chosen-prefix (SHAttered for SHA1) | Two commits with same hash |
| CTF: bypass MD5 check | fastcoll | Two different inputs accepted as same |
| 应用 | 技术 | 影响 |
|---|---|---|
| 证书伪造 | 选择前缀 | 伪造CA证书(2008年已被证实) |
| 二进制文件替换 | 相同前缀+条件判断 | 两个MD5相同、行为不同的可执行文件 |
| PDF碰撞 | UniColl | 两个显示不同内容的PDF |
| Git提交碰撞 | 选择前缀(针对SHA1的SHAttered攻击) | 两个哈希相同的提交 |
| CTF:绕过MD5校验 | fastcoll | 两个不同输入被判定为相同 |
2.5 CTF MD5 Collision Tricks
2.5 CTF MD5碰撞技巧
php
// 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)php
// 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 COLLISION
3. SHA-1碰撞
3.1 SHAttered Attack (2017)
3.1 SHAttered攻击(2017)
First practical SHA-1 collision: two PDF files with same SHA-1.
- Complexity: ~2^63 SHA-1 computations
- Cost: ~$110K on GPU clusters (2017 prices)
- Tool: shattered.io provides the collision PDFs
首个实用的SHA-1碰撞:两个SHA-1相同的PDF文件。
- 复杂度:约2^63次SHA-1计算
- 成本:在GPU集群上约11万美元(2017年价格)
- 工具:shattered.io提供碰撞PDF
3.2 SHA-1 Chosen-Prefix Collision (2020)
3.2 SHA-1选择前缀碰撞(2020)
- Complexity: ~2^63.4 computations
- Practical for attacking PGP/GnuPG key servers
- Demonstrates SHA-1 is broken for collision resistance
- 复杂度:约2^63.4次计算
- 可用于攻击PGP/GnuPG密钥服务器
- 证明SHA-1的碰撞抵抗性已被攻破
3.3 Impact
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 checksumsSHA-1 不应用于以下场景:
✗ 数字签名
✗ 证书指纹
✗ Git提交完整性校验(正在迁移到SHA-256)
✗ 基于哈希的去重
SHA-1 仍可安全用于以下场景:
✓ HMAC-SHA1(不需要碰撞抵抗性)
✓ HKDF-SHA1(PRF安全性足够)
✓ 非对抗性场景的校验和4. BIRTHDAY ATTACK
4. 生日攻击
4.1 Generic Birthday Bound
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对于n位哈希:约2^(n/2)次哈希计算后大概率出现碰撞
哈希算法 位数 生日边界
MD5 128 2^64
SHA-1 160 2^80
SHA-256 256 2^128
CTF应用场景:如果哈希被截断为k位,约2^(k/2)次尝试即可找到碰撞4.2 Birthday Attack Implementation
4.2 生日攻击实现
python
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 Nonepython
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 NoneExample: find collision for first 32 bits of SHA-256
Example: find collision for first 32 bits of SHA-256
result = birthday_attack(hashlib.sha256, 32)
---result = birthday_attack(hashlib.sha256, 32)
---5. HMAC TIMING ATTACK
5. HMAC时序攻击
5.1 Vulnerable Comparison
5.1 易受攻击的比较逻辑
python
undefinedpython
undefinedVULNERABLE: early-exit string comparison
存在漏洞:提前退出的字符串比较
def verify_hmac(received, expected):
return received == expected # Python == compares left to right
def verify_hmac(received, expected):
return received == expected # Python == 从左到右比较
The comparison may short-circuit on first differing byte,
比较会在第一个不同字节处短路,泄露时序信息
leaking timing information
—
undefinedundefined5.2 Attack Strategy
5.2 攻击策略
python
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 knownpython
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 known5.3 Constant-Time Comparison (Defense)
5.3 恒时比较(防御方案)
python
import hmacpython
import hmacSECURE: constant-time comparison
安全:恒时比较
def verify_hmac_secure(received, expected):
return hmac.compare_digest(received, expected)
---def verify_hmac_secure(received, expected):
return hmac.compare_digest(received, expected)
---6. MEET-IN-THE-MIDDLE (HASH)
6. 中间相遇攻击(哈希)
6.1 Concept
6.1 概念
Split hash computation into two halves, precompute one, match against the other.
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))将哈希计算拆分为两部分,预计算其中一部分,与另一部分匹配。
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. HASH PROOF-OF-WORK
7. 哈希工作量证明
7.1 Common CTF PoW Formats
7.1 常见CTF工作量证明格式
python
undefinedpython
undefinedFormat 1: Find x such that SHA256(prefix + x) starts with N zero bits
格式1:查找x使得SHA256(prefix + x)以N个零比特开头
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
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
格式2:查找x使得SHA256(x)以特定后缀结尾
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
undefineddef 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
undefined7.2 GPU-Accelerated PoW
7.2 GPU加速的工作量证明求解
bash
undefinedbash
undefinedhashcat for SHA256 PoW
hashcat for SHA256 PoW
hashcat -a 3 -m 1400 --hex-charset
"0000000000000000000000000000000000000000000000000000000000000000:prefix"
"?a?a?a?a?a?a?a?a"
"0000000000000000000000000000000000000000000000000000000000000000:prefix"
"?a?a?a?a?a?a?a?a"
---hashcat -a 3 -m 1400 --hex-charset
"0000000000000000000000000000000000000000000000000000000000000000:prefix"
"?a?a?a?a?a?a?a?a"
"0000000000000000000000000000000000000000000000000000000000000000:prefix"
"?a?a?a?a?a?a?a?a"
---8. RAINBOW TABLES & SALTING
8. 彩虹表与加盐
8.1 Rainbow Table Attack
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预计算链:密码 → 哈希 → 归约 → 密码2 → 哈希2 → ...
查找:给定哈希h,检查h是否出现在任意链中
时间内存权衡:比全量表占用空间少,比直接查找耗时多8.2 Salt Defeats Rainbow Tables
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不加盐:H(密码) — 相同密码始终生成相同哈希
加盐:H(盐 || 密码) — 每个用户使用不同的盐
彩虹表是针对密码的,不是针对(盐+密码)的
每个唯一盐都需要单独的彩虹表 → 实际不可行8.3 Modern Password Hashing
8.3 现代密码哈希算法
| Algorithm | Salt | Iterations | Memory-Hard | Recommended |
|---|---|---|---|---|
| MD5 | No | 1 | No | Never |
| SHA-256 | No | 1 | No | Never for passwords |
| bcrypt | Yes | Configurable | No | Yes |
| scrypt | Yes | Configurable | Yes | Yes |
| Argon2 | Yes | Configurable | Yes | Best choice |
| PBKDF2 | Yes | Configurable | No | Acceptable |
| 算法 | 加盐 | 迭代次数 | 内存硬加密 | 推荐程度 |
|---|---|---|---|---|
| MD5 | 否 | 1 | 否 | 绝不使用 |
| SHA-256 | 否 | 1 | 否 | 绝不用作密码哈希 |
| bcrypt | 是 | 可配置 | 否 | 推荐 |
| scrypt | 是 | 可配置 | 是 | 推荐 |
| Argon2 | 是 | 可配置 | 是 | 最佳选择 |
| PBKDF2 | 是 | 可配置 | 否 | 可接受 |
9. DECISION TREE
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哈希相关挑战 — 当前场景是什么?
│
├─ 持有H(secret || message),需要扩展消息?
│ ├─ 哈希算法是MD5/SHA1/SHA256/SHA512?
│ │ └─ 是 → 长度扩展攻击
│ │ └─ 需要:MAC值、原始消息、密钥长度
│ │ └─ 工具:HashPump 或 hash_extender
│ │
│ └─ 哈希算法是SHA3/HMAC/BLAKE2?
│ └─ 长度扩展攻击不生效
│ └─ 查找其他漏洞
│
├─ 需要两个哈希相同的输入?
│ ├─ 是MD5?
│ │ ├─ 相同前缀 → fastcoll(秒级)
│ │ ├─ 不同前缀 → hashclash(小时级)
│ │ └─ CTF PHP弱类型比较 → 0e魔法哈希
│ │
│ ├─ 是SHA-1?
│ │ └─ SHAttered(成本高,优先使用预计算结果)
│ │
│ └─ 是SHA-256及以上?
│ └─ 无实用碰撞攻击
│ └─ 转而查找逻辑漏洞
│
├─ 需要伪造HMAC?
│ ├─ 存在时序侧信道?
│ │ └─ 逐字节时序攻击
│ │
│ ├─ 密钥短/弱?
│ │ └─ 用hashcat暴力破解密钥
│ │
│ └─ 无漏洞?
│ └─ HMAC是安全的 — 查找其他方向
│
├─ 哈希被截断(输出较短)?
│ └─ 生日攻击 — 2^(位数/2)次尝试即可碰撞
│
├─ 工作量证明?
│ └─ 并行计算暴力破解
│ ├─ <28位用Python多进程
│ ├─ >28位用hashcat/GPU
│ └─ 优化:预增量字符串,避免重复编码
│
└─ 密码哈希破解?
├─ 无盐 → 彩虹表(预计算)
├─ 已知盐 → hashcat / John the Ripper
└─ 内存硬加密(Argon2/scrypt) → 受内存限制,暴力破解速度慢10. TOOLS
10. 工具
| Tool | Purpose | Usage |
|---|---|---|
| HashPump | Length extension attack | |
| hash_extender | Length extension (multiple algorithms) | |
| fastcoll | MD5 identical-prefix collision | |
| hashclash | MD5 chosen-prefix collision | |
| hashcat | Password/hash cracking (GPU) | |
| John the Ripper | Password cracking (CPU/GPU) | |
| CyberChef | Quick hash computation and encoding | Web-based |
| 工具 | 用途 | 用法 |
|---|---|---|
| HashPump | 长度扩展攻击 | |
| hash_extender | 长度扩展攻击(支持多种算法) | |
| fastcoll | MD5相同前缀碰撞 | |
| hashclash | MD5选择前缀碰撞 | |
| hashcat | 密码/哈希破解(GPU加速) | |
| John the Ripper | 密码破解(CPU/GPU) | |
| CyberChef | 快速哈希计算与编码 | 网页版工具 |