前言
今天碰到一道需要SSTI注入的题,百度了一下,发现大多数关于SSTI的基础文章上下文的连贯性并不是很好,于是便有了此文。
在阅读此文前,我假设您已具有Python和Html基础.
什么是SSTI(服务器模板注入)
SSTI 即服务端模板注入攻击,服务端接受用户输入,将其作为 Web 应用模板的一部分渲染编译后执行了恶意内容,导致敏感信息泄露,代码执行等.(与Xss原理大致相似)
什么是Flask
Flask是一个用Python编写的Web应用程序框架.它由Armin Ronacher 开发,他领导一个名为Pocco的国际Python爱好者团队.Flask基于Werkzeug WSGI工具包和Jinja2模板引擎.两者都是Pocco项目.
一个Flask应用是如何跑起来的
运行虚拟环境:
Flask是运行在虚拟环境(VirtualEnv)中的,VirtualEnv是一个虚拟的Python环境构建器。它可以帮助用户并行创建多个Python环境.因此,它可以避免不同版本的库之间的兼容性问题.(最好不要使用python3.8运行,以减少不兼容的可能性)
pip install virtualenv
virtualenv venv
cd ./venv/Scripts
activate.bat
如何跑起来:
先来看一个简单的小demo
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World' if __name__ == '__main__': app.run()
首先是导入flask框架,这是必须的.
Flask构造函数使用当前模块(__name __)的名称作为参数.
Flask类的route()函数是一个装饰器,它告诉应用程序哪个URL应该调用相关的函数.
app.route(rule, options)
rule参数代表该路径与哪个函数进行绑定.如上图中的小demo,@app.route(‘/’)是函数hello_world的装饰器,即代表网站的根路径与函数hello_world绑定,在访问http://127.0.0.1/的时候,就会触发函数hello_world.
最后,Flask类的run()方法在本地开发服务器的虚拟环境上运行应用程序
Flask模板
Flask模板的基本使用
在项目下创建 templates 文件夹,用于存放所有模板文件,并在目录下创建一个模板文件 html 文件 hello.html
在env这个虚拟环境中,render_template()这个函数会自动寻找在同级目录下templates文件夹下的文件.
也就是说render_template(‘hello.html’)等价于render_template(‘./templates/hello.html’)
模板变量(重点)
传入字符串到html模板中
在html模板中使用{{变量名}}的方法输出变量内容
在html模板中,{{}}之间的内容会被当做表达式进行执行,并将结果输出到页面上
一个存在SSTI漏洞的demo
在ctf中基于python开发的web,存在SSTI漏洞的一般都使用的是Jianja2模板引擎
什么是Jianja2引擎
Jinja2是Python下一个被广泛应用的模版引擎,他的设计思想来源于Django的模板引擎,并扩展了其语法和一系列强大的功能。.中最显著的一个是增加了沙箱执行功能和可选的自动转义功能.
注意这一句话,可选的自动转义功能,即默认不进行转义.这为我们进行SSTI注入创造了条件.
test.py
from flask import Flask, request from jinja2 import Template app = Flask(__name__) @app.route('/') def index(): id = request.args.get('id') t = Template(''' <html> <head> <title></title> </head> <body> <h1>%s</h1> </body> </html> ''' % (id)) return t.render() app.run()
表达式果然被执行了.
一个不存在SSTI漏洞的demo
test.py
from flask import Flask, request,render_template app = Flask(__name__) @app.route('/') def index(): id = request.args.get('id') return render_template('hello.html',id=id) app.run()
使用request对象,处理来自客户端url中id的数据.
request.args.get() 解析查询字符串的内容,它是问号(?)之后的URL的一部分。
html模板
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{id}} </body> </html>
flask中的render_plate函数会对变量内容进行转义,即输出原始字符串.所以不存在SSTI漏洞.
如何对存有SSTI漏洞的flask进行命令执行
这里一道简单的ctf练习题为例.你可能会疑惑,没有导入OS模块,也没有system()类似的函数怎么能进行命令执行呢?
命令执行的基本流程:获取基本类->获取基本类的子类->在子类中找到关于命令执行和文件读写的模块
获取基本类
我们都知道在python中一切皆为对象.
使用__bases__获取基本类
Python 为所有类都提供了一个 bases属性,通过该属性可以查看该类的所有直接父类,该属性返回所有直接父类组成的元组,注意是直接父类.
''.__class__.__bases__
可以看到str的父类是basestring
使用__mro__同样也可以查找父类,不同的是__mro__获取的是类的调用顺序
调用顺序依次是object->basestring->str
获取基本类的子类
”.__class__.__mro__[2].__subclasses__()
在子类中找到关于命令执行和文件读写的模块
在上图中我们要找到’os’ 所在的’site._Printer’类,它的索引为[71]
使用__subclasses__()[71].__init__.__globals__[‘os’].popen(‘cmd’).read(),运行命令并得到回显结果
总结
SSTI模板注入的漏洞好像并不太常见,以后遇到再更新吧。
来源:freebuf.com 2021-07-06 13:40:00 by: 菜头想学安全
请登录后发表评论
注册