未能解析此远程名称_Fastjson 1.2.24远程代码执行漏洞

097dd7907c4797c7682bcbb6de1ae450.png

1.漏洞信息

1.1 漏洞简介

  • 漏洞名称:Fastjson 1.2.24远程代码执行漏洞(com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl)
  • 漏洞编号:无
  • 漏洞类型:远程代码执行
  • CVSS评分:无
  • 漏洞危害等级:高危

1.2 组件概述

Fastjson是一个Java语言编写的高性能功能完善的JSON库。它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,是目前Java语言中最快的JSON库。Fastjson接口简单易用,已经被广泛使用在缓存序列化、协议交互、Web输出、Android客户端等多种应用场景。下图是Fastjson组件中的反序列化流程。

b3c85d921d7eba2afa6ba83dc2cd5685.png

1.3 漏洞概述

漏洞是利用fastjson autotype在处理json对象的时候,未对@type字段进行完全的安全性验证,攻击者可以传入危险类,服务器接收到危险类执行其中恶意代码。攻击者通过这种方式可以实现远程代码执行漏洞的利用,获取服务器的敏感信息泄露,甚至可以利用此漏洞进一步对服务器数据进行修改,增加,删除等操作,对服务器造成巨大的影响。

1.4 漏洞利用条件

1.5 漏洞影响

影响版本:
Fastjson < 1.2.25

1.6 漏洞修复

获取Fastjson最新版本,下载链接:https://github.com/alibaba/fastjson

2.漏洞复现

2.1 环境拓扑

5057464479119e7f898e706dbdcc07ae.png

2.2 应用协议

8080/HTTP

2.3 复现过程

基于Windows平台,使用环境目录下的fastjsondemo环境,拷贝后使用Idea打开fastjsondemo文件夹,下载maven资源,运行DemoApplication类,即可启动环境。效果如图。

a7b9515f8d9126899c1eda6a5fb3b70d.png

运行sniper工具箱,填写表单信息,点击Attack,效果如图。

f02920d457e11fe21073d0e9c4a9e951.png

3.漏洞分析

3.1 技术背景

JavaBean:

JavaBean 是特殊的 Java 类,使用 Java 语言书写,并且遵守 JavaBean API 规范。JavaBean的特征:

  • 提供一个默认的无参构造函数。
  • 需要被序列化并且实现了 Serializable 接口。
  • 可能有一系列可读写属性。
  • 可能有一系列的 getter 或 setter 方法。
方法描述
getPropertyName()举例来说,如果属性的名称为 myName,那么这个方法的名字就要写成 getMyName() 来读取这个属性。这个方法也称为访问器。
setPropertyName()举例来说,如果属性的名称为 myName,那么这个方法的名字就要写成 setMyName()来写入这个属性。这个方法也称为写入器。

程序实例

