skip to content

What property of SSL 3.0's CBC padding let POODLE recover one plaintext byte at a time?

level: middleimportance: must knowfreq 55%

answer

  1. padding appended after the MAC
  2. contents unspecified, only the length byte
  3. nothing for the receiver to compare
  4. final block made entirely of padding
  5. accepted about one try in 256

basics

~20 s

SSL 3.0 defines only the last padding byte, the padding length, and leaves the other padding bytes free, so a receiver cannot verify them. POODLE builds records whose final block is entirely padding, and acceptance confirms a guess.

solid answer

~50 s

In an SSL 3.0 CBC record the MAC is computed over the message and the padding is appended afterwards, and — unlike TLS 1.0 and later — the specification fixes only the final padding byte, which carries the padding length. The other padding bytes may hold anything, so a conforming receiver strips them by length and has nothing to compare. POODLE (`CVE-2014-3566`) exploits that: the attacker shifts the request until a block containing the target plaintext byte is positioned usefully, makes the record's final block entirely padding, and substitutes the target ciphertext block into that final position. The receiver accepts the record only when the decrypted final byte happens to equal the full-block padding length, about once in 256 attempts, and acceptance reveals the plaintext byte by a simple XOR relation. Repeating recovers a byte at a time.

code

pseudocode · 13 lines
pseudocode
on CBC record decrypted:
    pad_len = last plaintext byte

    # TLS 1.0 and later
    for each of the pad_len bytes before the length byte:
        if byte is not equal to pad_len:
            reject with bad_record_mac(20)

    # SSL 3.0
    # those bytes are unspecified, so there is no comparison to make;
    # pad_len is used only to decide how many bytes to strip

    strip pad_len + 1 bytes, then verify the MAC over what remains

go deeper

for a junior

Remember that SSL 3.0 lets the padding bytes hold anything except the final length byte, so the receiver has nothing to verify, and that this is what killed the version.

for a middle

Explain the two facts that combine: the padding sits outside the MAC, and its contents are undefined. Then show that accept-or-reject becomes a per-byte oracle.

for a senior

Demonstrate the operational reading: the attack needs a path position plus influence over request content, recovers a byte at a time, and is closed only by refusing the version, not by configuration.

for a principal

Take the design lesson: any field a receiver cannot verify becomes an input to someone else's search, so a protocol should leave no accept-or-reject decision resting on unauthenticated bytes.

## What SSL 3.0 says about padding, and what it does not A CBC record has to be a whole number of cipher blocks long, so padding is appended before encryption. Two facts about **SSL 3.0** (`RFC 6101`) combine into the break: 1. The MAC is computed over the message; the padding is appended afterwards and is therefore not covered by it. That alone is not unusual. 2. SSL 3.0 defines the **contents** of the padding only for the final byte, which carries the padding length. The bytes before it are unspecified and may hold anything. The second point is the one that matters. Because any content is legal, any content must be accepted. A receiver reads the last byte, strips that many padding bytes plus the length byte, and verifies the MAC over what remains. There is no padding check, because there is nothing to check against. **TLS 1.0 and later** (`RFC 5246` for TLS 1.2) closed this by defining every padding byte to carry the padding length value, so the receiver has a concrete expectation and rejects a mismatch with `bad_record_mac(20)` — deliberately the same alert as a MAC failure, so the two cases are not distinguishable from outside. ## What POODLE does with it The attacker needs two capabilities that are ordinary in a browser-shaped setting and are also reachable in any environment where a client can be induced to send attacker-influenced content on an authenticated connection: they must be able to influence part of each request, and they must be able to observe and modify the resulting records. The steps: 1. **Position the target.** By adjusting the length of the attacker-controlled prefix, the secret byte of interest is moved so that it sits as the last byte of some cipher block. Call that block's ciphertext `C[i]`. 2. **Make the final block all padding.** By adjusting the length of the attacker-controlled suffix, the record is arranged so that its last cipher block consists entirely of padding. In that case its final byte — the padding length — equals `block_size - 1`. 3. **Substitute.** The attacker replaces the record's final ciphertext block with `C[i]` and forwards the record. 4. **Read the verdict.** The receiver decrypts the substituted final block as `decrypt(C[i]) XOR C[final - 1]`, takes its last byte as the padding length, and strips that many bytes. It accepts the record only when that byte happens to equal `block_size - 1`. If it does not, the MAC fails and the connection is torn down; the attacker retries with the request shifted. When the record is accepted, the attacker knows the decrypted final byte was `block_size - 1`, and the CBC relation gives the plaintext byte directly: `plaintext_byte = (block_size - 1) XOR last_byte(C[final - 1]) XOR last_byte(C[i - 1])` One byte in 256 guesses. Repeat with the target shifted by one position and the next byte falls out. ## Why the acceptance signal exists at all The attacker never reads any plaintext. The only thing observed is whether the connection survived the modified record. That single bit is enough because the receiver's decision depends on a secret-derived value. This is what makes the SSL 3.0 rule fatal rather than merely untidy: an unverifiable field turns a pass/fail response into a per-byte guessing device. ## Why the version had to go A deployment that wanted to keep SSL 3.0 and avoid POODLE would have to stop negotiating CBC suites with it. That leaves the stream ciphers, and of SSL 3.0's stream ciphers only RC4 remained in use — prohibited by `RFC 7465`. With both options closed, there is no safe configuration, which is why `RFC 7568` prohibits SSL 3.0 and prohibits falling back to it from any version of TLS. ## What differs across versions | | SSL 3.0 | TLS 1.0 and later | |---|---|---| | padding contents | only the final length byte defined | every byte carries the padding length | | receiver's check | strip by length; nothing to compare | compare each padding byte against the length | | failure reported as | MAC failure only | `bad_record_mac(20)` for both padding and MAC errors | | consequence | an accept/reject signal keyed on a secret | no signal from the padding alone | ## Reading the result in an audit The honest summary for an operator is short: the attack needs an attacker positioned on the path who can also influence request content, it recovers a byte at a time rather than a key, and it is closed permanently by refusing to negotiate the version. There is no configuration of SSL 3.0 that survives it, and no patched build of any implementation that helps, because a conforming receiver has to accept the padding the attacker sends.

  • Why is a padding error in TLS 1.2 reported with the same alert as a MAC failure?
    So the two cases are indistinguishable from outside. If a receiver answered differently for bad padding and bad content, the difference itself would be a signal an attacker could query. `RFC 5246` has both reported as `bad_record_mac(20)`, and implementations are expected to spend the same work either way.
  • What does the attacker actually learn from a single modified record?
    One bit: whether the connection survived. No plaintext is read. That bit is useful only because the receiver's decision depends on a secret-derived byte, which is why an unverifiable field is more than an aesthetic defect.
  • Could a deployment have kept SSL 3.0 by restricting it to stream ciphers?
    No. Of SSL 3.0's stream ciphers only RC4 remained in use, and RC4 is prohibited by `RFC 7465`. With CBC broken by the padding rule and the stream alternative prohibited, nothing safe was left, which is the reasoning `RFC 7568` records.

A sealed envelope where the wax seal covers the letter but not the packing stuffed around it: the packing can be swapped for anything and the seal still checks out.

saying these in an interview costs you the question

  • Thinks the record MAC covers the CBC padding
  • Says the attack recovers the session key
  • Believes the attacker reads the plaintext directly
  • Claims a fixed implementation could reject the padding
  • Says the same flaw applies to TLS 1.2 unchanged