怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

鄲城ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:028-86922220(備注:SSL證書合作)期待與您的合作!

一、背景

此前,實(shí)驗(yàn)室成員在對nodejs原型鏈污染漏洞進(jìn)行梳理時,發(fā)現(xiàn)原型鏈污染漏洞可結(jié)合模板引擎的渲染達(dá)到遠(yuǎn)程命令執(zhí)行的效果。為什么原型鏈污染能結(jié)合模板引擎能達(dá)到這樣的效果?模板引擎究竟是如何工作的?除了原型鏈污染,還有其他方式也能達(dá)到同樣的效果嗎?帶著這樣的疑問,實(shí)驗(yàn)室成員決定對nodejs模板引擎的內(nèi)在機(jī)制進(jìn)行一些探索。

二、Nodejs模板引擎現(xiàn)狀

目前JavaScript生態(tài)圈里面的模板引擎非常之多,各引擎的實(shí)現(xiàn)原理及特性都不盡相同,很難找到一款功能豐富、書寫簡單、前后端共用的模板引擎,因此有開發(fā)者設(shè)立了一個根據(jù)不同需求挑選不同引擎的網(wǎng)站garann.github.io/template-chooser。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

根據(jù)npm的官方數(shù)據(jù),目前較受歡迎的模板引擎下載量分別如圖2所示。無恒實(shí)驗(yàn)室根據(jù)已有的服務(wù)端引擎框架,挑選了目前下載量較大,開發(fā)者常用的幾種模板引擎進(jìn)行分析,發(fā)現(xiàn)模板引擎的渲染原理基本上都差不多,只是在一些細(xì)節(jié)的處理方式不太一致。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

三、引擎使用方式

大多數(shù)模板渲染引擎在工作時基本都對外提供了一個render函數(shù),這個函數(shù)一般至少需要兩個參數(shù),一個是渲染的模板template,一般都為字符串,另一個是要被渲染進(jìn)模板的數(shù)據(jù)data,以object(即鍵值對)的形式傳入。render函數(shù)一般都具有以下的形式:

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

以下面的ejs渲染代碼為例,“./views/index.ejs”為模板文件的位置,{message: 'test'}為要渲染進(jìn)模板中的數(shù)據(jù):

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

其中,“./views/test.ejs”文件內(nèi)容如下:

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

渲染結(jié)果如下,將message對應(yīng)的值test渲染進(jìn)模板中。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

在render函數(shù)中,除了這兩個參數(shù)之外,多數(shù)模板引擎還提供了可控制渲染特性的參數(shù)options,用來對模板對渲染特性進(jìn)行控制,比如是否開啟調(diào)試功能,是否開啟緩存機(jī)制,是否打印報錯信息,以ejs為例, 可通過設(shè)置compileDebug來開啟調(diào)試語句。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

四、引擎渲染機(jī)制

基本上所有模板引擎的渲染機(jī)制都包含兩個步驟:

步驟一:根據(jù)模板數(shù)據(jù)進(jìn)行定位與分割,根據(jù)各模板定義的特殊符號找到要被替換的數(shù)據(jù)。

步驟二:根據(jù)提供的鍵值對和定位的結(jié)果進(jìn)行值的替換、拼接,最終得到渲染的結(jié)果。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

在本次的分析中,無恒實(shí)驗(yàn)室主要對Mustache和ejs兩種引擎的渲染機(jī)制進(jìn)行闡述,其他引擎的渲染過程大致相同。

4.1 定位

大多數(shù)渲染引擎都規(guī)定了要被替換的數(shù)據(jù)必須被某些符號所包裹,比如Mustache默認(rèn)的符號是 {{ }} ,而ejs默認(rèn)的符號是<%= %>,因此引擎在工作時,首先要在傳入的模板字符串中尋找到這些特殊符號。這一步不同引擎實(shí)現(xiàn)方式不同,如Mustache,Nunjucks是通過詞法解析也就是采用字符掃描的方式對模板字符串進(jìn)行掃描,從而定位特殊符號的位置,以如下Mustache的渲染代碼為例:

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

Mustache相應(yīng)的定位代碼如下,其中scanner負(fù)責(zé)對模板字符串進(jìn)行掃描,掃描的結(jié)果為會存入多個token對象中。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

最終會對每一個掃描到的token進(jìn)行分類和相應(yīng)值、位置的存儲,并放入到tokens中供后續(xù)的使用。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

示例模板字符串“whoareyou {{title}}”的掃描結(jié)果如下所示,“whoareyou ”會被標(biāo)記為text類型,也就是純文本,而"titile"會被標(biāo)記為name類型,是要被替換的數(shù)據(jù)。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

而ejs則是直接通過正則匹配的方式,循環(huán)定位特殊符號的位置。最終模板引擎可根據(jù)特殊符號的位置找到要被替換的原始數(shù)據(jù),以對如下的模板字符串進(jìn)行定位為例:

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