public class StudentsBean implements java.io.Serializable
{
private String firstName = null;
private String lastName = null;
private int age = 0;
public StudentsBean() {
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public int getAge(){
return age;
}
public void setFirstName(String firstName){
this.firstName = firstName;
}
public void setLastName(String lastName){
this.lastName = lastName;
}
public void setAge(int age) {
this.age = age;
}
}

3.2 详细分析

3.2.1 代码分析

Fastjson通过parseObject方法解析传入的json数据。

efa1733841e4af377ca62ebbf344d957.png

调用DefaultJSONParser缺省方法对json格式数据进行解析。

fe755e0752338ee3a1dac9890e2fd23b.png

在方法的参数中,调用ParserConfig.getGlobalInstance()方法获取ParserConfig类中的初始配置,其中黑名单(denyList)也在此类中进行配置。

d69525a4cc675febe8543bc110b6eace.png

调用addDeny方法循环添加denyList数组中的黑名单。

07d5a183e43959009d0a5de17b94282e.png

b716b6b1c6a9a825f7dd496d0b9feaba.png

回到DefaultJSONParser方法,初始化结束后,调用JSONScanner方法对传入的json字符串设置读取位置,判断过程中处理Unicode字符集的BOM标识。

1fddb211986f4b02467158dd6f270ad6.png

回到DefaultJSONParser方法,为token赋值。

2ea3df07abae2a3ca8c2ddb220984353.png

回到JSON入口类,获取到DefaultJSONParser类型对象,调用parse()方法进行解析。

c85e6488d488653e493524e565b2ebbd.png

在parse方法中,通过判断lexer.token(),进入对应的代码块。

f67aa050e976638ef2389ad9df58156d.png

调用JSONObject构造方法,初始化JSONObject类中的map属性。

9cb9c54c713245e1150b073281305208.png

回到DefaultJSONParser#parse方法,调用parseObject方法,对传入的json数据进行字节读取。

eefcefcc6be0316a388977bcae2d7151.png

一般会读取json字符串中的双引号进入scanSymbol方法中,在scanSymbol方法中计算字符串的hash。

a2c3756498024d8e346acb68441df036.png

调用addSymbol方法,将键名添加到SymbolTable中。

40d432af48698a89091062f6a0433ace.png

回到DefaultJSONParser#parseObject方法中,判断key值是否为@type。如果是,则进入if判断条件下的代码块中。

22eb832a6e4d4089308e0be6198eaf92.png

调用scanSymbol方法,以双引号作为quote变量值,进行@typejson字段值的value读取。

2ca83bcba381524bc6aa6af0addf5bb2.png

获得@type的键值,调用addSymbol方法,将@type的字段值添加到SymbolTable中。

4e458606797a4c33bfea5ca4ac9bbc54.png

回到DefaultJSONParser#parseObject方法中,调用TypeUtils.loadClass方法进行类加载操作。

95b4b533b131d220f440fe8b2218cad1.png

进入loadClass方法中,首先会在现有的mappings中寻找从@type传入的classname。

11a3a39d132e4152ec44e6d131b8aeb2.png

如果在原有的mappings中没有记录传入的classname,则调用contextClassLoader.loadClass获取AppClassLoader类加载器,并加载到mappings中与@type传入的类进行关联,最后返回clazz对象。

97ffed82f0860d96a3822537361fe793.png

回到DefaultJSONParser#parseObject方法中,调用this.config.getDeserializer(clazz)获取反序列化器。

40c33a4f701e1404595b9c37b8dce6c7.png

进入getDeserializer方法中,首先现有的IdentityHashMap中进行hash匹配,如果无法匹配,则进入第二个if判断条件中重载getDeserializer方法,继续获取反序列化器。

85fd6f0bdc45dab11e022da0ce2634db.png

getDeserializer(Class<?> clazz, Type type)方法中,首先依然会与现有的IdentityHashMap中进行hash匹配。如果无法匹配,会事先进行黑名单匹配,在调用ServiceLoader.load判断META-INF/services/下是否存在传入的classname类。

60f3571eefda3ebab68dd86e5c904cf8.png

如果没有寻找到对应的类,则判断传入的classname是否是继承java.lang.Enum、是否是array类型选择对应的反序列化器生成方法。如果上述条件不满足,则继续判断传入的classname是否为Set、HashSet、Collection、List、ArrayList,如果不是则继续判断classname是否继承Collection,Map,Throwable接口。如果上述条件都不满足,则调用createJavaBeanDeserializer方法生成JavaBean反序列化器。

ca8205486afeac3b178652ab51df9a63.png

进入createJavaBeanDeserializer方法,判断asmEnable是否为true,调用JavaBeanInfo.build方法建立JavaBean。

a5f2cf02ab7c17e3fe2915608c299fbe.png

建立JavaBean过程中,通过反射机制获取传入的class中所有的属性,方法,并保存在数组中。选择一个无参构造函数作为默认的构造函数。

d3169874c29ed0612a028490685a0193.png

循环遍历method数组中的方法,并从中选取符合条件的方法。(条件:同时满足方法名长度大于4;非静态方法;方法类型为Void。或者方法类型与方法所在类相同)

dd3bba79d69edc1a2d925f7a2e18035d.png

再从筛选的规则中继续筛选出形参数量为1的方法。

9265a3433be17959b14f781e598c395d.png

再从筛选出的方法中获取以set方法开头的方法,并检测JavaBean的方法命名规范,筛选出符合规范的方法。调用TypeUtils.getField方法获取与set方法对应的属性值。

db169417cb5ad2b0a804aa4fd331d2d9.png

进入getField方法中,遍历@type传入的class以及其父类的所有属性值,返回寻找到属性。

141dc3d77a0655a1f10eb6b2760e8dc9.png

最终调用add方法,将获取的Field属性保存到fieldList列表中。

14acc6ff366032b0a8558e8f46e1c455.png

再以相同的流程筛选出存在get方法的属性值,如果筛选出的filed属性值不在fieldList,则添加到fieldList列表中。

427f8924c7c5f753a20761f7e4bacdf6.png

调用JavaBeanInfo方法对JavaBeanInfo中的属性进行初始化,并返回实例化对象。

056b5dff91527e0f4337bf8c382977ea.png

a5e3295a8c02c17a5cb914c280409f45.png

回到ParserConfig#createJavaBeanDeserializer方法中,获取到beanInfo对象,并从beaninfo中取出defaultConstructor默认构造器、field属性。

10d327a0b31738bbe5c5360da02af758.png

通过检测fieldClass属性值,为asmEnable标志位赋值

c248dc1880cbd27d6706cc056c42f11a.png

由于@type传入的class中的javabean方法,存在只读属性,因此asmEnable标志位变成false。

46a298e03c8b1ffdcc0a861ac57d7623.png

根据asmEnable标志位,进行if条件判断,调用JavaBeanDeserializer构造方法,并返回实例化对象。

175a4cbab494a19af210488f7b860c22.png

在实例化过程中,会将beaninfo中的属性赋值给JavaBeanDeserializer类中的filed反序列化器。

8ea33a80df41b8a014a53f6de7ea5d5a.png

回到ParserConfig#getDeserializer方法,调用putDeserializer方法,将生成的反序列化器与@type传入的class类进行关联,最后返回反序列化器

5776a59c77b3a1fd99b31409c46bc2c2.png

回到DefaultJSONParser#parseObject方法,调用deserializer.deserialze方法进行反序列化。

f38a1bc101a48ad100d0f5545885e377.png

进入deserialze方法中,首先根据token值进入到对应的条件代码块。调用scanSymbol方法。

41ee8026e5509ab6d089ae9925541e0b.png

进入scanSymbol方法,对传入的json字符串进行解析,和解析@type的流程相同,解析传入的其他属性字段。

5de242906b269d4f82cfc4b4679c5b08.png

回到JavaBeanDeserializer#deserialze方法中,解析的属性值返回并赋值到key属性中。

325dd514c5d1c867bb240e0f648c7047.png

调用parseField方法解析属性。

d46253ab2e8c64e6bc1b45b9f4123255.png

进入parseField方法,调用smartMatch方法,获取field反序列化器。

01214c6fb2c5c0ed4da1fc82b160f16b.png

进入smartMatch方法,首先会从建立的javabean中寻找是否存在对应key中属性值的操作方法。

a4b36434fe973b71d807e31b56964756.png

如果没有匹配到javabean中的方法,则先消除掉属性值中的_-符号,再与javabean中的方法进行匹配,如果匹配成功,则返回反序列化器。如果匹配失败,则返回null。

1ecbc52a72b357d9335de286c9d72274.png

c1c40cd4952095936d65e368d077853b.png

回到parseField方法中,设置Feature.SupportNonPublicField状态,并根据状态值进入if条件判断的代码块中,生成extraFieldDeserializers扩展的反序列化器。再从反序列化器中取出从fastjson获取的json数据中指定的属性。

4f7ce68e0e654b0ecc121f46a61154ad.png

调用parseField方法,按照获取deserializer反序列化器的流程,获取fieldValueDeserilizer反序列化器。得到的fieldValueDeserilizer反序列化器,在parseField方法中调用deserialze方法进行反序列化。

0568a7670edc0db6c37819c65aa68bad.png

由于传入的参数中存在数组,fastjson首先会调用getFastMatchToken方法,获取当前json字符串位置的token标志值。

b8c6f8dae07c668c8bce2f464bfb9af8.png

由于json字符串中的数组是以[data]的形式传入的,所以当检测属性值是以[开头,则为token赋值为14。

e9eb3e9e5e2228736891372545bdfca2.png

由于是数组类型,因此在获取反序列化器时,会进入ObjectArrayCodec类进行解析。

1cb164e5dfcb7b5ba66a63f687223a8c.png

调用ObjectArrayCodec#parseArray方法,进行数组的解析。

f1d21820d5eeb39f425668575becd946.png

根据数组中的元素类型,进行token赋值,再依据token,选择对应token值,进入对应的if代码块。

319416b3d56421d81559cc2e9345f0eb.png

f0e3f7f77774dfbf09210172cc0cf773.png

解析数组中元素时,如果元素时String类型,则将字符串按照byte类型进行读取,在读取的过程中,会先进行base64解码。

a8524e150d6c319cfd2b9310d6645a96.png

5248766136eac5f831a6aea8f1a0a58b.png

最终以]符号作为数组结束符。

9a92d8f19fb9d5c3172edd7243f49f22.png

回到ObjectArrayCodec#deserialze方法中,调用toObjectArray方法,将传入的数组数据,转换成数组对象。

81f33fa1d841ad8cda9d1e04f0d984fc.png

回到DefaultDeserializer#parseField方法中,调用setValue方法,将获取的数组对象,赋予到@type class中的对应属性中。

ab3c7e38565e549c033c02a58487ed59.png

在解析最后一个_outputProperties参数时,会在setValue方法中进行反射,调用getOutputProperties方法。

a69a89a5d1423158ee1a448c472cff3d.png

此方法会在调用的过程中,实例化从bytecode传入恶意class文件,从而实现攻击。

6ecabe9263c0abda01ab3feb22096584.png

3.2.2补丁分析

Fastjson1.2.25版本新增了checkAutoType方法,设置了autotype开关,对@type字段进行限制。如果autotype开关关闭,则无法从@type字段传入类进行jndi攻击。

27222dd9ce30312d7155d9dd0612cd21.png

增加了黑名单中的类,对fastjson的gadget进行拦截。

5bf0c65d4160793b43a12395b8ce9204.png

4.防御方案

【深信服下一代防火墙】可轻松防御此漏洞, 建议部署深信服下一代防火墙的用户更新至最新的安全防护规则,可轻松抵御此高危风险。
【深信服云盾】已第一时间从云端自动更新防护规则,云盾用户无需操作,即可轻松、快速防御此高危风险。
【深信服安全感知平台】可检测利用该漏洞的攻击,实时告警,并可联动【深信服下一代防火墙等产品】实现对攻击者ip的封堵。
【深信服安全运营服务】深信服云端安全专家提供7*24小时持续的安全运营服务。对存在漏洞的用户,检查并更新了客户防护设备的策略,确保客户防护设备可以防御此漏洞风险。

5.参考链接

1.https://www.runoob.com/jsp/jsp-javabean.html
2.http://xxlegend.com/2018/10/23/%E5%9F%BA%E4%BA%8EJdbcRowSetImpl%E7%9A%84Fastjson%20RCE%20PoC%E6%9E%84%E9%80%A0%E4%B8%8E%E5%88%86%E6%9E%90/
3.https://github.com/alibaba/fastjson/compare/1.2.24...1.2.25

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值