news 2026/5/26 10:13:16

[CTF] 从CBC模式到权限窃取:字节翻转攻击实战剖析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[CTF] 从CBC模式到权限窃取:字节翻转攻击实战剖析

1. 从登录框到管理员权限:CBC字节翻转攻击全景解析

想象你正在参加一场CTF比赛,眼前是一个普通的登录页面。系统提示"只有admin能看到flag",但尝试用admin登录时却显示"admin禁止登录"。这种看似矛盾的场景背后,往往隐藏着加密算法的漏洞。AES-CBC模式下的字节翻转攻击,正是破解这类谜题的金钥匙。

我第一次遇到这种场景是在三年前的某次实战中。当时目标系统使用PHP的openssl_encrypt函数,采用AES-128-CBC模式加密用户凭证。通过分析发现,虽然前端禁止admin登录,但后端却通过解密cookie中的身份信息来验证权限。这种加密验证机制的设计缺陷,为字节翻转攻击创造了完美条件。

2. CBC模式工作原理与漏洞根源

2.1 AES-CBC的加密解密流程

CBC(Cipher Block Chaining)模式就像工厂的流水线:每个明文块在加密前,都要与前一个密文块进行XOR混合。第一块明文则与IV(初始化向量)混合。这种链式结构使得每个密文块都依赖于之前的所有块。

具体加密过程分五步:

  1. 将明文按16字节分块,不足部分用PKCS#7填充
  2. 生成随机IV和密钥
  3. 第一块明文与IV异或后加密
  4. 后续每块明文与前一块密文异或后加密
  5. 最终输出IV+全部密文块

解密则是逆向操作:

def decrypt_block(cipher, key, prev_cipher): decrypted = aes_decrypt(cipher, key) return xor(decrypted, prev_cipher)

2.2 致命弱点:密文可控性

CBC模式的核心漏洞在于:攻击者可以通过修改前一个密文块,直接影响下一个明文块的解密结果。这是因为解密时的XOR操作是可逆的——如果我们知道原始明文和期望明文,就能精确计算出需要修改的密文字节。

举个例子:

原明文块2 = decrypt(密文块2) XOR 密文块1 期望明文块2 = decrypt(密文块2) XOR 修改后的密文块1 => 修改后的密文块1 = 密文块1 XOR 原明文块2 XOR 期望明文块2

3. 实战攻击步骤拆解

3.1 目标分析与定位

以文中CTF题目为例,登录后服务器返回两个Cookie:

  • iv:Base64编码的初始化向量
  • cipher:Base64编码的序列化用户数据

通过分析PHP代码发现关键逻辑:

$info = unserialize(openssl_decrypt($cipher, METHOD, KEY, OPENSSL_RAW_DATA, $iv)); if($info['username'] === 'admin') { echo $flag; }

攻击目标很明确:修改密文使得解密后的username变为admin,同时保证其他数据完整。

3.2 精确计算字节偏移

首先用普通用户(如admix)登录,获取原始密文。序列化后的数据格式为:

a:2:{s:8:"username";s:5:"admix";s:8:"password";s:3:"123";}

分组情况(每16字节一组):

|----Block1----| |----Block2----| |----Block3----| a:2:{s:8:"userna me";s:5:"admix"; s:8:"password";s :3:"123";}

要修改的是第二块的"x"变为"n",该字符位于整个明文的第(16+9)=25字节,对应第二块的第9字节。

3.3 实施字节翻转

根据公式计算新密文:

original_char = 'x' target_char = 'n' block_index = 1 # 第二块 byte_offset = 9 # 获取原始密文块 cipher_blocks = [cipher[i:i+16] for i in range(0, len(cipher), 16)] prev_block = bytearray(cipher_blocks[block_index-1]) # 计算修改值 prev_block[byte_offset] ^= ord(original_char) ^ ord(target_char) new_cipher = cipher_blocks[0] + bytes(prev_block) + cipher_blocks[2]

此时解密后的第二块明文已变为"admin",但第一块因密文被修改会出现乱码。

3.4 IV修复技术

为了修复第一块乱码,需要重新计算IV:

# 已知损坏的第一块明文 damaged_plaintext = decrypt_block(cipher_blocks[0], key, iv)[:16] # 原始第一块明文 original_plaintext = b'a:2:{s:8:"userna' # 计算新IV new_iv = bytes([iv[i] ^ damaged_plaintext[i] ^ original_plaintext[i] for i in range(16)])

4. 完整攻击脚本实现

结合上述步骤,自动化攻击脚本如下:

