这是规范版 seal-security-nuget-demo(目标框架为 net9.0)的重定向分支。漏洞利用场景、控制器和密封包列表完全相同——只有 TargetFramework 不同。
它存在的原因是大多数企业客户无法按需迁移到最新的 .NET SDK。.NET 7 已于 2024 年 5 月 14 日停止支持,但真实的生产环境仍然基于它运行,原因可能是兼容性、认证或运维需求。这正是 Seal Security 的设计场景:当客户无法(或不愿)进行主版本升级时,Seal 会在相同版本下就地修补易受攻击的依赖项,不改变任何公共 API,也无需修改客户应用的代码。此演示让这种对话可以在客户实际使用的技术栈上进行,而不是要求他们先安装 net8/net9。
该分支通过 global.json 将 SDK 固定为 7.0.x,防止演示过程中意外升级。
此演示应用是一个简单的 ASP.NET Core 欢迎页面,使用 Newtonsoft.Json 12.0.2 将用户输入解析为配置对象。应用有一个名称字段——输入你的名字,点击 Go,它会显示 "Welcome, alice!"。在底层,它通过 Newtonsoft.Json 的 JsonConvert.DeserializeObject<NestedConfig>() 传递输入。仅此而已——完全是对流行 JSON 库的标准使用。
问题在于 Newtonsoft.Json 12.0.2(以及 13.0.1 之前的版本)存在 CVE-2024-21907——一个高严重性的拒绝服务漏洞,CVSS 评分为 7.5(高危)。此演示展示了 Seal Security 如何在不要求主版本升级的情况下就地修补该漏洞。
Newtonsoft.Json 的 JsonConvert.DeserializeObject<T>() 方法可能被精心构造的深层嵌套 JSON 载荷利用。当反序列化为类型化对象(POCO)时,该库的 JsonSerializerInternalReader 会执行真正的递归调用(CreateValueInternal → CreateObject → PopulateObject → SetPropertyValue → CreateValueInternal),导致栈溢出,进而引发应用程序崩溃(拒绝服务)。
应用接收用户输入并通过 Newtonsoft.Json 解析。如果输入是 URL,应用会先获取内容——这是配置加载器、API 测试器和 Webhook 接收器使用的现实模式:
public class NestedConfig
{
[JsonProperty("n")]
public NestedConfig? N { get; set; }
}
var config = JsonConvert.DeserializeObject<NestedConfig>(name);
正常输入: 输入 alice → 显示 "Welcome, alice!"
漏洞利用: 将以下 URL 粘贴到名称字段并点击 Go:
https://raw.githubusercontent.com/seal-sec-demo-2/json-payload/main/payload.json
应用检测到这是 URL,获取 json-payload(深层嵌套的 JSON {"n":{"n":{...}}}),并通过 Newtonsoft.Json 将其反序列化为递归的 NestedConfig 类——触发栈溢出。
JsonSerializerInternalReader 对每一层嵌套都通过 CreateValueInternal → CreateObject → PopulateObject → SetPropertyValue 进行递归。当嵌套深度达到约 5,000 层时,线程栈被耗尽,应用程序以 StackOverflowException 崩溃——进程立即终止(无法进行优雅的错误处理)。
利用此漏洞,攻击者可以:
公开可用的修复方案要求升级到 13.0.1 版本。然而,升级主版本通常会引入:
这使得"直接升级"的修复方案成为一个可能轻易消耗数周开发时间的项目——在此期间漏洞仍然暴露。
Seal 的修补版本(12.0.2-sp1)添加了递归深度保护,且不改变任何公共 API。该补丁:
MaxDepth 限制以防止无界递归这与 Newtonsoft.Json 13.0.1 中采用的缓解策略相同,被反向移植到 12.0.2 作为即插即用的替代品。
此演示还包含 Seal Security 可以修补的其他易受攻击的 NuGet 包:
log4net 的 XML 配置解析中存在 XML 外部实体(XXE)漏洞。能够控制 log4net 配置文件的攻击者可以:
关于
System.Net.Http的说明: 规范版 net9 演示还附带了一个易受攻击的System.Net.Http 4.3.0引用,对应 CVE-2017-0249。我们在本 net7 分支中省略了它,因为在 .NET 7 上System.Net.Http是 BCL 的一部分,独立的包引用是一个残留的元包——它与dotnet add package --source <local-nupkg>存在已知的边缘情况,而这正是 Seal CLI 应用密封版本的方式。移除它使seal fix步骤可靠运行,同时不改变演示的故事(HttpClient仍然正常工作;运行时提供它)。
Windows CLI 二进制文件在 v0.3.238 之后停止发布。v0.3.238 在 Windows 上完全支持 NuGet 修复。
详细的 Windows Server 安装和运行指南见 README-WINDOWS-SERVER.md。下面的快速入门以精简形式涵盖相同步骤。
PowerShell:
$env:SEAL_TOKEN = "your-seal-token-here"
$env:SEAL_PROJECT = "nuget-demo-net7"
cd seal-security-nuget-demo-net7
# 还原(从 nuget.org 和 Seal 源拉取——见 nuget.config)
dotnet restore
# 构建并运行
dotnet build
dotnet run
打开 http://localhost:5000 — 应用正在使用易受攻击的依赖项运行。
在名称字段中输入 alice,点击 Go。你应该看到:"Welcome, alice!"
将以下 URL 粘贴到名称字段并点击 Go:
https://raw.githubusercontent.com/seal-sec-demo-2/json-payload/main/payload.json
未修补的结果: 浏览器显示错误/连接重置——应用在 JsonSerializerInternalReader.CreateValueInternal 中以 StackOverflowException 崩溃。进程已终止。
# (可选——上面已完成)首先还原依赖项
dotnet restore
# 运行 Seal CLI 修复漏洞
seal fix . --mode remote -v
# 再次还原以拉取密封版本
dotnet restore
# 构建并运行修补后的应用
dotnet build
dotnet run
应用现在使用修补版本(Newtonsoft.Json 12.0.2-sp1、log4net 2.0.5-sp1)。
修补后的结果: 粘贴相同的漏洞 URL → 页面显示 "Blocked by Seal patch: MaxDepth of 64 has been exceeded." — Newtonsoft.Json 修补后的递归限制拒绝了深层载荷。服务器继续正常运行。
dotnet list package
你应该看到带有 -sp1 后缀的包,表示 Seal Security 补丁。
CLI 步骤必须添加在依赖项安装之后、最终构建之前。
# 1. 还原依赖项
dotnet restore
# 2. <--- 在此处运行 Seal CLI
$env:SEAL_TOKEN = "your-seal-token-here"
$env:SEAL_PROJECT = "nuget-demo-net7"
seal fix . --mode remote -v
# 3. 再次还原(以获取密封版本)
dotnet restore
# 4. 构建
dotnet build
| 模式 | 描述 |
|---|---|
all | 自动应用所有可用修复 |
remote | 仅应用在 Seal UI 中批准的修复 |
local | 仅应用 .seal-actions.yml 中定义的修复 |
此仓库中的 .seal-actions.yml 已列出 local 模式的三个密封覆盖项,因此 seal fix . --mode local -v 可以离线运行(仍需要 token 访问工件服务器)。
nuget.config 已预先配置为使用环境变量与 Seal Security 配合:
<configuration>
<packageSources>
<add key="Seal" value="https://nuget.sealsecurity.io/v3/index.json" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<packageSourceCredentials>
<Seal>
<add key="Username" value="%SEAL_PROJECT%" />
<add key="ClearTextPassword" value="%SEAL_TOKEN%" />
</Seal>
</packageSourceCredentials>
</configuration>
| 变量 | 描述 |
|---|---|
SEAL_TOKEN | 你的 Seal Security 访问令牌 |
SEAL_PROJECT | 项目 ID(例如 nuget-demo-net7) |
Seal CLI 需要出站 HTTPS(TCP 443)连接到:
cli.sealsecurity.io — 扫描/修复配置authorization.sealsecurity.io — 令牌验证nuget.sealsecurity.io — 密封 .nupkg 下载d2zko6i8myndc4.cloudfront.net — 提供实际密封工件的 CDN(.sealsecurity.io 主机名重定向到此)api.nuget.org / 标准 nuget.org 端点 — 用于非密封依赖项防火墙打开后从 PowerShell 验证:
Test-NetConnection cli.sealsecurity.io -Port 443
Test-NetConnection authorization.sealsecurity.io -Port 443
Test-NetConnection nuget.sealsecurity.io -Port 443
Test-NetConnection d2zko6i8myndc4.cloudfront.net -Port 443
所有连接都应报告 TcpTestSucceeded: True。
12.0.2-sp1 是 12.0.2 的二进制兼容即插即用替代品。此演示使用的包:
| 包 | 易受攻击版本 | 密封版本 | CVE | CVSS |
|---|---|---|---|---|
| Newtonsoft.Json | 12.0.2 |
Seal 源中可用的其他密封 NuGet 包(不在此演示中,仅供参考):
MIT 许可证 — 详情请参阅 LICENSE 文件。
| 项目 | 重要性 |
|---|
global.json 将 SDK 固定为 7.0.x,rollForward: latestFeature | 防止并排安装 net8/net9 的机器在演示中途静默切换 SDK。 |
System.Configuration.ConfigurationManager 固定为 7.0.0 | 规范版 net9 演示使用 8.0.0,它仅面向 net8,在 net7 上无法还原。7.0.0 具有 log4net 所需的相同 API 表面。 |
csproj 中抑制 NU1701 | log4net 2.0.5 声明了一个旧版 net4x TFM,.NET 7 在运行时接受但在还原时发出警告。该警告仅为外观问题;抑制它可在演示期间保持构建输出干净。 |
| Windows x64 的 Seal CLI v0.3.238 | 最后一个附带 Windows 二进制的版本;完全支持 NuGet 修复。Windows 二进制文件在此版本之后停止发布,因此不要建议更新版本。 |
| 12.0.2-sp1 |
| CVE-2024-21907 |
| 7.5 高危 |
| log4net | 2.0.5 | 2.0.5-sp1 | CVE-2018-1285 | 9.8 严重 |
| 包 | 易受攻击版本 | 密封版本 | CVE | CVSS |
|---|
| log4net | 2.0.0 | 2.0.0-sp1 | CVE-2018-1285 | 9.8 严重 |
| System.Net.Http | 4.3.0 | 4.3.0-sp1 | CVE-2017-0249 | 7.3 高危 |
| Snappier | 1.1.0 | 1.1.0-sp1 | CVE-2023-28638 | 7.0 高危 |
| jQuery.Validation | 1.17.0 | 1.17.0-sp1 | CVE-2021-21252 | 7.5 高危 |