一、模板注入與常見Web注入
就注入類型的漏洞來說,常見 Web 注入有:SQL 注入,XSS 注入,XPATH 注入,XML 注入,代碼注入,命令注入等等。注入漏洞的實質是服務端接受了用戶的輸入,未過濾或過濾不嚴謹執行了拼接了用戶輸入的代碼,因此造成了各類注入。下面這段代碼足以說明這一點:
// SQL 注入 $query = "select * from sometable where id=".$_GET['id']; mysql_query($query); ------------- 華麗的分割線 -------------
// 模版注入 $temp->render("Hello ".$_GET['username']);
而服務端模板注入和常見Web注入的成因一樣,也是服務端接收了用戶的輸入,將其作為 Web 應用模板內容的一部分,在進行目標編譯渲染的過程中,執行了用戶插入的惡意內容,因而可能導致了敏感信息泄露、代碼執行、GetShell 等問題。其影響范圍主要取決於模版引擎的復雜性。
二、模板注入原理
模板注入涉及的是服務端Web應用使用模板引擎渲染用戶請求的過程,這里我們使用 PHP 模版引擎 Twig 作為例子來說明模板注入產生的原理。考慮下面這段代碼:
1 <?php 2 require_once '../Twig-1.35.3/lib/Twig/Autoloader.php'; 3 Twig_Autoloader::register(true); 4 $twig = new Twig_Environment(new Twig_Loader_String()); 5 $output = $twig->render("Hello {{name}}", array("name" => $_GET["name"])); // 將用戶輸入作為模版變量的值
6 echo $output;
使用 Twig 模版引擎渲染頁面,其中模版含有 {{name}} 變量,其模版變量值來自於 GET 請求參數 $_GET["name"] 。顯然這段代碼並沒有什么問題,即使你想通過 name 參數傳遞一段 JavaScript 代碼給服務端進行渲染,也許你會認為這里可以進行 XSS,但是由於模版引擎一般都默認對渲染的變量值進行編碼和轉義,所以並不會造成跨站腳本攻擊:
但是,如果渲染的模版內容受到用戶的控制,情況就不一樣了。修改代碼為:
1 <?php 2 require_once '../Twig-1.35.3/lib/Twig/Autoloader.php'; 3 Twig_Autoloader::register(true); 4 $twig = new Twig_Environment(new Twig_Loader_String()); 5 $output = $twig->render("Hello {$_GET['name']}"); // 將用戶輸入作為模版內容的一部分
6 echo $output;
上面這段代碼在構建模版時,拼接了用戶輸入作為模板的內容,現在如果再向服務端直接傳遞 JavaScript 代碼,用戶輸入會原樣輸出,測試結果顯而易見:
對比上面兩種情況,簡單的說服務端模板注入的形成終究還是因為服務端相信了用戶的輸入而造成的(Web安全真諦:永遠不要相信用戶的輸入!)。當然了,第二種情況下,攻擊者不僅僅能插入 JavaScript 腳本,還能針對模板框架進行進一步的攻擊,此部分只說明原理,在后面會對攻擊利用進行詳細說明和演示。
三、模板注入檢測
上面已經講明了模板注入的形成原來,現在就來談談對其進行檢測和掃描的方法。如果服務端將用戶的輸入作為了模板的一部分,那么在頁面渲染時也必定會將用戶輸入的內容進行模版編譯和解析最后輸出。
借用本文第二部分所用到的代碼:
1 <?php 2 require_once '../Twig-1.35.3/lib/Twig/Autoloader.php'; 3 Twig_Autoloader::register(true); 4 $twig = new Twig_Environment(new Twig_Loader_String()); 5 $output = $twig->render("Hello {$_GET['name']}"); // 將用戶輸入作為模版內容的一部分
6 echo $output;
在 Twig 模板引擎里,{{ var }} 除了可以輸出傳遞的變量以外,還能執行一些基本的表達式然后將其結果作為該模板變量的值,例如這里用戶輸入 name={{2*10}} ,則在服務端拼接的模版內容為:
Hello {{2*10}}
Twig 模板引擎在編譯模板的過程中會計算 {{2*10}} 中的表達式 2*10 ,會將其返回值 20 作為模板變量的值輸出,如下圖:
現在把測試的數據改變一下,插入一些正常字符和 Twig 模板引擎默認的注釋符,構造 Payload 為:
IsVuln{# comment #}{{2*8}}OK
實際服務端要進行編譯的模板就被構造為:
Hello IsVuln{# comment #}{{2*8}}OK
這里簡單分析一下,由於 {# comment #} 作為 Twig 模板引擎的默認注釋形式,所以在前端輸出的時候並不會顯示,而 {{2*8}} 作為模板變量最終會返回 16 作為其值進行顯示,因此前端最終會返回內容 Hello IsVuln16OK ,如下圖:
通過上面兩個簡單的示例,就能得到 SSTI 掃描檢測的大致流程(這里以 Twig 為例):
同常規的 SQL 注入檢測,XSS 檢測一樣,模板注入漏洞的檢測也是向傳遞的參數中承載特定 Payload 並根據返回的內容來進行判斷的。每一個模板引擎都有着自己的語法,Payload 的構造需要針對各類模板引擎制定其不同的掃描規則,就如同 SQL 注入中有着不同的數據庫類型一樣。
簡單來說,就是更改請求參數使之承載含有模板引擎語法的 Payload,通過頁面渲染返回的內容檢測承載的 Payload 是否有得到編譯解析,有解析則可以判定含有 Payload 對應模板引擎注入,否則不存在 SSTI。
四、小結
本文簡單介紹服務端模版注入漏洞如常規 Web 注入漏洞之間的關系,分析了其產生的原理,並以 PHP 模板引擎 Twig 為例講解了 SSTI 常規的掃描和檢測方法。雖然說 SSTI 並不廣泛存在,但如果開發人員濫用模板引擎,進行不安全的編碼,這樣 Web 應用就可能出現 SSTI,並且根據其模板引擎的復雜性和開發語言的特性,可能會造成非常嚴重的問題。
在后續的文章中會針對各語言流行的模板引擎做一個較為詳細的研究和分析,給出對應的可利用點和方法。
來自FreeBuf黑客與極客(FreeBuf.COM)
http://blog.knownsec.com/2015/11/server-side-template-injection-attack-analysis/