密码学博客:AES-CBC 比特翻转(Bit Flipping)攻击原理、实战与防御

📅 2026/7/3 1:41:07 👁️ 阅读次数 📝 编程学习
密码学博客:AES-CBC 比特翻转(Bit Flipping)攻击原理、实战与防御

一、前言

AES-CBC 是 Web、CTF 中最常见的分组加密模式之一,相比 ECB 解决了明文重复密文重复的缺陷,但CBC 仅提供机密性,不自带完整性校验。比特翻转攻击正是利用 CBC 解密的异或链式特性,在不知道密钥的前提下篡改解密后的明文,常用于越权登录、修改交易金额、绕过身份校验等攻击场景,是 Web 密码安全必考漏洞。

二、AES-CBC 核心加解密公式(攻击根基)

AES 分组长度固定 128bit(16 字节),记:

  • K:加密密钥(攻击者未知)
  • IV:初始向量,第一块解密的前置 “虚拟密文块”
  • \(P_i\):第 i 块明文
  • \(C_i\):第 i 块密文
  • \(D(K, C)\):AES 解密函数(不可逆、黑盒)

1. 加密公式

\(C_i = E(K,\ P_i \oplus C_{i-1})\) \(C_0 = IV\),第一块明文与 IV 异或后加密。

2. 解密公式(攻击核心)

\(P_i = D(K,\ C_i) \oplus C_{i-1}\)关键结论: 当前明文块 \(P_i\) 由两部分异或得到:密文块 \(C_i\) 的解密结果、前一块密文 \(C_{i-1}\)。 \(D(K,C_i)\) 由密钥和 \(C_i\) 决定,攻击者无法控制;但攻击者可以自由修改 \(C_{i-1}\),从而精准控制 \(P_i\) 的每一个字节 / 比特。

三、比特翻转攻击数学推导