ejs會調(diào)用parsteTemplateText函數(shù)進(jìn)行定位,其中this.templateText為原始的模板字符串,this.regex為指定的特殊符號(也就是ejs指定的'<%'、'%>'等),接下來則會通過while循環(huán)不斷匹配將原始模板字符串分割。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

最終分割示例模板字符串的結(jié)果如下所示,可以看到要被替換的數(shù)據(jù)message已經(jīng)被定位出來了。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

4.2 替換

在定位到要被替換的原始數(shù)據(jù)后,模板引擎則開始根據(jù)輸入對原始數(shù)據(jù)進(jìn)行替換操作。這一步不同引擎的替換方式也不一樣。Mustache(包括Handlebars)的替換方式非常簡單粗暴,就是直接替換,代碼如下所示:

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

如上所示,如果檢測到token為name類型,也就是要被替換的類型,則調(diào)用escapedValue函數(shù),該函數(shù)中會調(diào)用lookup,根據(jù)token找到對應(yīng)的值。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

context.lookup最終會尋找到對應(yīng)的title的值,也就是joe。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

Pug, Nunjucks, ejs等引擎的替換過程就略顯麻煩,ejs的render函數(shù)中,會先調(diào)用handleCache函數(shù)。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

把如下的代碼拎出來,可以看到handleCache(opts, template)的結(jié)果是一個匿名函數(shù)

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

而result就是最終的渲染結(jié)果,這也就意味著,ejs的具體渲染過程是由函數(shù)進(jìn)行控制的,最終會等價于:

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

而在handleCache函數(shù)中,這個匿名函數(shù)是經(jīng)過compile編譯而來的。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

跟進(jìn)compile函數(shù)中,可以看到最終調(diào)用了Function函數(shù)構(gòu)造器動態(tài)構(gòu)造了一個匿名函數(shù)。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

以上面的ejs示例代碼為例,渲染引擎最終構(gòu)造的匿名函數(shù)如下所示,通過__append得到最終要渲染的模板數(shù)據(jù),這里同樣會采用escapeFn防止xss,可以看到ejs的處理過程,實(shí)際上也是根據(jù)定位分割的結(jié)果進(jìn)行處理拼接的過程。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

五、ejs模板引擎遠(yuǎn)程代碼執(zhí)行漏洞(CVE-2020-35772)

從上面的分析可以看到,ejs的渲染,是通過 **“動態(tài)生成函數(shù)代碼 -> 生成匿名函數(shù) -> 調(diào)用匿名函數(shù)”**的方式去實(shí)現(xiàn)的(實(shí)際上Nunjucks, pug等許多引擎都是這么實(shí)現(xiàn)的),而這種方式是相當(dāng)危險的,一旦動態(tài)生成的函數(shù)代碼中存在用戶可控的部分,惡意用戶就可以在匿名函數(shù)中插入惡意代碼并且會被渲染引擎所執(zhí)行,最終導(dǎo)致遠(yuǎn)程代碼執(zhí)行漏洞。之前GYCTF2020 Ez_Express的題就是利用了ejs的這種特性。

其利用原理如下,ejs在渲染時會獲取渲染選項的某些值拼接進(jìn)函數(shù)代碼中,其中就包括動態(tài)拼接outputFunctionName這個選項的值進(jìn)函數(shù)代碼中,但是ejs的作者從一開始就禁止了用戶對渲染選項中outputFunctionName進(jìn)行操控,同樣也包括其他的選項。既然無法從正面進(jìn)行操控,可以利用javascript的原型鏈污染,往Object中注入outputFunctionName屬性進(jìn)而操控。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

5.1 渲染選項的污染

能不能不通過原型鏈污染的方式注入惡意代碼?

來看看ejs渲染的入口函數(shù)render,其接受三個參數(shù),第一個是template,為模板字符串,第二個為data,一般會是用戶可控的數(shù)據(jù),第三個為渲染選項opts,這個渲染選項可控制匿名函數(shù)代碼的生成。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

ejs為了保持可用性,允許第二個參數(shù)(一般是用戶可控參數(shù))使用一些渲染選項,但是這些選項是有限定的,在代碼中被utils.shallowCopyFromList(opts, data, _OPTS_PASSABLE_WITH_DATA)函數(shù)所限定,“_OPTS_PASSABLE_WITH_DATA”指定了可控制的范圍,該范圍如下:

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

最終這些渲染選項會進(jìn)入到compile函數(shù)也就是匿名函數(shù)代碼生成的過程中,也就是說,若用戶數(shù)據(jù)能夠控制傳入的data選項,那么惡意用戶就能污染opts中的“delimiter”, “scope”, “context”,“debug”,“compileDebug”, “client”,“_with”,“rmWhitespace”,“strict”,“filename”, “async”。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

5.2 匿名函數(shù)代碼的生成

那么這些可污染選項,能對匿名函數(shù)代碼的生成造成什么影響呢?繼續(xù)跟進(jìn)渲染引擎發(fā)現(xiàn),匿名函數(shù)代碼在動態(tài)生成的過程中,由三部分構(gòu)成,分別是prepended, this.source, append三部分,而這三個部分的代碼又受到了渲染選項的影響

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

