{% raw %}
# 十六、模板注入
> 作者:Peter Yaworski
> 譯者:[飛龍](https://github.com/)
> 協議:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
模板引擎是允許開發者或設計師在創建動態網頁的時候,從數據展示中分離編程邏輯的工具。換句話說,除了擁有接收 HTTP 請求的代碼,從數據庫查詢必需的數據并且之后將其在單個文件中將其展示給用戶之外,模板引擎從計算它的剩余代碼中分離了數據的展示(此外,流行的框架和內容管理系統也會從查詢中分離 HTTP 請求)。
服務端模板注入(SSTI)在這些引擎渲染用戶輸入,而不合理處理它的時候發生,類似于 XSS,例如,jinja2 是 Python 的模板語言,取自 nVisium,一個 404 錯誤頁面的示例為:
```py
@app.errorhandler(404)
def page_not_found(e):
template = '''{%% extends "layout.html" %%}
{%% block body %%}
<div class="center-content error">
<h1>Opps! That page doesn't exist.</h1>
<h3>%s</h3>
</div>
{%% endblock %%}
''' % (request.url)
return render_template_string(template), 404
```
來源:https://nvisium.com/blog/2016/03/09/exploring-ssti-in-flask-jinja2
這里,`page_not_found`函數渲染了 HTML,開發者將 URL 格式化為字符串并將其展示給用戶。所以,如果攻擊者輸入了`http://foo.com/nope{{7*7}}`,開發者的代碼會渲染`http://foo.com/nope49,`,實際上求解了傳入的表達式。當你傳入實際的 Python 代碼,并且 jinja2 會求值時,它的嚴重性還會增加。
現在,每個 SSTI 的嚴重性取決于所用的模板引擎,以及在該字段上進行何種驗證(如果有的話)。例如,jinja2 存在任意文件訪問和遠程代碼執行,Rails 的 ERB 模板引擎存在遠程代碼執行,Shopify 的 Liquid 引擎允許訪問受限數量的模板方法,以及其他。展示你所發現的嚴重性實際上取決于測試什么是可能的。并且雖然你可能能夠求解一些代碼,它可能最后不是重要的漏洞。例如,我通過使用載荷`{{4+4}}`來發現了 SSTI,它返回了 8。但是,當我使用`{{4*4}}`,返回了文本`{{44}}`,因為星號被過濾了。這個字符安也溢出了特殊字符,例如`()`和`[]`,僅僅允許最大 30 個字符。所有這些組合起來使 SSTI 變得無用。
與 SSTI 相反的是客戶端模板注入(CSTI),要注意這里的 CSTI 不是一個通用的漏洞縮寫,像這本書的其它縮寫一樣,我推薦將其用于報告中。這個漏洞在應用使用客戶端模板框架時出現,例如 AngularJS,將用戶內容嵌入到 Web 頁面中而不處理它。它非常類似于 SSTI,除了它是個客戶端框架,產生了漏洞。 Angular 中 CSTI 的測試類似于 jinja2 并且設計使用`{{}}`和其中的一些表達式。
## 示例
### 1\. Uber Angular 模板注入
難度:高
URL:`developer.uber.com`
報告鏈接:`https://hackerone.com/reports/125027`
報告日期:2016.3.22
獎金:$3000
描述:
2016 年 3 月,James Kettle(Burp 的開發者之一,在工具一章所推薦的工具)使用 URL `https://developer.uber.com/docs/deeplinking?q=wrtz{{7*7}}`發現了 CSTI 漏洞。根據他的報告,如果你查看并渲染了頁面源碼,字符串`wrtz49`是存在的,表明該表達式被求值了。
現在,有趣的是,Angular 使用叫做沙箱的東西來“維護應用職責的合理分離”。有時這種由沙箱提供的分離設計為一種安全特性,來限制潛在的攻擊者可訪問的東西。但是,對于 Angular 來說,文檔中寫著“這個沙箱并不用于阻止想要編輯模板的攻擊者,而且在兩個花括號的幫定種可能運行任意代碼。”之后,James 設法這樣做了。
使用下面的 JavaScript,James能夠繞過 Angular 沙箱并且執行任意 JavaScript 代碼:
```
https://developer.uber.com/docs/deep-linking?q=wrtz{{(_="".sub).call.call({}[$="constructor"].getOwnPropertyDescriptor(_.__proto__,$).value,0,"alert(1)")()}}zzzz
```

Uber 文檔中的 Angular 注入
它注意到,這個漏洞可以用于劫持開發者賬戶,以及關聯 APP。
> 重要結論
> 一定要注意 AngularJS 的使用,并使用 Angular 語法`{{}}`來測試字段。為了使你更加輕松,使用 Firefox 的插件 Wappalyzer - 它會向你展示站點使用了什么軟件,包含 AngularJS。
### 2\. Uber 模板注入
難度:中
URL:`riders.uber.com`
URL:`hackerone.com/reports/125980`
報告日期:2016.3.25
獎金:$10000
描述:
Uber 在 HackerOne 發起它們的公開漏洞獎勵計劃時,它們也包含了一個“尋寶圖”,它可以在它們的站點找到,`https://eng.uber.com/bug-bounty`。
這個地圖記錄了 Uber 所使用的的一些敏感的子域,包含彼此依賴的技術。所以,對于問題中的站點來說,` riders.uber.com`,技術棧包括 Python Flask 和 NodeJS。所以,對于這個漏洞,Orange(攻擊者)注意到了所用的 Flask 和 Jinja2,并在名稱字段測試語法。
現在,在測試過程中,Orange 注意到了任何`riders.uber.com`上個人資料的修改,都會發送一封郵件,以及一個文本消息給賬戶擁有者。所以,根據他的博文,他測試了`{{1+1}}`,這導致站點解析了表達式并在給它的郵件中打印了`2`。
下面它嘗試了載荷`{% For c in [1,2,3]%} {{c,c,c}} {% endfor %} `,它執行了一個`for`循環并產生了下面的個人資料頁面:

載荷注入后的`blog.organge.tw ` Uber 資料
這是產生的郵件:

載荷注入后的`blog.organge.tw` Uber 郵件
你可以看到,在個人資料頁面,實際的文本被渲染了,但是郵件實際上執行了代碼并將其注入到郵件中。因此,漏洞是存在的,允許攻擊者執行 Python 代碼。
現在,Jinja2 嘗試通過將執行放入沙箱中來緩和傷害,意思是功能有限,但是偶爾能被繞過。這個報告最開始由一個博文支持(它在更早的時候發布),并包含一些` nVisium.com`博客的不錯的鏈接(是的,執行 Rails RCE 的同一個),它展示了如何繞過沙箱的功能:
+ https://nvisium.com/blog/2016/03/09/exploring-ssti-in-flask-jinja2
+ https://nvisium.com/blog/2016/03/11/exploring-ssti-in-flask-jinja2-part-ii
> 重要結論
> 要注意站點使用什么功能,這些通常是如何利用站點的關鍵信息。這里,Flask 和 Jinja2 變成了極好的攻擊向量。并且,在這個有一些 XSS 漏洞的例子中,漏洞可能不是那么直接或者明顯,要確保檢查了所有文本渲染的地方。這里,Uber 站點的資料名稱展示了純文本,但是郵件實際上存在漏洞。
### 3\. Rails 動態渲染器
難度:中
URL:無
報告鏈接:`https://nvisium.com/blog/2016/01/26/rails-dynamic-render-to-rce-cve-2016-0752`
報告日期:2015.2.1
獎金:無
描述:
在這個利用的研究中,nVisium 提供了一個 NB 的截斷和遍歷。基于他們的 WriteUp,RoR 的控制器在 Rails APP 中負責業務邏輯。這個框架提供了一些不錯的健壯的功能,包括哪些內容需要渲染用戶,基于傳給渲染方法的簡單值。
處理 Rails 的時候,開發者能夠隱式或者顯式控制渲染什么,基于傳給函數的參數。所以,開發者能夠顯式控制作為文本、JSON、HTML,或者一些其他文件的內容。
使用這個功能,開發者就能夠接收在 URL 中傳入的參數,將其傳給 Rails,它用于判斷要渲染的文件。所以,Rails 會尋找一些東西,例如`app/views/user/#{params[:template]}`。
nVisium 使用了在后臺中傳遞的示例,它可能會渲染`.html`、`.haml`、`.html.reb`后臺視圖。收到調用之后,Rails 會在目錄中掃描匹配 Rails 約定的文件類型(Rails 的理念是約定優于配置)。但是,當你讓 Rails 渲染一些東西,并且它找不到合適的文件來使用,他就會在`RAILS_ROOT/app/views`,`RAILS_ROOT`和系統根目錄中搜索。
這就是問題的一部分。`RAILS_ROOT`指代你的 APP 的根目錄,在這里尋找很有意義。系統的根目錄卻沒有,并且這很危險。
所以,使用它,你可以傳入` %2f%2fpasswd`,Rails 會打印出你的`/etc/passwd`文件。很可怕。
現在,讓我們進一步,如果你傳入`<%25%3dls%25>`,它會解釋為`<%= ls %>`。在 ERB 模板語言中,`<%= %>`表示要背執行和打印的代碼。所以這里,這是要執行的命令,或者允許遠程代碼執行。
> 重要結論
> 這個漏洞并不存在于每個 Rails 站點 - 它取決于站點如何編碼。因此,這不是自動化工具能夠解決的事情。當你知道站點使用 Rails 構建一定要注意,因為它遵循通用的 URL 約定 - 基本上,它的`/controller/id `用于簡單的 GET 請求,或者`/controller/id/edit`用于編輯,以及其他。
> 當你看到這個 URL 模式時,開始玩玩吧。傳入非預期的值并觀察返回了什么。
## 總結
搜索漏洞時,嘗試并識別底層的技術(框架、前端渲染引擎、以及其他)是個不錯的理念,以便發現可能的攻擊向量。模板引擎的不同變種,使我們難于準確地說,什么適用于所有環境,但是,知道用了什么技術會有幫助。要留意一些機會,其中你可控制的文本在頁面上,或者一些其他地方(例如郵件)渲染給你。
{% endraw %}