Athena Wiki

CBC Attacks

cryptointermediate

Exploit AES-CBC vulnerabilities - bit flipping, IV=Key recovery, and padding oracle chaining.

cryptoaescbcbit-flipivpadding-oracledecryption

CBC Attacks

AES-CBC (Cipher Block Chaining) chains blocks by XORing each plaintext block with the previous ciphertext block before encryption. This introduces vulnerabilities that ECB doesn't have.

What is CBC?

  • Cipher Block Chaining (CBC) is a mode that adds chaining between blocks: before encrypting each plaintext block the system XORs it with the previous ciphertext block (or the IV for the first block). This means each ciphertext block depends on all previous plaintext blocks, not just the block itself.

Why this matters

  • Changes to one block affect the next block's decryption, enabling both protections and attack surfaces (e.g., bit-flipping and padding oracles).
  • Unlike ECB, CBC hides repeated patterns across equal plaintext blocks, but incorrect use (predictable IVs, reused IVs, lack of authentication) introduces CTF-relevant vulnerabilities.
Modes of Operation
Modes of Operation - CBC Encryption
Modes of Operation
Modes of Operation - CBC Decryption

CBC Math Review

Encrypt:

C0=AESK(P0IV)Ci=AESK(PiCi1),i1\begin{aligned} C_0 &= \mathrm{AES}_K(P_0 \oplus \mathrm{IV}) \\ C_i &= \mathrm{AES}_K(P_i \oplus C_{i-1}), \quad i \ge 1 \end{aligned}

Decrypt:

P0=AESK1(C0)IVPi=AESK1(Ci)Ci1,i1\begin{aligned} P_0 &= \mathrm{AES}_K^{-1}(C_0) \oplus \mathrm{IV} \\ P_i &= \mathrm{AES}_K^{-1}(C_i) \oplus C_{i-1}, \quad i \ge 1 \end{aligned}

Notation (quick reference)

  • P_i: Plaintext block number i (16 bytes / 128 bits for AES).
  • C_i: Ciphertext block number i (16 bytes / 128 bits).
  • K: Symmetric key used for AES encryption/decryption.
  • IV: Initialization Vector - a non-secret, typically random 16-byte value used to randomize encryption of the first block.
  • AES_K(...): AES block encryption under key K (encrypts a single 16-byte block).
  • AES_K^-1(...): AES block decryption under key K (the inverse operation of AES_K).

Attack 1: Bit Flipping

Goal: Change a specific byte in P[i] by modifying C[i-1].

Since Pi=AESK1(Ci)Ci1P_i = \mathrm{AES}_K^{-1}(C_i) \oplus C_{i-1}, flipping a bit in Ci1C_{i-1} flips the corresponding bit in PiP_i.

# Example: Change P[1][6] from 'X' (0x58) to 'Y' (0x59)
ciphertext = bytearray(oracle_encrypt(plaintext))

target_block = 0      # modify C[0] to affect P[1]
target_byte  = 6      # byte position within the block

# original_value ⊕ desired_value = bit to flip
ciphertext[target_block * 16 + target_byte] ^= ord('X') ^ ord('Y')
# (If you know the plaintext byte at that position)

# Or if you don't know the original:
# Set: C[i-1][j] ^= known_P[i][j] ^ desired_P[i][j]  (XOR adjustment)

CTF application: If admin=0 is in P[1] and you can modify C[0]:

ct = bytearray(encrypt(b"A" * 16 + b"admin=0;role=user"))
# C[0] is the "A" * 16 block (our controlled padding)
# P[1] starts with "admin=0"
pos_of_0 = 16 + 6  # C[0][6] affects P[1][6]
ct[pos_of_0] ^= ord('0') ^ ord('1')  # change '0' to '1'
submit(bytes(ct))

Attack 2: IV = Key Recovery

If the IV equals the key (a common implementation mistake):

When IV=K\mathrm{IV} = K:

P0=AESK1(C0)KP_0 = \mathrm{AES}_K^{-1}(C_0) \oplus K

Craft C=C00128C0C' = C_0 \,\|\, 0^{128} \,\|\, C_0. With IV=K\mathrm{IV}=K, decrypting gives P0P2=K=IVP'_0 \oplus P'_2 = K = \mathrm{IV} (128-bit / 16-byte blocks).

def recover_iv_equals_key(oracle_encrypt, oracle_decrypt, block_size=16):
    # Encrypt any 3-block plaintext
    pt = b'A' * (block_size * 3)
    ct = oracle_encrypt(pt)

    C0 = ct[:block_size]
    C1 = ct[block_size:2*block_size]
    C2 = ct[2*block_size:3*block_size]

    # Craft: C0 || 0...0 || C0
    crafted = C0 + b'\x00' * block_size + C0

    # Decrypt and XOR P'[0] with P'[2]
    pt_prime = oracle_decrypt(crafted)
    P0 = pt_prime[:block_size]
    P2 = pt_prime[2*block_size:3*block_size]

    key = bytes(a ^ b for a, b in zip(P0, P2))
    return key

Attack 3: IV Manipulation

If the IV is user-controlled or predictable, you can control P[0]:

# P[0] = AES_K^{-1}(C[0]) ⊕ IV
# To set P[0] = desired: IV' = AES_K^{-1}(C[0]) ⊕ desired = P[0]_orig ⊕ IV_orig ⊕ desired

def craft_iv(original_iv, original_p0, desired_p0):
    return bytes(a ^ b ^ c for a, b, c in zip(original_iv, original_p0, desired_p0))

Attack 4: Padding Oracle (recap)

See Padding Oracle for the full attack. In brief:

# If oracle reveals valid/invalid padding:
# 1. Modify C[i-1] to control P[i] via CBC relationship
# 2. Find byte values that produce valid PKCS#7 padding
# 3. Use padding values to recover intermediate state
# 4. XOR with C[i-1] to get P[i]

Common CTF CBC Scenarios

ScenarioAttack
Encrypt with IV=0, change IVIV manipulation
admin=false in position you controlBit-flip attack
IV sent with ciphertext to clientModify IV → control P[0]
Padding error revealed in responsePadding oracle
IV reused with same keyKnown-plaintext recovery


Last updated on

On this page