逐步跟進(jìn)匿名函數(shù)代碼的生成,首先可以看到outputFunctionName, localsName, destructuredLocals這個幾個渲染選項可影響prepended代碼的生成,但是這些選項都不在可控的范圍內(nèi)。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

繼續(xù)跟進(jìn)函數(shù)代碼的生成過程,如下所示,compileDebug是在可控范圍內(nèi),filename也在可控范圍內(nèi),但是filename被JSON.stringify進(jìn)行轉(zhuǎn)換了,無法逃逸出來,因此也無法污染函數(shù)代碼。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

接下來繼續(xù)跟進(jìn),可以看到在如下的代碼中,compileDebug和filename都是我們可控的,并且最后filename也被直接拼接進(jìn)匿名函數(shù)的代碼中,因此在這里就可以通過控制filename選項注入惡意的代碼。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

5.3 惡意代碼的注入

直接編寫如下的代碼,看看最終生成的匿名函數(shù)的源碼是怎么樣的。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

如下所示,可以看到/etc/passwd最終被插入到一個注釋的行中:

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

此時對payload進(jìn)行修改,加入換行符逃逸注釋。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

得到的結(jié)果結(jié)果如下,可以看到通過換行符已經(jīng)成功逃逸了注釋,但是,對于這樣一個函數(shù),其正常的流程走到try的代碼塊時,除非出現(xiàn)異常,否則的話直接走到return代碼就執(zhí)行結(jié)束了,壓根不會走到我們注入的代碼。除非能觸發(fā)異常繼續(xù)走下去,但是看try塊里面的代碼,基本沒有可觸發(fā)異常的邏輯。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

5.4 finally逃逸try catch限制

在常見的編程語言中,try catch實(shí)際上還可以再接一個finally,無論最終try cath如何,都會走到finally中的代碼塊,但是return的情況下,還能執(zhí)行finally嗎,paylaod如下:

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

來看看最終生成的代碼:

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

試了一下,還是能走到finally代碼塊的,最終注入的代碼被引擎所執(zhí)行

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

實(shí)際上,采用動態(tài)生成函數(shù)進(jìn)行渲染的引擎中,除了ejs,還有pug,nunjuck等,那么其他引擎是否也存在同樣的問題?無恒實(shí)驗(yàn)室也對其他的模板引擎進(jìn)行了分析,發(fā)現(xiàn)其他引擎雖然也采用了這種方式進(jìn)行渲染,但是較好的控制住了渲染選項對函數(shù)代碼的影響。

5.5 影響版本

在實(shí)際的測試過程中,發(fā)現(xiàn)在較老的ejs版本上,并不存在該漏洞,影響版本范圍為:
2.7.2(包括2.7.2)到最新版(3.1.5)。

5.6 利用難度

如上的漏洞實(shí)際上要求服務(wù)端的代碼直接拿用戶可控的json數(shù)據(jù)進(jìn)行渲染,包括key和value。對于正常的服務(wù)端框架來說,框架中間件是能將傳入的json數(shù)據(jù)轉(zhuǎn)換為json對象的,比較少有開發(fā)會直接拿整個json數(shù)據(jù)進(jìn)行渲染,但是也存在研發(fā)直接使用JSON.parse解析用戶數(shù)據(jù)進(jìn)行模板渲染的用法。

5.7 臨時修復(fù)方案

發(fā)現(xiàn)了該漏洞之后,無恒實(shí)驗(yàn)室及時與ejs的作者取得聯(lián)系,ejs的作者闡述這實(shí)際上屬于模板引擎本身的特性,用戶可控的json數(shù)據(jù)不應(yīng)該被直接傳入進(jìn)行使用,暫無提供修復(fù)版本的計劃。

無恒實(shí)驗(yàn)室對該問題進(jìn)行披露,希望能夠幫助受影響的業(yè)務(wù)避免潛在的安全風(fēng)險。若有線上業(yè)務(wù)代碼符合漏洞的觸發(fā)條件,因目前ejs暫時沒有修復(fù)的版本,無恒實(shí)驗(yàn)室提供如下的幾個臨時的修復(fù)方案:

  • ○ 若無版本要求,建議使用不在影響范圍內(nèi)的版本,如2.7.1。

  • ○ 若在受影響版本范圍內(nèi),建議不直接獲取用戶的json數(shù)據(jù)進(jìn)行模板渲染。

  • ○ 若需要直接獲取用戶數(shù)據(jù)進(jìn)行模板渲染,確保用戶數(shù)據(jù)中不存在compileDebug和filename選項或者這些選項的值不可控。可采用如下的安全檢測函數(shù)。

怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。

網(wǎng)站題目:怎么分析Nodejs中模板引擎渲染原理與潛在隱患探討
標(biāo)題路徑:http://muchs.cn/article20/iehgco.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供面包屑導(dǎo)航、網(wǎng)站收錄網(wǎng)站維護(hù)、網(wǎng)站排名、云服務(wù)器手機(jī)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化