探究Flask/Jinja2中的服务端模版注入(二)
在探究Flask/Jinja2中的服务端模版注入Part1中,我开端的方针是找到文件的途径或许说是进行文件体系拜访。之前还无法达到这些方针,可是感谢朋友们在之前文章中的反应,现在我现已可以完成这些方针了。本文就来讲讲进一步研讨取得的成果。
神助攻
关于之前的文章,感谢Nicolas G 对咱们的协助
假如你有玩玩这个payload,你很快就会清楚这是行不通的。这儿有有几个比较合理的解说,之后我会简略给咱们说说。要害是这个payload运用了多个之前咱们疏忽了但十分重要的内省实用程序:__mro__以及__subclasses__特点
免喷声明:以下的解说或许会存在少许生涩,我真实没兴趣把自己搞的十分通晓啥的,就这水平了。大多数时分我在处理结构/语言中存在的模糊不清的部分,我都会测验看是否可以带给我预期的作用,但我一向不知道会发生这种作用的缘由。我依旧在学习这些特点背面躲藏着的“为什么”,但我至少想将我知道的共享给咱们!
__mro__中的MRO(Method Resolution Order)代表着解析办法调用的次序,可以看看Python文档中的介绍。它是每个方针元类的一个躲藏特点,当进行内省时会疏忽dir输出(see Objects/object.c at line 1812)
__subclasses__特点在这儿作为一种办法被界说为,对每个new-style class“为它的直接子类保持一个弱引证列表”,之后“回来一个包含一切存活引证的列表”。
简略来说,__mro__答应咱们在当时Python环境中追溯方针承继树,之后__subclasses__又让咱们回到原点。从一个new-style object开端,例如str类型。运用__mro__咱们可以从承继树爬到根方针类,之后在Python环境中运用__subclasses__爬向每一个new-style object。ok,这让咱们可以拜访加载到当时Python环境下的一切类,那么咱们该怎样运用这一新发现愉快的游玩呢?
运用
这儿咱们还要考虑一些东西,Python环境或许会包含:
源于Flask运用的东西
方针运用自界说的一些东西
因为咱们是想取得一个通用exploit,所以测验环境越挨近原生Flask越好。越向运用中增加库和第三方模块,那咱们能取得通用exploit的概率就越低。咱们之前进行概念验证时运用的那个运用就是一个十分不错的挑选。
为了挖掘出一枚exploit向量,要求不修正方针源代码。在前一篇文章中,为了进行内省,咱们向存在缝隙的运用中增加了一些函数,但现在这些通通都不需要了。
首要咱们要做的榜首件事就是挑选一个new-style object用于拜访object基类。可以简略的运用'',一个空字符串,str方针类型。之后咱们可以运用__mro__特点拜访方针的承继类。将{{ ''.__class__.__mro__ }}作为payload注入到存在SSTI缝隙的页面中
咱们可以看到之前讨论过的元组现在正向咱们反应,因为咱们想追溯根方针类,咱们运用第二条索引挑选object类类型。现在咱们正坐落根方针,可以运用__subclasses__特点dump一切存在于运用程序中的类,将{{ ''.__class__.__mro__[2].__subclasses__() }}注入到SSTI缝隙中。
如你所看到的,这儿面的信息太多了。在我运用的这个方针App中,这儿有572个可拜访类。这事情变得有些扎手了,这也是为什么上面推特中说到的payload行不通的原因了。记住,并不是每个运用的Python环境都差不多。咱们的方针是找到一个可以让咱们拜访文件或许操作体系的东西。或许不那么简单在一个运用中找到相似subprocess.Popen模块从而取得一枚exploit,例如受前文Twitter上附有的那个payload影响的运用。可是从我的发现来看,没有什么可以比得上原生Flask。幸亏,在原生Flask下咱们也可以完成相似的作用。
假如你整理之前payload的输出信息,你应该可以找到类,它是文件体系拜访的要害。尽管open是创立文件方针的内置函数,file类也是有才能罗列文件方针的,假如咱们可以罗列一个文件方针,之后咱们可以运用相似read办法来提取内容。为了证明这一点,找到file类的索引并注入{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }},其间的40是环境中类的索引。
片面上咱们现已证明了在Flask/Jinja2结构下运用SSTI是可以读取文件的,咱们废了这么多时刻莫非仅仅这样?今日我的方针是长途代码/指令履行!
在前一篇文章中我引证了config方针的几个办法将方针加载到Flask装备环境中。其间一种办法就是from_pyfile,以下为from_pyfile办法的代码(flask/config.py)
def from_pyfile(self, filename, silent=False):
"""Updates the values in the config from a Python file. This function
behaves as if the file was imported as module with the
:meth:`from_object` function.
:param filename: the filename of the config. This can either be an
absolute filename or a filename relative to the
[1] [2] 黑客接单网