写在前面
自weax勒索病毒开始使用0day攻击国内应用系统以来,我们一直在持续跟进。
先同步一个最新动向。近期该家族的加密后缀由此前的 .weax 改为 .rox,例如 123.pdf.rox。从我们的处置现场看,勒索信样式、联系邮箱、加密流程均未变化,属于换汤不换药,只是改了一个扩展名。
再谈两点我们从多起现场中得到的判断。
其一:从攻击时间看,该家族的攻击动作大部分集中在每晚19点到23点左右,非常符合国内人员的作案作息;
其二:近几起事件使用的漏洞均为未公开的0day,攻击源均为国内代理IP。0day的来源目前没有定论,不排除攻击者通过一些渠道购买所得,我们会继续跟踪核实。
既往weaxor勒索家族的受害对象几乎全是中小型企业,因为这类企业防护薄弱、安全投入有限,是投入产出比最高的目标。但0day攻击的逻辑完全不同,它不挑企业规模,只要系统对外暴露,无论是中小企业还是大中型企业,都有被勒索的风险。
阅读说明:按照惯例,本文对受害单位名称、受害资产地址等信息做脱敏处理,配图中的敏感信息已打码。为避免攻击代码被滥用,本文不公开完整可利用载荷,涉及攻击载荷处统一以脱敏形式展示,技术细节以讲清原理为限。目前该漏洞已按流程提交至国家信息安全漏洞共享平台(CNVD)与中国国家信息安全漏洞库(CNNVD)。
一、事件概述
2026年9月30日晚,某企业的用友畅捷通T+服务器遭遇勒索攻击。受害站点对外服务端口8080,经本机nginx反向代理至IIS,为.NET Framework应用,后端数据库为SQL Server。
当晚19:33至19:43,攻击者先后使用江苏省南京市IP 117.62.223.95 与北京市IP 49.7.180.227(威胁情报均显示代理特征)对受害站点发起四发POST请求,目标全部指向同一接口 /tplus/api/v2/collaborationapp/GetAnonymousTPlusToken?IsFree=1。四次请求与数据库ERRORLOG中的配置变更秒级对齐,依次为开启xp_cmdshell、开启OLE自动化、调用sp_OACreate,第四次请求则执行了长达641秒的数据库命令。19:43,加密器 uuAmyFeQV.exe 落地 C:\Windows\System32\ 目录,随后系统安全日志被清除,服务器文件被批量加密为 .weax 后缀,业务中断。
应急响应过程中,我方对被攻击版本的服务端程序集开展代码审计,完整还原了漏洞链路:
- 查询串中的
IsFree=1 使REST管线整体跳过验签;
- 攻击载荷藏于Authorization请求头的
orgId 字段,经管线对该接口的硬编码分支覆盖进入业务方法;
appKey 与 authInfo 使用产品内置硬编码密钥对即可通过结构解析;
orgId 未经任何参数化或转义直接拼入SQL的WHERE子句,以TPlusDBAdmin(sysadmin)身份执行;
- 而产品自带WAF的检查范围不包含Authorization请求头,因此全程无拦截。
上述链路经复现环境逐项实测,并以攻击者原始载荷重放确认。
二、详细溯源过程
时区换算说明:受害站点的IIS访问日志默认使用UTC时区,SQL Server ERRORLOG与Windows系统日志使用UTC+8本地时间。下文凡涉及IIS日志与其他日志对照之处,均按"IIS日志UTC时间加8小时等于本地时间"进行换算。
2.1 首次攻击:四次注入请求与数据库动作秒级对齐
2026年9月30日19:33:12至19:43:54(北京时间,对应IIS日志UTC时间11:33:12至11:43:54),攻击者IP 117.62.223.95、49.7.180.227 依次发起四次请求:
POST /tplus/api/v2/collaborationapp/GetAnonymousTPlusToken?IsFree=1
IIS日志中针对GetAnonymousTPlusToken接口的攻击请求记录,红框标注的攻击条目均返回200
攻击IP 117.62.223.95(江苏省南京市)威胁情报,历史开放端口逾百个,多个端口呈现代理特征
攻击IP 49.7.180.227(北京市)威胁情报,同样呈现代理IP特征
对应时段的SQL Server ERRORLOG显示,19:32:12至19:34:14,攻击者先后开启OLE自动化并调用sp_OACreate:
2026-09-30 19:34:13.54 spid104 Configuration option 'Ole Automation Procedures' changed from 0 to 1. Run the RECONFIGURE statement to install.
2026-09-30 19:34:14.12 spid104 Using 'odsole70.dll' version '2009.100.1600' to execute extended stored procedure 'sp_OACreate'.
SQL Server ERRORLOG中的配置变更记录,红框处为OLE自动化开启与sp_OACreate执行,与攻击请求秒级对齐
由此可以判断,weax勒索病毒利用用友畅捷通T+的SQL注入漏洞开启xp_cmdshell及OLE自动化,进而执行系统命令获取服务器权限,部署加密器进行勒索。
这组日志还还原了该家族标准化的攻击序列:四发请求依次为开启xp_cmdshell、开启OLE自动化、sp_OACreate实例化、长任务执行。前三发间隔紧凑,功能互为前置;第四发耗时约641秒,结合攻击上下文判断为下载勒索样本及加密前置准备。
2.2 权限获取、加密器落地与痕迹清除
系统日志方面,由于攻击者通过SQL注入在数据库服务上下文中执行命令,Windows事件日志没有记录具体的命令内容,但仍有侧面痕迹可寻。
19:43:48,攻击者获取服务器权限后,安全日志记录了一条SYSTEM账户的服务登录事件:
安全日志中19:43:48记录的SYSTEM账户登录事件(登录类型5),时间点与加密器落地前的权限获取动作吻合
19:43,加密器落地至 C:\Windows\System32\uuAmyFeQV.exe:
Everything检索System32目录,加密器uuAmyFeQV.exe(669KB)修改时间为2026年9月30日19:43
19:43:49,攻击者执行的加密器清除系统日志,这是weaxor勒索家族加密器清理痕迹的典型特征:
系统日志显示19:43:49审核日志被清除,为加密器清理痕迹的动作
19:43起,系统文件开始被批量加密,文件后缀被追加 .weax:
Everything检索.weax后缀,数十万个文件被加密,修改时间集中于19:43起
2.3 勒索家族归属
受害机各目录下遗留勒索信 RECOVERY INFORMATION.txt,内容为TOR会话地址(weaxorpemwzoxg5cd...onion,按惯例不完整披露)与联系邮箱 datahelper@cyberfear.com,据此确认加密器归属weaxor勒索家族。
三、确定漏洞类型:FREB捕获的决定性证据
这里需要先交代一段插曲,它是整个溯源过程的关键转折。
应急处置结束后,客户已由用友官方协助重新搭建了环境。我们在新环境上开展代码审计时,实际对应路由没有发现漏洞,测试过程中构造的SQL注入请求均被规则拦截,返回拦截状态码,这说明官方在新版本上已经修复了相关漏洞。但奇怪的是,即使漏洞已经修复,对应的Web日志里针对该接口的攻击请求仍在持续出现。攻击者还在打,说明他们手里掌握着确切的入口细节,而这些细节在常规日志里看不见:IIS默认日志只记录URL查询串与请求元数据,不记录请求体与请求头。
为看清攻击者的真实请求,我们在环境上开启了IIS失败请求跟踪(FREB),最终捕获到攻击者的完整请求载荷:
POST /tplus/api/v2/collaborationapp/GetAnonymousTPlusToken?IsFree=1
Authorization: 攻击载荷BASE64编码(为避免滥用,此处不公开完整内容)
IIS失败请求跟踪日志捕获到攻击者完整请求,payload全程只经过Authorization请求头
对Authorization头做Base64解码后,其结构为一个JSON对象,包含 appKey、authInfo、orgId 三个字段,注入payload位于 orgId 字段,注入形态为引号闭合、堆叠执行加尾部注释。这一发现与我们此前代码审计预判的攻击点如出一辙,只是我们审计测试所用的版本已加了规则。随后我们在另一项目中尚未修复版本的畅捷通T+环境上进行了测试,结果发现漏洞表现完全一致。于是我们将存在漏洞的版本与新版本逐一做了对比,确认了官方修复的真实生效点。下面依次展开代码审计过程、PoC验证与修复版本的对比结果。
载荷中的三个要素与后文代码审计一一对应:appKey 与 authInfo 是产品内置的硬编码密钥对;payload位于 orgId 字段;注入形态为引号闭合加堆叠执行。这也是多波攻击的IIS日志中始终看不到载荷的原因,payload全程只经过请求头。至此漏洞类型明确:GetAnonymousTPlusToken接口未授权SQL注入,经堆叠执行开启xp_cmdshell与OLE自动化,达成命令执行。
四、代码审计
审计动线:从"这个接口为什么能未授权调用"出发,逐层定位参数的真实来源,落到SQL拼接点,最后回答"规则为什么没有拦"。
审计底稿说明:被攻击版本的核心程序集经ConfuserEx混淆,方法体不可直接反编译,但其同架构相邻版本的同名文件为明文且逻辑一致,两者行为一致性已由攻击载荷在复现环境上的完整重放予以实证。下文代码讲解以明文版本为底稿,未混淆的程序集直接引用其实际源码。
4.1 入口:IsFree=1使验签整体跳过
攻击URL的查询串只有一个参数 IsFree=1。在反编译目录全量检索 IsFree,命中REST管线主处理器 RestHandler.cs,其第152行处为鉴权分支:
if (!Context.BaseInfo.IsFree && !Context.BaseInfo.IsLocalSessionCall)
{
obj = RestAuthorizationFactory.GetDefaultRestAuthorization().Invoke(Context); // 验签与会话校验
}
ILSpy反编译RestHandler主处理器,红框处为鉴权分支:IsFree为真时验签调用被整体跳过
当请求携带 IsFree=1 时,整个验签调用被短路跳过,请求直接进入业务分发。也就是说,IsFree=1 不是业务参数,而是一个鉴权开关。
4.2 orgId的真实来源:Authorization头覆盖请求参数
继续在 RestHandler.cs 检索攻击URL中的方法名 GetAnonymousTPlusToken,命中第158至163行,v2管线对该方法名存在硬编码的参数改写分支:
if (Context.Version == "v2" && Context.CurrentCallInfo.MethodName == "GetAnonymousTPlusToken")
{
Context.CurrentCallInfo.Arguments["orgId"] = RestSerializer.Serialize(Context.AuthorizationInfo.OrgId);
Context.CurrentCallInfo.Arguments["cspAppKey"] = RestSerializer.Serialize(Context.AuthorizationInfo.AppKey);
Context.CurrentCallInfo.Arguments["cspAppSecret"] = RestSerializer.Serialize(Context.AuthorizationInfo.AppSecret);
Context.CurrentCallInfo.Arguments["signvalue"] = RestSerializer.Serialize(Context.AuthorizationInfo.AuthInfo);
}
ILSpy中v2管线对GetAnonymousTPlusToken的硬编码参数覆盖分支(红框),payload从请求头注入业务参数的关键行
调用服务方法前,管线用Authorization头解析出的四个字段强制覆盖了请求体中的同名参数。也就是说,请求体中的 orgId 不会被实际使用,真正进入业务方法的 orgId 取自Authorization请求头JSON中的 orgId 字段。
4.3 Authorization头的构成:内置密钥随产品分发
Authorization头的值是Base64编码的JSON,结构为 {"appKey","authInfo","orgId"}。其中的 appKey 与 authInfo 从何而来?在被攻击版本程序集的字符串堆中检索,命中一组连续排列的GUID与六位字母串对,约30组,可确认其为产品内置的appKey/appSecret密钥表,硬编码于程序集中。
独立佐证来自受害机应用日志 CloudAuthentication.log,产品自身与畅捷通云端交互时即以明文携带该密钥对:
受害机CloudAuthentication.log中,产品自身与云端交互时即以明文携带内置密钥对
密钥随产品分发,等同于公开。攻击者无需任何凭据,取内置密钥对构造Authorization头即可通过结构解析,而验签环节已在第一步被 IsFree=1 短路。
4.4 SQL拼接点:orgId未经任何转义直拼WHERE子句
GetAnonymousTPlusToken 的服务实现先用orgId查询账套,查账套的实现落在 AccountBE.cs:
public AccountStruct GetAccountByCloudOrgId(string cloudOrgId)
{
AccountStruct result = new AccountStruct();
UFTable uFTable = new UFTable();
uFTable = GetAllAccounts("CloudOrganizationID=N'" + cloudOrgId + "' AND OpenCloudAppState=1 AND cState<100 ");
...
}
ILSpy反编译AccountBE.cs,红框处orgId未经任何转义直接拼入WHERE子句
cloudOrgId 即被请求头覆盖后的 orgId,未经任何参数化或转义直接拼入WHERE子句,并以TPlusDBAdmin(sysadmin)身份执行。将攻击载荷代入后,拼接结果为引号闭合、分号分隔的堆叠语句,尾部条件被注释吞掉,语法完整可执行,与ERRORLOG中的配置变更记录完全对应。
4.5 规则为什么没有拦:Authorization头不在检查范围
T+自带请求过滤组件(InterceptService)。实测在请求体中注入常规测试字符会被拦截,返回"请求中存在危险数据!",证明WAF在线。但审计其检查范围代码可以看到,其遍历的键集合为查询串与表单参数,另有请求体原文与URL的检查,全程不读取Authorization请求头。
ILSpy反编译InterceptService,红色箭头依次为查询串、表单参数与请求体原文的检查来源,全程未读取Authorization请求头
这就是payload藏于请求头即可绕过全部关键词过滤的原因,也是IIS日志始终看不到载荷的原因。
4.6 攻击链逐字段对应
至此全链路闭环,攻击者请求的每个元素都能在代码中找到落点:
| 攻击者请求元素 |
代码落点 |
结果 |
查询串 IsFree=1 |
RestHandler.cs 第152行鉴权分支 |
验签与会话校验整体跳过 |
Authorization头中的 appKey/authInfo |
产品内置硬编码密钥表(约30组) |
通过Authorization结构解析 |
Authorization头中的 orgId |
RestHandler.cs 第160行参数覆盖 |
覆盖请求体同名参数进入业务方法 |
orgId 进入SQL |
AccountBE.cs 第2237行直拼WHERE子句 |
以sysadmin身份堆叠执行任意SQL |
| payload藏于请求头 |
InterceptService.cs 检查范围不含Authorization头 |
规则全程无拦截 |
五、复现验证
审计结论经以下实测闭环(2026年10月12日至13日,复现环境与FREB捕获载荷的目标同源):
| 验证项 |
请求(已脱敏) |
结果 |
| 注入点存在 |
请求头orgId携带单引号 |
HTTP 200出错页(SQL语法错误,未捕获异常),证实orgId确实进入SQL |
| 堆叠执行 |
请求头orgId携带延时指令,另设对照组 |
7.16秒对0.88秒,延差6.28秒,任意SQL堆叠执行确认 |
| 攻击者操作复现 |
请求头orgId代入FREB载荷原文 |
ERRORLOG出现xp_cmdshell配置变更记录,与受害机记录同构 |
| 命令执行回显 |
xp_cmdshell输出落盘后HTTP读回 |
whoami回显nt service\mssqlserver,即以SQL Server服务账户执行系统命令 |
| 未授权业务接管 |
请求头orgId代入真实组织标识 |
返回有效access_token,等同企业管理员登录态,可调用全量业务API |
复现请求与FREB抓取的攻击者请求逐字节同构,仅测试命令不同,证明审计还原的链路即攻击者实际使用的链路。
PoC验证(Burp请求框架,关键载荷已脱敏):
POST /tplus/api/v2/collaborationapp/GetAnonymousTPlusToken?IsFree=1 HTTP/1.1
Host: 目标地址
Content-Type: application/x-www-form-urlencoded
Authorization: 攻击载荷BASE64编码(为避免滥用,此处不公开)
(请求体为固定占位参数,会被管线覆盖,不会被实际使用)
判定方式:注入点探测时,可利用版本返回HTTP 200加出错页(SQL语法错误未捕获);堆叠执行确认时,含延时指令的请求响应耗时明显大于对照组,即任意SQL堆叠执行成立。
PoC注入探测实测:orgId单引号使服务端返回出错页,证实该参数进入SQL拼接
PoC时间盲注实测:含延时指令的请求响应耗时约6.4秒,对照组不足1秒,堆叠执行确认
开发验证工具实测汇总:注入探测、时间盲注与xp_cmdshell命令回显全部命中(仅用于授权安全测试)
六、修复机制定位与残留风险
为确认官方修复情况,我们对四个核心程序集做了被攻击版本与修复版本的比对。修复版本程序集提取自二次勒索事件后的修复环境,文件时间为10月11日,确认为攻击后部署的修复版本。
新增的注入过滤正则:未接线的死代码。 修复版本新增了注入过滤逻辑,定义了一个注入特征正则及对应的检测函数:
private static readonly Regex sqlInjectionPattern = new Regex(
"(['\"])\\s*(or|and|union|select|insert|update|delete|drop|like|exec|chr|mid|master|truncate|char|declare)\\s*['\"=()]",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
public static bool IsPossibleSqlInjection(string input)
{
if (string.IsNullOrEmpty(input)) { return false; }
return sqlInjectionPattern.IsMatch(input);
}
ILSpy反编译修复版本的HttpInterceptor,红框处为新增的注入过滤正则定义
但对四个核心程序集做二进制检索,该检测函数仅在定义处自身命中,没有任何调用方。即该正则补丁未接线,是一段未生效的死代码。实测佐证:修复环境上对请求体注入特定变形语句依然通过,布尔盲注二分可用。
实际生效的修复:鉴权扩展到IsFree场景。 修复版本的有效修复不在规则关键词,而在鉴权链。IsFree=1 不再完全跳过校验,携带异常字符的 orgId 在验签层即被拒绝(返回EXSM0002),注入payload无法到达SQL拼接点,命令执行路径就此关闭。
修复前后能力对照如下:
| 能力 |
被攻击版本 |
修复版本 |
| IsFree=1跳过验签 |
存在 |
已修复(鉴权扩展,返回EXSM0002) |
| Authorization头orgId注入 |
可堆叠执行至命令执行 |
认证层拒绝 |
| 内置密钥对 |
硬编码泄露(约30组) |
仍存在,未更换 |
| 规则覆盖Authorization头 |
不覆盖 |
仍不覆盖,靠鉴权层间接拦截 |
七、影响版本与自查方法
受害环境日志中的账套数据版本字段不直接等于程序补丁号,因此建议以程序行为作为判定依据。若部署版本介于被攻击版本与修复版本之间,可按上文的判定方式实测自查:注入点探测返回出错页、延时请求响应耗时显著偏大,即为受影响版本。
检测是否已被此链路攻击,可按以下顺序排查:
- 检索SQL Server ERRORLOG中
xp_cmdshell、Ole Automation Procedures、sp_OACreate 的配置变更记录及其时刻;
- 在该时刻前后5分钟的IIS日志中,检索
GetAnonymousTPlusToken?IsFree=1 且响应200的POST请求(经nginx反代时客户端IP可能记录为127.0.0.1);
- 查询
sp_configure 'xp_cmdshell' 当前值,该配置跨重启持久,曾被利用的机器即使重装系统(不重装SQL实例)后仍可能为1;
- 检索
Eap_OpenAPILog 表中的异常调用记录。
八、防范建议
面对0day,我们想给大家几条务实的建议:
第一,尽量把这类承载财务与核心业务数据的系统收敛到内网。0day的特点是公开前无规则、无特征,漏洞扫描扫不出尚未公开的漏洞,指望扫描和特征库防住0day是不现实的。最有效的办法就是减少暴露,能不对外发布就不对外发布,确实需要远程访问的,通过VPN或访问白名单兜底。暴露面越小,被打中的概率越低。
第二,按第七节的方法做一次自查。重点看ERRORLOG里的配置变更记录和xp_cmdshell当前状态,这两条成本最低、指向最直接。
第三,保持数据库层面的最小权限。生产环境的xp_cmdshell与OLE自动化应保持关闭,数据库连接账户降权,对sp_configure配置变更设置告警。即使漏洞被利用,也能让攻击者拿不到顺手的服务器权限。
第四,及时跟进官方修复。目前官方已有新版本补丁,但是否已经面向全部用户正式发布,建议咨询用友畅捷通官方客服或前往官网查看核实,并以官方答复为准。已部署该系统的企业,建议尽快联系官方确认自身版本的修复状态。
第五,如果发现已被攻击的迹象,不要重装系统,先保留日志与现场,及时联系专业团队处置。需要协助排查或处置的,可以随时联系Solar应急响应团队。
第六,防勒索AI疫苗(SAR)目前已支持Weaxor勒索家族相关病毒的密钥捕获。SAR的核心思路是在勒索软件启动加密行为的瞬间,从内存中捕获加密密钥并留存,让数据恢复不必完全依赖攻击者"守信"。截至2026年上半年,SAR已支持69个勒索家族、87种加密后缀的密钥捕获,累计输出47份专项解密方案。
SAR捕获勒索家族密钥的后台日志(示意图)
Solar勒索解密工具使用捕获的密钥完成恢复,6个被加密文件全部解密成功
九、IOC清单
| 类型 |
值 |
说明 |
| 攻击源IP |
117.62.223.95 |
江苏省南京市,代理IP特征,前三发注入请求 |
| 攻击源IP |
49.7.180.227 |
北京市,代理IP特征,第四发长耗时请求 |
| 入口请求 |
POST /tplus/api/v2/collaborationapp/GetAnonymousTPlusToken?IsFree=1 |
payload位于Authorization请求头,IIS日志不可见 |
| 加密器 |
C:\Windows\System32\uuAmyFeQV.exe(MD5:b76dd9d7a576d3653b52d9c4df177a78) |
weaxor家族,669KB,2026年9月30日19:43落地 |
| 勒索信 |
RECOVERY INFORMATION.txt |
TOR会话联系,邮箱datahelper@cyberfear.com |
| 加密后缀 |
.weax / .rox |
weaxor家族特征后缀,近期由.weax改为.rox |
| 硬编码密钥 |
产品内置appKey/appSecret密钥对(约30组) |
随安装包分发,修复版本仍未更换,具体值此处不公开 |
| 数据库特征 |
xp_cmdshell、Ole Automation Procedures、sp_OACreate的changed from记录 |
sp_configure配置跨重启持久 |