一、漏洞简述🍺
1、SSTI(Server-Side Template Injection,服务器端模板注入)指的是一种攻击技术,攻击者通过向服务器发送恶意代码,从而在服务器端执行任意代码并获取敏感信息,SSTI攻击通常发生在服务器端模板渲染引擎中,攻击者在模板中注入恶意代码,从而导致服务器端执行该代码
2、SSTI攻击的目标通常是使用模板引擎的Web应用程序,例如Flask、Django、Jinja2等,攻击者可以利用这些模板引擎的弱点,将恶意代码注入到模板中,然后将其发送到服务器执行
3、常见的SSTI攻击载荷如:
- {{7*7}}:将会输出49,则存在SSTI
- {{config}}:将会输出服务器端的配置信息
二、flask模板注入🍺
1、不同框架有不同的渲染模板
2、如:flask支持使用Jinja2来作为渲染引擎
- Flask是一个Python Web框架,它使用Werkzeug工具箱和Jinja2模板引擎,它被设计成易于扩展和灵活的,并且可以很好地处理小到大的Web应用程序
- Jinja2是一个Python模板引擎,它允许你以灵活和安全的方式构建HTML页面
3、flask的渲染方法有render_template和render_template_string两种,其中render_template_string则是用来渲染一个字符串的,SSTI与这个方法密不可分
三、shrine(攻防世界)🍺
1、弄个环境理清一下思路,开启环境访问,即发现一段源代码,Flask 框架
import flask
import os
app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')
@app.route('/')
def index():
return open(__file__).read()
@app.route('/shrine/')
def shrine(shrine):
def safe_jinja(s):
s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
return flask.render_template_string(safe_jinja(shrine))
if __name__ == '__main__':
app.run(debug=True)
2、路由作用
route装饰器的作用是将函数与url绑定,如代码中就是当你访问http://61.147.171.105:57667/shrine
的时候,flask会执行shrine函数
3、对代码简单分析
(1)、将环境变量中的FLAG值存储到应用程序对象的配置中,然后从环境变量中移除FLAG值:
app.config['FLAG'] = os.environ.pop('FLAG')
(2)、定义/shrine/路由处理函数,使用safe_jinja函数处理输入的模板字符串shrine,然后渲染模板并返回结果
s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
使用replace方法替换掉字符串中的左右括号,设置黑名单过滤config、self字符
最后一行代码负责将黑名单的东西遍历并设为空,即进行过滤
(3)、在Jinja模板语言中,{{…}}用于表示需要被替换的变量或执行的表达式,而{%…%}用于表示控制流语句,比如if、for、set等,因此,{{%…%}}就是将控制流语句转义,表示这部分内容不需要被替换,将控制流语句转义,即是使用{{%…%}}可以将一段Python代码作为字符串输出,而不会被解释器当成控制流语句执行,这样可以方便在模板中使用包含了Python语法的代码段
在这个代码中,{{% set {}=None%}}是用于定义一个变量,表示将黑名单中的变量设置为None,从而防止黑客利用这些变量进行注入攻击
(4)、就是将过滤后的变量进行渲染HTML页面并返回
return flask.render_template_string(safe_jinja(shrine))
4、操作过程
在/shrine/
目录下执行
由于黑名单的过滤,我们输入config
的值为None
为了获取信息,可以读取例如current_app
这样的全局变量,python的沙箱逃逸这里的方法是利用python对象之间的引用关系来调用被禁用的函数对象
,有两个函数包含了current_app
全局变量,url_for
和get_flashed_messages
利用{{url_for.__globals__}}
注入
出现了**current_app**
变量,**{{url_for.__globals__['current_app']}}**
**app**
变量为Flask应用程序实例
然后注入当前**app**
的**config**
,**{{url_for.__globals__['current_app'].config}}**
成功找到**flag**
利用**get_flashed_messages
**注入的方法同步
同时,Flask的所有接口文档可参考:API — 烧瓶文档 (1.1.x) (palletsprojects.com)
参考学习文章:
四、SSTI注入绕过🍺
1、出现以下情况的;
- 过滤了敏感字符,如
**eval**
,**os
**等 - 过滤了中括号**
[]
、引号'
、"
** - 过滤双下划线
**__**
- 删除built下的一些函数,不能执行命令存在
- 过滤了
**{{**
参考文章:SSTI注入绕过(沙盒逃逸原理一样) - 冬泳怪鸽 - 博客园 (cnblogs.com)
2、常见不同模板引擎的姿势
(1)、Smarty模板引擎,PHP
(2)、Twig模板引擎,PHP
(3)、JinJa模板引擎,Python
(4)、Django框架,Python
(5)、Tornado框架,Pyhon
参考文章:SSTI模板注入 | Err0r的小站
3、还有经典