设原始明文:\(P_i = D(C_i) \oplus C_{i-1}\) 攻击者目标:将 \(P_i\) 篡改至目标明文 \(P_i'\)

  1. 变形:\(D(C_i) = P_i \oplus C_{i-1}\)
  2. 代入目标等式:

\(\begin{align*} P_i' &= D(C_i) \oplus C_{i-1}' \\ P_i' &= (P_i \oplus C_{i-1}) \oplus C_{i-1}' \end{align*}\)

  1. 求解需要修改的前置密文 \(C_{i-1}'\): \(C_{i-1}' = C_{i-1} \oplus P_i \oplus P_i'\)

两种攻击场景

  1. 修改第一块明文 \(P_1\)\(P_1 = D(C_1) \oplus IV\),修改IV:\(IV' = IV \oplus P_1 \oplus P_1'\)
  2. 修改第 \(i(i>1)\) 块明文 \(P_i\)修改前一块密文 \(C_{i-1}\),公式同上;修改后 \(C_{i-1}\) 对应块解密会全部乱码,但不影响我们关心的 \(P_i\)。

攻击必须满足的 4 个前置条件

  1. 攻击者可获取完整密文 + IV(Cookie、URL 参数、响应返回);
  2. 知晓原始明文对应位置的原始字符(可注册、回显、源码泄露);
  3. 攻击者能提交篡改后的密文 / IV给服务端解密;
  4. 服务端无完整性校验(无 MAC、无 HMAC、不用 GCM/CCM 认证加密)。

四、实战 Python 完整 POC 演示

环境依赖

bash

运行

pip install pycryptodome

场景设定

服务端加密用户身份明文:user=guest&role=user,我们要把role=user改为role=admin,实现权限提升。 AES-128-CBC,16 字节分组。

python

运行

from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad import base64 # 全局密钥(攻击者未知,仅服务端持有) KEY = b"1234567890abcdef" BLOCK_SIZE = 16 def aes_cbc_encrypt(plain: bytes, iv: bytes) -> tuple[bytes, bytes]: cipher = AES.new(KEY, AES.MODE_CBC, iv) ciphertext = cipher.encrypt(pad(plain, BLOCK_SIZE)) return iv, ciphertext def aes_cbc_decrypt(iv: bytes, cipher: bytes) -> bytes: cipher = AES.new(KEY, AES.MODE_CBC, iv) return unpad(cipher.decrypt(cipher), BLOCK_SIZE) # ===================== 1. 原始加密流程 ===================== origin_plain = b"user=guest&role=user" iv, cipher = aes_cbc_encrypt(origin_plain, b"abcdef1234567890") print(f"原始明文:{origin_plain.decode()}") print(f"原始IV:{iv.hex()}") print(f"原始密文:{cipher.hex()}\n") # ===================== 2. 攻击计算 ===================== # 定位:"role=user" 位于第二明文块,需要修改第一块密文 cipher[0:16] # 原始目标段:b"user",目标修改为 b"admin" offset = len(b"user=guest&role=") # 偏移到待修改位置 origin_byte = b"user" target_byte = b"admin" delta = bytes([o ^ t for o, t in zip(origin_byte, target_byte)]) cipher_arr = bytearray(cipher) # 修改前一块密文对应字节 for i in range(len(delta)): cipher_arr[offset + i] ^= delta[i] # ===================== 3. 解密验证攻击结果 ===================== new_cipher = bytes(cipher_arr) result_plain = aes_cbc_decrypt(iv, new_cipher) print(f"篡改后解密明文:{result_plain.decode()}")

输出效果

plaintext

原始明文:user=guest&role=user 原始IV:61626364656631323334353637383930 原始密文:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 篡改后解密明文:user=guest&role=admin

成功将普通用户权限提升为管理员,全程未使用密钥,仅篡改密文字节。

IV 篡改简化示例(单块明文攻击)

若明文仅 1 块,直接修改 IV 即可:

python

运行

# 原始明文:username=test,目标 username=admin origin_p = b"username=test" target_p = b"username=admin" delta = bytes(a ^ b for a,b in zip(origin_p, target_p)) new_iv = bytes(iv_byte ^ delta_byte for iv_byte, delta_byte in zip(iv, delta))

五、真实安全场景攻击案例

案例 1:CTF Web Cookie 越权

网站登录后返回加密 Cookie:base64(IV + Cipher),解密内容为uid=100&is_admin=0

  1. 已知原始明文is_admin=0
  2. 计算翻转量将0改为1
  3. 修改前一块密文对应字节,重编码 Cookie 发包;
  4. 服务端解密得到is_admin=1,获取管理员页面权限。

案例 2:金融交易金额篡改

支付接口加密订单明文:pay=100&to=Bob,攻击者修改密文,将金额100翻转为9999,伪造大额转账。

案例 3:参数过滤绕过

后端过滤明文不能包含admin,但攻击者先用合法明文xdmin获取密文,通过 IV 翻转将首字符x改为a,解密后出现admin绕过黑名单。

六、比特翻转攻击与填充预言机(Padding Oracle)区分

表格

维度Bit Flipping 比特翻转Padding Oracle 填充预言机
攻击目的篡改已有明文内容完整爆破未知明文
前置条件已知原始明文完全未知明文
依赖特性异或链式可控修改PKCS7 填充错误信息泄露
是否需要错误回显不需要,只需观察业务逻辑变化必须区分填充正常 / 异常报错
攻击成本极低,单次计算即可高,逐字节爆破

七、安全防御方案(生产环境必做)

1. 最优方案:直接使用认证加密模式(推荐)

放弃纯 AES-CBC,使用自带机密性 + 完整性的标准模式:

  • AES-GCM(主流 Web、接口首选)
  • AES-CCM、ChaCha20-Poly1305 这类模式会校验密文完整性,任何字节篡改直接解密失败,从根源杜绝比特翻转攻击。

2. 坚持 CBC 模式时:增加独立完整性校验

加密流程:密文 = AES-CBC(明文) + HMAC(IV+密文)解密流程:

  1. 先校验 HMAC 签名,校验失败直接丢弃密文;
  2. 校验通过后再执行 AES 解密。 推荐哈希:SHA256/SHA3,签名密钥与加密密钥分离。

3. 开发规范红线

  1. 禁止将 IV、密文直接暴露在 URL、Cookie、前端存储;
  2. IV 必须密码学安全随机生成(os.urandom,不可写死、不可自增);
  3. 解密前统一校验长度、签名,不直接信任用户可控密文;
  4. 禁止业务逻辑依赖未校验的解密明文。

4. 误区避坑

  • ❌ 仅增加明文过滤:攻击者翻转密文后绕过过滤;
  • ❌ 仅加长密钥长度:AES-256-CBC 依然存在翻转漏洞,密钥长度不解决完整性问题;
  • ❌ 自定义简单校验(长度、关键词):极易绕过,必须密码学签名。

八、总结

  1. 比特翻转攻击的本质是CBC 解密的异或依赖关系:修改前置密文 / IV,精准控制当前明文;
  2. 攻击核心公式:\(C_{i-1}' = C_{i-1} \oplus P_{origin} \oplus P_{target}\),无需破解 AES 密钥;
  3. 漏洞根源:CBC 只保证加密不可读,无内置防篡改机制
  4. 生产环境唯一根治方案:使用 AES-GCM 等认证加密,拒绝裸 CBC 上线。

拓展阅读

  1. PentesterLab CBC Bit Flipping 靶场
  2. NIST SP 800-38D GCM 模式标准文档
  3. CTF CBC 填充预言机与字节翻转复合利用