import base64 import urllib.parse from Crypto.Cipher import AES def xor(a, b): return bytes([x^y for x,y in zip(a,b)]) def decrypt_block(cipher, key, iv): cipher_obj = AES.new(key, AES.MODE_CBC, iv) return cipher_obj.decrypt(cipher) # 原始数据 original_cookie = "w1uvgfzxxuYHA%2Bo08ZL%2BCefhwr2jHuwglOIBAh8cP1w5TCiCmY0Yy%2BQxelAl9%2B%2FiZeRvLD7UjzlF58bTGFZ%2BWQ%3D%3D" original_iv = "1HxERxo2%2FTuymbrPoVDB%2Bw%3D%3D" # 解码并分块 cipher = base64.b64decode(urllib.parse.unquote(original_cookie)) iv = base64.b64decode(urllib.parse.unquote(original_iv)) blocks = [cipher[i:i+16] for i in range(0, len(cipher), 16)] # 修改第1块的13字节(第二块的'e'改'a') modified_block1 = bytearray(blocks[0]) modified_block1[13] ^= ord('x') ^ ord('n') modified_cipher = bytes(modified_block1) + blocks[1] + blocks[2] # 修复IV first_block_plain = decrypt_block(blocks[0], KEY, iv) target_plain = b'a:2:{s:8:"userna' new_iv = xor(xor(iv, first_block_plain), target_plain) # 输出结果 print("Modified cipher:", urllib.parse.quote(base64.b64encode(modified_cipher))) print("New IV:", urllib.parse.quote(base64.b64encode(new_iv)))

5. 防御方案与最佳实践

5.1 认证架构设计缺陷

案例中的根本问题在于信任客户端提供的加密数据。正确的做法应该是:

  • 在服务端存储会话状态
  • 如果必须使用加密cookie,应添加HMAC签名
  • 避免将用户权限信息直接放在可解密的数据中

5.2 具体防护措施

  1. 加密+认证组合
$cipher = openssl_encrypt($data, METHOD, $key, 0, $iv); $hmac = hash_hmac('sha256', $iv.$cipher, $key); setcookie('auth', base64_encode($iv.$hmac.$cipher));
  1. 使用认证加密模式: 直接采用GCM或CCM等提供完整性和机密性的模式。

  2. 固定IV方案: 对于给定用户使用派生IV(如HMAC-SHA256(user_id)),避免随机IV被篡改。

6. 深入理解攻击本质

字节翻转攻击之所以有效,源于三个关键因素:

  1. 密文可控:攻击者能获取并修改加密数据
  2. 错误传播特性:CBC模式只影响当前块和下一块
  3. 业务逻辑依赖:系统信任解密后的数据完整性

在真实渗透测试中,这种攻击常出现在:

  • 加密的JWT令牌
  • 会话cookie
  • API请求参数
  • 客户端存储的敏感数据

我曾在一个电商系统的优惠券系统中发现类似漏洞,通过修改加密后的金额参数,实现了优惠券面值的任意调整。这再次证明,任何依赖客户端加密数据的业务逻辑都需要严格验证。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/26 10:13:11

Python运算符深度解析:从字节码到重载的底层逻辑

1. Python 运算符:不只是“ - * /”,而是程序逻辑的底层齿轮你刚学 Python 时,大概率是从print(2 3)开始的。那一刻,你没意识到自己正亲手拨动计算机最底层的逻辑开关——运算符不是语法糖,不是教学示例里的装饰品&am…

作者头像 李华
网站建设 2026/5/26 10:08:58

30分钟掌握AlphaPose:从零开始构建实时多人姿态检测系统

30分钟掌握AlphaPose:从零开始构建实时多人姿态检测系统 【免费下载链接】AlphaPose Real-Time and Accurate Full-Body Multi-Person Pose Estimation&Tracking System 项目地址: https://gitcode.com/gh_mirrors/al/AlphaPose 想要在30分钟内快速上手一…

作者头像 李华
网站建设 2026/5/26 10:08:04

MATLAB图形标注实战:从基础函数到交互式图例的进阶指南

1. MATLAB图形标注基础入门 第一次用MATLAB画图的时候,我盯着屏幕上那几条光秃秃的曲线发愁——这玩意儿拿给导师看肯定要被骂。后来才发现,图形标注就像给照片加滤镜,能把原始数据变成专业图表。咱们从一个简单例子开始:假设你要…

作者头像 李华
网站建设 2026/5/26 10:07:50

Unity URP真机调试:三指双击启用Runtime Rendering Debugger

1. 这个“三指双击”不是玄学,是URP渲染调试的物理开关 你有没有在真机上跑着一个Unity URP项目,画面突然发灰、阴影错位、后处理失效,或者更糟——某个特效在编辑器里好好的,一打包到手机上就彻底消失?这时候你翻遍Lo…

作者头像 李华
网站建设 2026/5/26 10:07:49

一键激活Windows与Office:KMS_VL_ALL_AIO智能脚本完全指南

一键激活Windows与Office:KMS_VL_ALL_AIO智能脚本完全指南 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO KMS_VL_ALL_AIO是一款功能强大的Windows和Office智能激活脚本工具&#xf…

作者头像 李华
网站建设 2026/5/26 10:06:01

系统QPS提高了,应该怎么办?

某天突然被问到系统QPS提高了,应该怎么办?我答道:首先考虑系统设计,比如系统的设计是否符合实际的需求,具体可以从微服务架构等方面考虑。然后就是接口的响应时间是否能满足需求。还有就是系统的数据库设计是否需要做调…

作者头像 李华