symmetric-cipher-attacks
yaklang/hack-skills
Exploit symmetric cipher weaknesses: padding oracle, ECB cut-and-paste, bit flipping, stream cipher key reuse, and meet-in-the-middle attacks.
What is symmetric-cipher-attacks?
Expert cryptanalysis playbook for attacking symmetric encryption in CTF and authorized testing. Covers CBC padding oracle attacks, ECB mode exploitation, stream cipher key reuse, and LFSR/LCG state recovery. Use when you need to break block cipher modes, detect and exploit ECB, or recover keys from weak PRNGs.
- Decrypt CBC-encrypted data via padding oracle attacks without the key
- Detect ECB mode and perform cut-and-paste or byte-at-a-time decryption attacks
- Flip specific bits in CBC plaintext by modifying ciphertext blocks
- Recover plaintext from stream ciphers with key reuse (two-time pad)
- Recover LFSR/LCG internal state and predict future outputs
- Execute meet-in-the-middle attacks against double encryption schemes
How to install symmetric-cipher-attacks
npx skills add https://github.com/yaklang/hack-skills --skill symmetric-cipher-attacks- Python 3.6+ with pycryptodome or similar crypto library
- Understanding of block cipher modes (ECB, CBC, CTR) and padding schemes (PKCS#7)
- Access to an oracle function (padding validation endpoint, decryption service, or encryption endpoint)
- For LFSR/LCG attacks: familiarity with linear algebra or lattice reduction tools
How to use symmetric-cipher-attacks
- 1.Identify the cipher mode and weakness (ECB detection, padding oracle endpoint, bit flipping opportunity, or key reuse)
- 2.Select the appropriate attack from the playbook based on the observable behavior
- 3.Implement or adapt the provided Python code for your target (oracle function, block size, ciphertext format)
- 4.Execute the attack iteratively (byte-by-byte for ECB, block-by-block for padding oracle) to recover plaintext or key
- 5.Verify results and adjust parameters (block size, byte position, guess range) if needed
Use cases
- Decrypt CBC ciphertext by exploiting a padding oracle endpoint in a web application
- Extract admin credentials from ECB-encrypted cookies by reordering ciphertext blocks
- Modify encrypted authentication tokens in CBC mode to escalate privileges without knowing the key
- Break stream cipher encryption when the same key is used twice with different plaintexts
- Recover the internal state of a predictable PRNG used for key generation
- CTF competitors exploiting cryptographic vulnerabilities
- Security researchers performing authorized penetration testing on legacy encryption systems
- Cryptanalysts analyzing cipher implementations for weaknesses
- Bug bounty hunters finding encryption flaws in web applications
symmetric-cipher-attacks FAQ
Send repeated plaintext blocks (e.g., 48 'A's) and check if the ciphertext contains identical blocks. ECB encrypts identical plaintext blocks to identical ciphertext blocks; CBC and CTR will not.
Optimize by caching oracle responses, parallelizing guesses across multiple connections, or using tools like PadBuster which implement efficient batching. For rate-limited targets, consider offline attacks if you can capture multiple ciphertexts.
No. GCM includes authentication (AEAD), so bit flipping and padding oracle attacks fail. These attacks work on unauthenticated modes (ECB, CBC, CTR without authentication). Always check if the target uses authenticated encryption.
Collect consecutive LFSR outputs and set up a system of linear equations over GF(2). Use Gaussian elimination or lattice reduction (LLL) to solve for the internal state, then predict future outputs.
Meet-in-the-middle attacks double encryption (e.g., 2DES) by precomputing all possible intermediate values for half the key space, then matching them against decryptions of the ciphertext. Use when key size is small enough (e.g., 2^56 for 2DES) to precompute.
Full instructions (SKILL.md)
Source of truth, from yaklang/hack-skills.
name: symmetric-cipher-attacks description: >- Symmetric cipher attack playbook. Use when exploiting block cipher mode weaknesses (CBC padding oracle, ECB cut-and-paste, bit flipping), stream cipher key reuse, or meet-in-the-middle attacks.
SKILL: Symmetric Cipher Attacks — Expert Cryptanalysis Playbook
AI LOAD INSTRUCTION: Expert techniques for attacking symmetric encryption in CTF and authorized testing. Covers CBC padding oracle, CBC bit flipping, ECB detection and exploitation, stream cipher key reuse, LFSR/LCG state recovery, RC4 biases, and meet-in-the-middle attacks. Base models often confuse ECB and CBC attack strategies or fail to set up byte-at-a-time ECB decryption correctly.
0. RELATED ROUTING
- rsa-attack-techniques when symmetric key is protected by RSA
- hash-attack-techniques when HMAC or hash-based authentication is involved
- lattice-crypto-attacks for LCG/LFSR state recovery via lattice methods
Advanced Reference
Also load BLOCK_CIPHER_ATTACKS.md when you need:
- Detailed attack scripts with full Python implementations
- Step-by-step byte-at-a-time ECB walkthrough
- PadBuster usage and custom padding oracle scripts
- LCG/LFSR recovery implementation
Quick attack selection
| Observable Behavior | Likely Weakness | Attack |
|---|---|---|
| Same plaintext → same ciphertext (block-aligned) | ECB mode | Cut-and-paste / byte-at-a-time |
| Padding error distinguishable | CBC padding oracle | Decrypt without key |
| Can modify ciphertext, affects next block | CBC mode, no integrity check | Bit flipping |
| Key reused with XOR/stream cipher | Two-time pad | XOR ciphertexts together |
| Predictable PRNG output | LCG or LFSR | State recovery |
| Double encryption used | 2DES-like | Meet in the middle |
1. PADDING ORACLE ATTACK (CBC MODE)
1.1 Mechanism
CBC decryption: P_i = D_K(C_i) ⊕ C_{i-1}
If the server reveals whether padding is valid (PKCS#7), we can decrypt any block by manipulating the previous ciphertext block.
1.2 Attack Steps
Target: decrypt block C_i (with unknown plaintext P_i)
For byte position b = 15 down to 0 (last byte first):
padding_value = 16 - b
For guess = 0x00 to 0xFF:
Construct modified C'_{i-1}:
- Bytes 0..b-1: original C_{i-1} bytes
- Byte b: guess
- Bytes b+1..15: calculated to produce correct padding
Send (C'_{i-1} || C_i) to oracle
If oracle says "valid padding":
intermediate_byte[b] = guess ⊕ padding_value
plaintext_byte[b] = intermediate_byte[b] ⊕ original_C_{i-1}[b]
1.3 Python Implementation
def padding_oracle_attack(ciphertext, block_size, oracle):
"""
oracle(ct) returns True if padding is valid, False otherwise.
ciphertext includes IV as first block.
"""
blocks = [ciphertext[i:i+block_size] for i in range(0, len(ciphertext), block_size)]
plaintext = b""
for block_idx in range(1, len(blocks)):
prev_block = bytearray(blocks[block_idx - 1])
curr_block = blocks[block_idx]
intermediate = [0] * block_size
decrypted = [0] * block_size
for byte_pos in range(block_size - 1, -1, -1):
padding_val = block_size - byte_pos
for guess in range(256):
modified = bytearray(block_size)
modified[byte_pos] = guess
for j in range(byte_pos + 1, block_size):
modified[j] = intermediate[j] ^ padding_val
test_ct = bytes(modified) + curr_block
if oracle(test_ct):
if byte_pos == block_size - 1:
# Verify it's not a false positive (padding 0x02 0x02)
check = bytearray(modified)
check[byte_pos - 1] ^= 1
if not oracle(bytes(check) + curr_block):
continue
intermediate[byte_pos] = guess ^ padding_val
decrypted[byte_pos] = intermediate[byte_pos] ^ prev_block[byte_pos]
break
plaintext += bytes(decrypted)
return plaintext
1.4 Tools
# PadBuster
padbuster http://target/decrypt?ct= CIPHERTEXT_HEX 16 -encoding 0
padbuster http://target/decrypt?ct= CIPHERTEXT_HEX 16 -encoding 0 -plaintext "admin=true"
2. CBC BIT FLIPPING
2.1 Concept
Flipping bit at position j in C_{i-1} flips the same bit at position j in P_i (and corrupts all of P_{i-1}).
Original: P_i[j] = D_K(C_i)[j] ⊕ C_{i-1}[j]
Modified: P'_i[j] = D_K(C_i)[j] ⊕ C'_{i-1}[j]
= P_i[j] ⊕ (C_{i-1}[j] ⊕ C'_{i-1}[j])
2.2 Practical Example
def cbc_bitflip(ciphertext, block_size, target_byte_pos, old_value, new_value):
"""
Flip byte in plaintext block N+1 by modifying ciphertext block N.
target_byte_pos: absolute position in plaintext (0-indexed)
"""
ct = bytearray(ciphertext)
block_num = target_byte_pos // block_size
byte_in_block = target_byte_pos % block_size
# Modify previous block (block_num - 1) to flip target byte
modify_pos = (block_num - 1) * block_size + byte_in_block
# XOR to cancel old value and set new value
ct[modify_pos] ^= old_value ^ new_value
return bytes(ct)
# Example: flip "admin=0" to "admin=1"
# If "admin=0" is at byte position 22 (block 1, byte 6):
modified_ct = cbc_bitflip(ciphertext, 16, 22, ord('0'), ord('1'))
3. ECB MODE ATTACKS
3.1 Detection
def detect_ecb(ciphertext, block_size=16):
"""ECB produces identical blocks for identical plaintext blocks."""
blocks = [ciphertext[i:i+block_size] for i in range(0, len(ciphertext), block_size)]
return len(blocks) != len(set(blocks))
# Force detection: send repeated plaintext
test_input = b"A" * 48 # at least 3 blocks of identical data
# If response has repeated blocks → ECB
3.2 ECB Cut-and-Paste
Reorder ciphertext blocks to create new valid plaintexts.
Original blocks:
Block 0: "email=foo@bar.c"
Block 1: "om&role=user&uid"
Block 2: "=10\x0d\x0d\x0d..."
Attack: craft input so "admin" + padding lands in its own block,
then swap it in place of "user" block.
Step 1: Send email that aligns "admin" + PKCS7 to a block:
email = "foo@bar.coadmin\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
→ Block 1 encrypts "admin\x0b\x0b..." (save this block)
Step 2: Send email that puts "role=" at end of block:
email = "foo@bar.co"
→ Block 2 = "=user&uid=10..." (but we replace this)
Step 3: Replace last block with saved "admin\x0b..." block
3.3 Byte-at-a-Time ECB Decryption
Decrypt unknown appended secret one byte at a time.
def ecb_byte_at_a_time(encrypt_oracle, block_size=16):
"""
encrypt_oracle(input_bytes) = AES_ECB(input || unknown_secret)
Returns the unknown_secret.
"""
secret = b""
secret_len = len(encrypt_oracle(b""))
for i in range(secret_len):
block_num = i // block_size
pad_len = block_size - 1 - (i % block_size)
padding = b"A" * pad_len
# Build lookup table
target_ct = encrypt_oracle(padding)
target_block = target_ct[block_num * block_size:(block_num + 1) * block_size]
for byte_val in range(256):
test_input = padding + secret + bytes([byte_val])
test_ct = encrypt_oracle(test_input)
test_block = test_ct[block_num * block_size:(block_num + 1) * block_size]
if test_block == target_block:
secret += bytes([byte_val])
break
return secret
4. STREAM CIPHER ATTACKS
4.1 Known Plaintext / Key Reuse (Two-Time Pad)
def two_time_pad(c1, c2, known_crib=None):
"""
c1 = m1 ⊕ K, c2 = m2 ⊕ K (same key K)
c1 ⊕ c2 = m1 ⊕ m2 (key cancels)
"""
xored = bytes(a ^ b for a, b in zip(c1, c2))
if known_crib:
results = []
for offset in range(len(xored) - len(known_crib) + 1):
candidate = bytes(
xored[offset + i] ^ known_crib[i] for i in range(len(known_crib))
)
if all(0x20 <= b <= 0x7e for b in candidate):
results.append((offset, candidate))
return results
return xored
4.2 Single-Byte XOR Brute Force
def single_byte_xor_crack(ciphertext):
"""Brute force single-byte XOR key using frequency analysis."""
english_freq = {
'e': 12.7, 't': 9.1, 'a': 8.2, 'o': 7.5, 'i': 7.0,
'n': 6.7, 's': 6.3, 'h': 6.1, 'r': 6.0, 'd': 4.3,
}
best_score, best_key, best_plaintext = 0, 0, b""
for key in range(256):
plaintext = bytes(b ^ key for b in ciphertext)
score = sum(
english_freq.get(chr(b).lower(), 0)
for b in plaintext if 0x20 <= b <= 0x7e
)
if score > best_score:
best_score = score
best_key = key
best_plaintext = plaintext
return best_key, best_plaintext
4.3 Repeating-Key XOR (Kasiski-like)
def repeating_xor_crack(ciphertext, max_keylen=40):
"""Crack repeating-key XOR using Hamming distance for key length."""
def hamming(a, b):
return sum(bin(x ^ y).count('1') for x, y in zip(a, b))
# Find key length
scores = []
for kl in range(2, max_keylen + 1):
blocks = [ciphertext[i:i+kl] for i in range(0, len(ciphertext) - kl, kl)]
if len(blocks) < 4:
continue
dist = sum(hamming(blocks[i], blocks[i+1]) for i in range(min(3, len(blocks)-1)))
normalized = dist / (min(3, len(blocks)-1) * kl)
scores.append((normalized, kl))
best_keylen = sorted(scores)[0][1]
# Crack each position with single-byte XOR
key = b""
for i in range(best_keylen):
column = bytes(ciphertext[j] for j in range(i, len(ciphertext), best_keylen))
k, _ = single_byte_xor_crack(column)
key += bytes([k])
return key
4.4 LFSR State Recovery (Berlekamp-Massey)
def berlekamp_massey_gf2(output_bits):
"""Recover LFSR feedback polynomial from output sequence over GF(2)."""
n = len(output_bits)
C = [0] * (n + 1)
B = [0] * (n + 1)
C[0] = B[0] = 1
L = 0
m = 1
b = 1
for N in range(n):
d = output_bits[N]
for i in range(1, L + 1):
d ^= C[i] & output_bits[N - i]
if d == 0:
m += 1
elif 2 * L <= N:
T = C[:]
for i in range(m, n + 1):
C[i] ^= B[i - m]
L = N + 1 - L
B = T
b = d
m = 1
else:
for i in range(m, n + 1):
C[i] ^= B[i - m]
m += 1
return C[:L + 1], L
4.5 RC4 Biases
| Bias | Description | Exploitation |
|---|---|---|
| Initial byte bias | P(K[0] = 0) ≈ 2/256 (double normal) | Statistical plaintext recovery for first bytes |
| Fluhrer-Mantin-Shamir | Weak key scheduling with IV | WEP attack (historical) |
| NOMORE attack | Long-term biases in keystream | TLS/RC4 plaintext recovery (2^24-2^26 ciphertexts) |
| Invariance weakness | Key-dependent biases throughout stream | Statistical attack on many encryptions |
5. MEET-IN-THE-MIDDLE
5.1 Double Encryption Attack
Double encryption: C = E_K2(E_K1(P))
Brute force: 2^(2n) expected
MITM: 2^(n+1) + storage for 2^n entries
Attack:
1. Encrypt P with all possible K1 → store (E_K1(P), K1) in table
2. Decrypt C with all possible K2 → check if D_K2(C) matches any entry
3. Match found → (K1, K2) recovered
from itertools import product
def meet_in_the_middle(encrypt, decrypt, plaintext, ciphertext, keyspace_bits):
"""MITM attack on double encryption."""
# Phase 1: build encryption table
enc_table = {}
for k1 in range(2**keyspace_bits):
intermediate = encrypt(plaintext, k1)
enc_table[intermediate] = k1
# Phase 2: decrypt and look up
for k2 in range(2**keyspace_bits):
intermediate = decrypt(ciphertext, k2)
if intermediate in enc_table:
k1 = enc_table[intermediate]
return k1, k2
return None
6. DECISION TREE
Symmetric cipher challenge — what can you observe?
│
├─ Can you detect the mode?
│ ├─ Repeated input → repeated output blocks?
│ │ └─ Yes → ECB mode
│ │ ├─ Can control prefix → byte-at-a-time decryption
│ │ ├─ Can reorder blocks → cut-and-paste
│ │ └─ Can detect block boundaries → block alignment oracle
│ │
│ ├─ Error message differs for bad padding?
│ │ └─ Yes → Padding oracle (CBC)
│ │ └─ PadBuster or custom script
│ │
│ └─ Can modify ciphertext and observe effect?
│ └─ Next-block plaintext changes → CBC bit flipping
│
├─ Stream cipher or XOR?
│ ├─ Key reused on different messages?
│ │ └─ XOR ciphertexts → crib drag
│ │
│ ├─ Known plaintext-ciphertext pair?
│ │ └─ Recover keystream directly
│ │
│ ├─ Single-byte XOR key?
│ │ └─ Brute force 256 keys with frequency analysis
│ │
│ ├─ Repeating-key XOR?
│ │ └─ Hamming distance → key length → per-position crack
│ │
│ └─ LFSR-based?
│ └─ Berlekamp-Massey for state/polynomial recovery
│
├─ PRNG-based cipher?
│ ├─ LCG → truncated output lattice attack
│ ├─ Mersenne Twister → 624 outputs → full state recovery
│ └─ Custom PRNG → analyze period and state size
│
├─ Double / triple encryption?
│ └─ Meet-in-the-middle
│
└─ RC4 specifically?
├─ Single encryption → initial byte bias
├─ Many encryptions same key → statistical attack
└─ IV prepended to key → FMS attack (WEP-like)
7. TOOLS
| Tool | Purpose |
|---|---|
| PadBuster | Automated padding oracle exploitation |
| xortool | Repeating-key XOR analysis (key length detection + cracking) |
| CyberChef | Quick XOR, encoding, block cipher operations |
| SageMath | LFSR/LCG analysis, lattice-based recovery |
| pycryptodome | AES/DES implementation for testing |
| hashcat | Brute force symmetric keys (GPU-accelerated) |
| Custom Python | All attacks above implementable in pure Python |
Related skills
More from yaklang/hack-skills and the wider catalog.

traffic-analysis-pcap
Expert PCAP forensics and network traffic analysis with Wireshark, tshark, and protocol-specific techniques.

tunneling-and-pivoting
Expert SSH, Chisel, Ligolo-ng, socat, DNS/ICMP/HTTP tunneling and multi-layer pivoting playbook.

type-juggling
Exploit PHP weak comparison (`==`) and magic hashes to bypass authentication and token validation.

unauthorized-access-common-services
Exploit unauthenticated management services (Redis, Rsync, PHP-FPM, AJP, Hadoop YARN, H2) for RCE and data theft.

upload-insecure-files
Test file upload validation, storage, processing chains, and access control for bypass and exploitation paths.

vm-and-bytecode-reverse
Reverse engineer custom VMs and bytecode interpreters in CTF challenges and protected software.