mcpField
S
symmetric-cipher-attacks

symmetric-cipher-attacks

github.com/yaklangセキュリティ2.6k3.6k 回インストール6 週間前に更新
リポジトリ

symmetric-cipher-attacks について

CTFや許可されたテスト向けの暗号解析スキルです。対称暗号やストリーム暗号の攻撃手法を扱い、観測できる挙動をパディングオラクルやECBの攻撃などに結び付けます。

主な機能

  1. 01CBCパディングオラクル攻撃とビットフリッピング
  2. 02ECBのパターン検出と攻撃
  3. 03ストリーム暗号の鍵再利用とXORの分析
  4. 04LFSR、LCG、RC4の弱点を扱う
  5. 05ミートインザミドル攻撃の解説

活用シーン

  1. 01パディングオラクルが露出した環境での暗号文復号
  2. 02入力を制御できるECB暗号化の評価
  3. 03ストリーム鍵再利用が疑われる暗号文の分析
  4. 04予測可能なLFSRまたはLCG生成器の状態復元

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/yaklang/hack-skills --skill symmetric-cipher-attacks

インストール後、Claude Code で/symmetric-cipher-attacksを入力して読み込まれたか確認します。

同梱ファイルBLOCK_CIPHER_ATTACKS.md

詳細

SKILL:共通鍵暗号攻撃 — 専門家向け暗号解読プレイブック

AI LOAD INSTRUCTION:CTF および許可を得たテストで共通鍵暗号を攻撃するための専門的な手法です。CBC パディングオラクル、CBC ビットフリッピング、ECB の検出と悪用、ストリーム暗号の鍵再利用、LFSR/LCG の状態復元、RC4 のバイアス、ミートインザミドル攻撃を扱います。ベースモデルは、ECB と CBC の攻撃戦略を混同したり、バイト単位の ECB 復号を正しく設定できなかったりすることがよくあります。

0. 関連するルーティング

高度なリファレンス

以下が必要な場合は、BLOCK_CIPHER_ATTACKS.md も読み込んでください。

  • Python の完全な実装を含む詳細な攻撃スクリプト
  • バイト単位の ECB 復号の手順を追った解説
  • PadBuster の使用方法とカスタムパディングオラクルスクリプト
  • LCG/LFSR の復元実装
攻撃方法のクイック選択
観測可能な動作考えられる脆弱性攻撃
同じ平文 → 同じ暗号文(ブロック境界に整列)ECB モードカットアンドペースト/バイト単位
パディングエラーを識別できるCBC パディングオラクル鍵なしで復号
暗号文を変更でき、次のブロックに影響するCBC モード、完全性チェックなしビットフリッピング
XOR/ストリーム暗号で鍵が再利用されている二回使用パッド暗号文同士を XOR
予測可能な PRNG 出力LCG または LFSR状態復元
二重暗号化が使われている2DES 型ミートインザミドル

1. パディングオラクル攻撃(CBC モード)

1.1 仕組み

CBC 復号:P_i = D_K(C_i) ⊕ C_{i-1}

サーバーがパディングが有効かどうか(PKCS#7)を明らかにする場合、直前の暗号文ブロックを操作することで任意のブロックを復号できます。

1.2 攻撃手順
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 実装
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 ツール
# 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 ビットフリッピング

2.1 概念

C_{i-1} の位置 j のビットを反転すると、P_i の同じ位置 j のビットが反転します(また、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 実践例
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 モード攻撃

3.1 検出
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 カットアンドペースト

暗号文ブロックを並べ替えて、新しい有効な平文を作成します。

Original blocks:
  Block 0: "[email protected]"
  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 = "[email protected]\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 = "[email protected]"
  → Block 2 = "=user&uid=10..."  (but we replace this)

Step 3: Replace last block with saved "admin\x0b..." block
3.3 バイト単位の ECB 復号

追加された未知のシークレットを、一度に 1 バイトずつ復号します。

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. ストリーム暗号攻撃

4.1 既知平文/鍵の再利用(二回使用パッド)
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 1 バイト XOR の総当たり
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 繰り返し鍵 XOR(カシスキ法に類似)
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 の状態復元(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 のバイアス
バイアス説明悪用方法
初期バイトのバイアスP(K[0] = 0) ≈ 2/256(通常の 2 倍)最初のバイトの統計的な平文復元
Fluhrer-Mantin-ShamirIV を伴う弱い鍵スケジューリングWEP 攻撃(歴史的)
NOMORE 攻撃キーストリームの長期的なバイアスTLS/RC4 の平文復元(2^24-2^26 個の暗号文)
不変性の弱点ストリーム全体にわたる鍵依存のバイアス多数の暗号化に対する統計的攻撃

5. ミートインザミドル

5.1 二重暗号化攻撃
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. 判断ツリー

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. ツール

ツール用途
PadBusterパディングオラクルの自動悪用
xortool繰り返し鍵 XOR の分析(鍵長の検出+解読)
CyberChef手軽な XOR、エンコード、ブロック暗号操作
SageMathLFSR/LCG の分析、格子ベースの復元
pycryptodomeテスト用の AES/DES 実装
hashcat共通鍵の総当たり(GPU による高速化)
Custom Python上記すべての攻撃は純粋な Python で実装可能

コメント