1. 程式人生 > 實用技巧 >服務端模板注入攻擊 SSTI

服務端模板注入攻擊 SSTI

1. SSTI模板注入(Server-side template injection)
a. 伺服器模板注入是當攻擊者能夠用本地的模板語法去注入一個惡意的payload,然後再伺服器端執行改模板的攻擊手法。
b. 模板引擎使用過將固定模板與多邊資料結合起來生成的html網頁的一種技術,當用戶直接輸入資料到模板不做任何過濾額時,可能會發生服務端的模板注入攻擊,這使得攻擊者可以注入任何模板指令來操作伺服器模板引擎,從而使整個伺服器被控制。
顧名思義,伺服器模板注入和SQL注入大同小異,但SSTI是發生在伺服器端的,更加危險。
c. 伺服器模板注入的危害性往往取決於所使用的模板引擎以及應用程式的使用方式,很少有情況不會帶來真正的安全風險,但絕大多數情況下都是致命性的影響。最嚴重的的情況是攻擊者可以進行RCE(遠端程式碼執行),完全控制伺服器端,並進行內網攻擊;即使在無法完全進行RCE的情況下,攻擊者也能將SSTI和其他漏洞進行“組合拳”攻擊,比如可能讀取伺服器上的敏感檔案等。
2. 為什麼需要伺服器模板
a. 簡單來說,頁面上的資料需要不斷更新,即為渲染。後臺語言通過一些模板引擎生成HTML的過程。(常見的模板渲染引擎Jade,YAML)
b. 由於WebApplication最終都是要落實到HTMl、CSS、JavaScript等使用者介面上的,有一種情況是,每一個頁面都需要特殊的邏輯,隨著應用功能的增加,而彼此之間沒有同步。比如你更改了站點的佈局風格,那麼響應的就需要修改成百上千的HTMl檔案,顯然是十分複雜的。
c. 既然如此多的HTML具有一定的邏輯聯絡,何不使用程式碼生成程式碼。於是後端模板語言誕生了。分別有前端渲染和後端(伺服器)渲染,區別是後端渲染是將一些模板規範語言翻譯成如上三種語言回傳給前端;而前端渲染則是將整個生成邏輯程式碼全部回傳前端,再由客戶端生成使用者介面。
Eg:
前端

<html>
<head>
<title>{{title}}</title>
</head>
<body>
<form method="{{method}}" action="{{action}}">
<input type="text" name="user" value="{{username}}">
<input type="password" name="pass" value="">
<button type="submit">submit</button>
</form> <p>Used {{mikrotime(true) - time}}</p> </body> </html>

後端

$template Engine=new TempLate Engine() ;
$template=$template Engine-load File('login.tpl') ;
$template->assign('title', 'login') ;
$template->assign('method', 'post') ;
$template->assign('action
', 'login.php') ; $template->assign('username', get Username From Cookie() ) ; $template->assign('time', microtime(true) ) ; $template->show() ;

首先載入login.tpl模板檔案,然後對與模板中名稱相同的變數賦值(大括號裡的變數),然後呼叫show()函式,相應的替換它們
相應的HTML程式碼。
3. 漏洞原理
當用戶直接輸入資料到模板不做任何過濾,可能會發生服務端模板注入攻擊。使用PHP模板引擎Twing作為例子來說明,末班注入產生的原理。
<?php
…………
$output = $twig->render("Hello {{name}}", array("name" => $_GET["name"])); // 將使用者輸入作為模版變數的值
echo $output;
?>
使用Twing模板引擎渲染頁面,其中模板含有{{name}}變數,其模板變數值來自於GET請求引數,$_GET['name']。顯然這段程式碼並沒有什麼問題,其實你想通過name引數傳遞一段JavaScript程式碼給服務端進行渲染,但是由於模板引擎一般都預設對渲染的變數值進行編碼和轉義,所以並不會造成XSS

但是如果渲染的模板內容是使用者可以控制的,情況就不一樣了。修改程式碼為:

<?php
…………
$output = $twig->render("Hello {$_GET['name']}"); // 將使用者輸入作為模版內容的一部分
echo $output;
?>

上面這段程式碼帶構建模板時,拼接了使用者輸入作為模板的內容,現在如果傳入一段JavaScript程式碼,就會產生XSS問題。
4. 模板注入的檢測
a. 尋找SSTI漏洞需要程式碼審計或者直接黑盒引發報錯,最簡單的方法是通過注入模板表示式中常用的特殊字元來Fuzz,例如:$ {{<%[%'“}}%\。如果引發了報錯,則表明伺服器模板可能存在漏洞。SSTI漏洞通常發生在兩個不同的上下文中,所以要根據特定的上下文來進行Fuzz。
b. 例如,如下就是一個有漏洞的模板

<?php
$output = $twig->render("Hello {$_GET['name']}"); 
echo $output;
?>

在Twing模板引擎裡,{{var}}除了可以輸出傳遞的變數意外,還能執行一些基本的表示式然後將其結果作為改模板變數的值
例如
i. 這裡輸入name={{2*10}} http://127.0.0.1/ssti.php?name={{2*10}}
ii. 則服務端拼接模板的的內容為Hello {{2*10}};
iii. Twing模板引擎在編譯模板的過程中會計算{{2*10}}中的表示式2*10,會將其返回值 20 作為模板的變數值輸出,前端最終的返回內容為Hello 20
c.
i. 現在把測試的資料改變一下,插入一些正常字元和 Twig 模板引擎預設的註釋符,構造 Payload 為:
IsVuln{#comment#}{{2*8}}OK
ii. 實際服務端要進行編譯的模板就被構造為:
HelloIsVuln{#comment#}{{2*8}}OK
iii. 這裡簡單分析一下,由於 {# comment #} 作為 Twig 模板引擎的預設註釋形式,所以在前端輸出的時候並不會顯示,而 {{2*8}} 作為模板變數最終會返回 16 作為其值進行顯示,因此前端最終會返回內容 Hello IsVuln16OK
d. 通過上面連個簡單的示例,可以得到SSTI掃描檢測的大致流程(以Twing為例)

同常規的 SQL 注入檢測,XSS 檢測一樣,模板注入漏洞的檢測也是向傳遞的引數中承載特定 Payload 並根據返回的內容來進行判斷的。每一個模板引擎都有著自己的語法,Payload 的構造需要針對各類模板引擎制定其不同的掃描規則,就如同 SQL 注入中有著不同的資料庫型別一樣。

簡單來說,就是更改請求引數使之承載含有模板引擎語法的 Payload,通過頁面渲染返回的內容檢測承載的 Payload 是否有得到編譯解析,有解析則可以判定含有 Payload 對應模板引擎注入,否則不存在 SSTI。