- Decrypt any ciphertext without knowing the key
- Encrypt any chosen plaintext (forge ciphertext)
Prerequisites
- Target uses AES-CBC (or another CBC mode cipher) with PKCS#7 padding
- The system exposes a padding validity signal after decryption:
- Different HTTP status codes (
200 OKvs500 Internal Server Error) - Different response bodies (“Invalid padding” vs “Incorrect MAC”)
- Timing difference between valid and invalid padding
- Different HTTP status codes (
How the attack works
CBC decryption reminder
D[i] = Decrypt(C[i]) (the raw block cipher output). Then:
C[i-1] (the previous ciphertext block) and can query the oracle controls what P[i] decrypts to.
Recovering one byte
To recover the last byte ofP[i]:
- Send a modified ciphertext where the last byte of
C[i-1]is replaced with a guessg. - If the oracle returns “valid padding”, the last byte of
P[i]is\x01(single-byte valid PKCS#7). - Therefore:
D[i][15] XOR g = 0x01, soD[i][15] = g XOR 0x01. - Recover the original plaintext byte:
P[i][15] = D[i][15] XOR C[i-1][15].
Recovering the full block
Repeat for each byte position, right to left. For positionj (counting from the right, starting at 1):
- Fix all previously recovered bytes: set them so they decrypt to the target padding value
j. - Brute-force the next byte until the oracle signals valid padding.
Encryption forgery
By reversing the decryption process you can also encrypt arbitrary plaintext:- Choose a target plaintext
P'and pad it. - Starting from the last block and working backwards, determine the
C[i-1]values that will produce valid decryptedP'[i]. - The final computed
C[-1]becomes the IV.
Practical tooling
PadBuster
PadBuster automates the attack against web targets.padbuster (Python)
Manual exploit with pycryptodome
Real-world examples
POODLE — SSLv3 CBC padding oracle (CVE-2014-3566)
POODLE — SSLv3 CBC padding oracle (CVE-2014-3566)
SSLv3 uses a non-deterministic padding scheme and performs MAC-then-encrypt. An attacker who can inject chosen blocks into a TLS session can exploit the padding validation to recover plaintext cookies, one byte at a time (256 requests per byte on average).Mitigation: disable SSLv3 and TLS 1.0; use TLS 1.2+ with AEAD ciphers.
ASP.NET ViewState padding oracle (2010, MS10-070)
ASP.NET ViewState padding oracle (2010, MS10-070)
ASP.NET encrypted ViewState with AES-CBC and returned a generic error page when padding was invalid. Researchers demonstrated full decryption and code execution via crafted ViewState tokens.Mitigation: Microsoft added a
customErrors requirement and later deprecated CBC-based ViewState encryption.Performance
For a 16-byte AES block, the worst case is 256 queries per byte × 16 bytes = 4096 queries per block. In practice the average is ~128 per byte, or ~2048 per block. Multi-threading or binary search on the oracle can significantly reduce this.Defences
| Defence | Notes |
|---|---|
| Use AEAD (AES-GCM, ChaCha20-Poly1305) | Integrity check prevents oracle queries from being useful |
| Constant-time padding check | Removes timing oracle; check MAC first, padding second |
| Encrypt-then-MAC | MAC is verified before decryption — invalid ciphertexts are rejected before padding is checked |
| Uniform error responses | Never distinguish padding errors from MAC errors in server responses |