前言
一直对模板注入似懂非懂的,打算在这篇文章中深入的研究一下模板注入以及在ctf中bypass的办法。
Learning
什么是模板&模板注入
小学的时候拿别人的好词好句,套在我们自己的作文里,此时我们的作文就相当于模板,而别人的好词好句就相当于传递进模板的内容。
那么什么是模板注入呢,当不正确的使用模板引擎进行渲染时,则会造成模板注入,比如:
from flask import Flask
from flask import request
from flask import config
from flask import render_template_string
app = Flask(__name__)
app.config['SECRET_KEY'] = "flag{SSTI_123456}"
@app.route('/')
def hello_world():
return 'Hello World!'
@app.errorhandler(404)
def page_not_found(e):
template = '''
{%% block body %%}
Oops! That page doesn't exist.
%s
{%% endblock %%}
''' % (request.args.get('404_url'))
return render_template_string(template), 404
if __name__ == '__main__':
app.run(host='0.0.0.0',debug=True)
网上大部分所使用的request.url的方式已经不能导致模板注入了,在最新的flask版本中会自动对request.url进行urlencode,所以我稍微改了一下代码,改成request.args传参就可以了。
在上述代码中,直接将用户可控参数request.args.get('404_url')在模板中直接渲染并传回页面中,这种不正确的渲染方法会产生模板注入(SSTI)。
可以看到,页面直接传回了0而不是{ {1-1}}。
How2use
在Python的ssti中,大部分是依靠基类->子类->危险函数的方式来利用ssti,接下来讲几个知识点。
__class__
万物皆对象,而class用于返回该对象所属的类,比如某个字符串,他的对象为字符串对象,而其所属的类为。
__bases__
以元组的形式返回一个类所直接继承的类。
__base__
以字符串返回一个类所直接继承的类。
__mro__
返回解析方法调用的顺序。
__subclasses__()
获取类的所有子类。
__init__
所有自带带类都包含init方法,便于利用他当跳板来调用globals。
__globals__
function.__globals__,用于获取function所处空间下可使用的module、方法以及所有变量。
在看完上边这些自带方法、成员变量后,可能有点懵,接下来看看是如何利用这些方法以及成员变量达到我们想要的目的的。
在SSTI中,我们要做的无非就两个:
执行命令
获取文件内容
所以我们所做的一切实际上都是在往这两个结果靠拢。
测试代码:
# -*- coding:utf8 -*-
from flask import Flask
from flask import request
from flask import config
from flask import render_template_string
app = Flask(__name__)
app.config['SECRET_KEY'] = "flag{SSTI_123456}"
@app.route(