深入剖析.NET史上最严重漏洞:请求走私与CVE-2025-55315

本文详细解析了被微软评为CVSS 9.9分的.NET请求走私漏洞CVE-2025-55315,深入探讨了HTTP请求走私的工作原理、该漏洞的具体利用方式、攻击者可能造成的危害、微软的修复方案以及开发者应采取的防护措施。

理解史上最严重的.NET漏洞:请求走私与CVE-2025-55315

我承认,这是一个非常有“点击诱饵”性质的标题,但微软已经给这个漏洞打出了9.9的CVSS评分,这是他们迄今为止给出的最高分。是时候恐慌了吗?在这篇文章中,我试图提供更多的背景信息。我将解释请求走私漏洞通常是如何工作的,在本案例中它如何起作用,攻击者能利用它做什么,漏洞是如何被修复的,以及你可以做些什么来保护自己。

警告: 我不是安全专家,所以请不要将本文中的任何内容视为金科玉律或建议。我只是一个试图理清头绪的开发者。😄 本文中的所有细节均基于原始公告中提供或引用的信息。

什么是CVE-2025-55315漏洞?

2025年10月14日,在一个标准的微软“补丁星期二”,微软发布了所有受支持.NET版本的新版本,并发布了一份安全公告:Microsoft Security Advisory CVE-2025-55315: .NET Security Feature Bypass Vulnerability。该公告的高层摘要写道:

ASP.NET Core 中对 HTTP 请求的不一致解释(‘HTTP 请求/响应走私’)允许经过授权的攻击者通过网络绕过安全功能。

建议是“修补你所有的东西”,但真正的新闻点是这个漏洞获得了CVSS 10分制下的9.9分,这听起来相当糟糕!.NET 安全负责人 Barry Dorrans(又名 blowdart)在原问题的评论中解释了评分背后的理由:

这个漏洞使得 HTTP 请求走私成为可能,单就 ASP.NET Core 本身而言,其严重性远不会那么高,但我们不是那样评分的… 相反,我们是基于该漏洞可能如何影响构建在 ASP.NET 之上的应用程序来评分的。请求走私允许攻击者将一个额外请求隐藏在另一个请求中,而这个隐藏请求能做什么则非常依赖于具体的应用程序。被走私的请求可能导致你的应用程序代码:

  • 以不同用户身份登录(EOP)
  • 发起内部请求(SSRF)
  • 绕过 CSRF 检查
  • 执行注入攻击 但我们不知道具体什么是可能的,因为这取决于你如何编写你的应用程序。

这听起来确实很吓人!😱 所以你可以理解这个问题引起的惊愕,特别是考虑到微软在解释“你如何编写你的应用程序”的确切含义时表现出的犹豫。出于好奇,我决定深入研究,以真正理解这个漏洞,它可能如何影响你,以及“你如何编写你的应用程序”可能意味着什么。

请求走私是如何工作的?

在我们讨论 ASP.NET Core 中实际被修补的漏洞及其工作原理之前,我认为了解被称为 HTTP 请求走私 的通用漏洞利用类别的一些背景知识非常重要。

HTTP 请求走私是一种已知已久的安全漏洞利用(根据维基百科,它首次在2005年被记录在案)。它的根本原因在于,当你有两个不同的服务器处理一个 HTTP 请求时(例如一个服务器和一个代理服务器),并且这两个服务器在处理“无效”HTTP 请求的方式上存在差异。

在所有 HTTP 请求走私的案例中,漏洞利用都是通过创建一个看起来有点像两个 HTTP 请求粘在一起的无效 HTTP 请求(有时只是模糊的请求)来实现的。

总而言之,漏洞利用的工作原理大致如下:

  1. 代理服务器接收到模糊的 HTTP 请求
  2. 代理服务器(未经修改地)将请求转发给目标服务器
  3. 服务器将模糊的请求解释为发送给服务器的两个流水线式 HTTP 请求,并分别处理它们。

我认为通过一个例子来理解问题是最简单的,所以下面的请求展示了来自2005年原始论文的一个例子。

请注意,这不是 CVE-2025-55315 中请求走私漏洞的示例,它只是一个代表通用请求走私的示例。

让我们想象攻击者发送一个看起来像这样的 HTTP 请求:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
POST /some_script.jsp HTTP/1.0
Connection: Keep-Alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 9
Content-Length: 204

this=thatPOST /vuln_page.jsp HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 95

param1=value1&data=<script>alert("stealing%20your%20data:"%2bdocument.cookie)</script>&foobar

这个请求的重要特点是第一个请求中有两个 Content-Length 头(走私请求中后面还有一个),并且值不同:9 或 204。这就是漏洞利用的核心;HTTP 代理和 HTTP 服务器对这两个头部中的哪一个表示认可,正是导致漏洞的原因。

让我们逐步看看漏洞利用是如何工作的:

  1. 攻击者发送上述 HTTP 请求。
  2. HTTP 代理接收到请求,注意到重复的 Content-Length 头部,并接受第二个头部,即长度为 204。这意味着请求的其余部分都被视为消息体,就代理而言似乎没问题。
  3. HTTP 代理将请求转发到目标服务器。
  4. 该服务器也注意到重复的 Content-Length 头部,但它取第一个头部,长度为 9。
  5. 服务器读取消息体的 9 个字节(即 this=that)并将其视为整个请求。就服务器而言,整个(有效)请求已被接收,它将其余数据视为一个全新的请求。
  6. 这意味着目标服务器看到一个全新的 HTTP 请求要处理,POST /vuln_page.jsp,并将其视为一个新请求。

这就是问题的核心;代理看到一个请求,而目标服务器看到两个——第二个请求被“走私”过了代理,到达了服务器。

这里展示的请求走私技术,即拥有多个 Content-Length 头部,并不是你通常看到引用的“标准”示例,但我在这里使用它是因为它在很多方面更容易理解。标准的请求走私攻击是当你同时发送一个 Content-Length 头部和一个 Transfer-Encoding: chunked 头部(后者将消息体长度指定为消息体本身的一部分)时。和之前一样,请求走私漏洞利用依赖于代理和目标服务器在解释这些冲突头部时的差异。

因此,正如你所见,请求走私使得向目标服务器发送一个中间代理服务器未曾见过的秘密请求成为可能。在下一节中,我们将看看为什么这是一个坏事,以及它如何被利用。

攻击者如何利用请求走私?

表面上看,请求走私可能不是什么大事。服务器看到两个请求,那又怎样?反正你总是可以向服务器发送两个请求,对吧?

嗯,也对也不对。请求走私的问题实际上全在于代理服务器和目标服务器之间的不匹配。由于这种不匹配,以及取决于目标应用程序具有的行为和期望,攻击者可以利用请求走私来:

  • 将恶意数据反射给易受跨站脚本攻击的网站上的其他用户。
  • 用不良数据毒化缓存。
  • 从客户端请求中泄露身份验证凭据或其他数据。
  • 调用不应公开访问的端点(因为代理会阻止外部访问它们)。
  • 替换/覆盖由代理处理的认证控制。
  • 在易受开放重定向攻击的网站上将用户重定向到恶意站点。
  • 以及其他……

如你所见,这些都是非常糟糕的,所以你大概能理解为什么会给出 9.9 的评分了!😱

话虽如此,值得一提的是,并非所有这些攻击对所有应用程序都会奏效。其中一些最容易理解的漏洞利用版本是当代理不仅仅“盲目”地转发请求,而是以某种方式验证或增强请求时。

例如,如果你在服务器前面有一个代理,负责处理 TLS 终止和使用证书进行客户端身份验证和识别,那么请求走私可用于绕过这些检查并插入你自己的身份信息。

作为该攻击的一个例子,下面的 HTTP 请求演示了使用 Content-LengthTransfer-Encoding 请求走私攻击来向前端代理“隐藏”对 /admin 的请求,并插入一个恶意的 X-SSL-CLIENT-CN 头部,该头部通常由前端代理添加:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
POST /example HTTP/1.1
Host: some-website.com
Content-Type: x-www-form-urlencoded
Content-Length: 64
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
X-SSL-CLIENT-CN: administrator
Foo: x

在这个例子中,服务器假设 X-SSL-CLIENT-CN: administrator 头部是由代理添加的,因此服务器假设代理已经完成了所有必要的身份验证和授权。攻击者能够以完全不同的用户身份执行请求。

显然,只要你有一个执行某些功能的前端代理,请求走私就是一个大问题。但即使它本质上是一个“哑”代理,请求走私仍然可以用来从其他用户的请求中窃取和泄露数据,即使被攻击的站点不易受跨站脚本或其他漏洞的攻击。

在这些攻击中,仅仅拥有显示用户提供数据(即使经过净化)的功能,就足以窃取其他用户的凭据。所以像显示用户名或评论这样简单的事情可能就足够了。

这篇文章已经够长了,而且有太多不同的攻击方式,所以我将到此为止,不再深入探讨漏洞利用。如果你想了解更多可能性以及简单的漏洞利用解释和示例,我推荐 PortSwigger 关于利用请求走私的文档。

请求走私只适用于我有代理的情况吗?

一般来说,每当人们谈论请求走私时,他们通常会谈论你拥有多个服务器的情况:典型例子就是我目前讨论的代理服务器和目标服务器。但不要被愚弄了,即使你没有严格使用代理,这些问题和漏洞也可能适用。

漏洞的关键特征在于,两个“系统”之间存在混淆的可能性,无论它们是否都是完整的“服务器”。这显然适用于代理服务器,但也可能适用于你的应用程序,如果你正在做任何读取/操作/转发请求流的事情,或者在同一应用程序内部存在混淆的可能性。

对于 ASP.NET Core 应用程序,如果你正在使用 HttpRequest.BodyHttpRequest.BodyReader 或其他类似方法,那么即使你没有明确使用代理服务器,你也可能容易受到攻击。即使你不认为你的应用程序是代理或使用代理,如果你在做“类似代理”的事情,那么你可能是脆弱的。

换句话说,如果你在 ASP.NET Core 中直接读取、操作或转发请求流,而不是仅仅依赖内置的模型绑定,那么你可能面临请求走私攻击的风险。很难枚举所有的攻击向量,因此你应该将任何这样做的代码视为潜在的利用途径。

我们现在已经介绍了请求走私在一般情况下是如何工作以及如何被利用的,现在是时候看看 .NET CVE-2025-55315 漏洞中针对的特定请求走私版本了。

CVE-2025-55315 中的请求走私是如何工作的?

正如我们所见,HTTP 请求走私是一种通用技术,依赖于代理和服务器在解析 HTTP 请求方式上的差异。到目前为止我已经展示了两种具体版本:重复的 Content-Length 头部,以及 Content-Length/Transfer-Encoding 混淆,但这些并不是全部。这些方法还有变体也会导致请求走私。

CVE-2025-55315 中的请求走私漏洞依赖于一种变体,这种变体(据我所知)最早由 Jeppe Bonde Weikop 在 2025 年 6 月的博客上报告。这种变体依赖于 Transfer-Encoding块扩展功能。

本节中的所有细节和图片均基于原始帖子中的描述和示例。那篇帖子非常出色,所以如果你想获得比这里更详细的解释,你一定要读一读,然后你可以跳过我这里提供的缩略版本。

为了理解这个漏洞,我们将首先看看分块传输编码是如何工作的,以及什么是块扩展。然后我们将看看无效的行尾如何导致对请求的不同解释。最后,我们将看看这种解释差异如何为请求走私打开大门,以及 ASP.NET Core 如何解决了这个问题。

Transfer-Encoding: chunked 和块扩展

为了理解这个漏洞,我们首先需要了解 Transfer-Encoding: chunked 是如何工作的,以及块扩展如何使事情复杂化。

当你发送一个请求时,你可能并不总是事先知道你发送的请求有多大。让我们举一个将 .NET 对象序列化为 JSON 放入请求体的实际例子。唯一能确切知道序列化数据大小的方法就是实际序列化它。所以你可以先序列化数据到内存中,然后再写入请求,但如果数据非常大,那么可能会导致分配大数组的问题。

相反,Transfer-Encoding: chunked 允许以多个“块”发送请求数据。你需要知道每个单独块的大小,但不需要知道数据的总大小,或者有多少个块。这很适合序列化到一个小缓冲区,将该小缓冲区作为一个块发送,然后重用该缓冲区序列化下一部分,直到序列化完整个对象。

就 HTTP 请求本身而言,每个块由一个头部和一个主体组成。头部由一个十六进制格式的字节数后跟一个 \r\n(CRLF)行结束符组成。然后块主体是指定数量的字节,后跟另一个 \r\n。你可以有任意多的块,请求将持续传递,直到你发送一个长度为 0 的块,表示请求结束。

作为一个例子,下面的 HTTP POST 显示向端点发送一些 JSON,但 JSON 是作为三个不同的块发送的:

  • 块 1:头部是 9,表示将发送 9 个字节(后跟 \r\n),然后是块主体中的 9 个字节 JSON 文档开头,同样后跟 \r\n
  • 块 2:头部是 e,表示将发送 14 个字节(14 的十六进制是 e)(后跟 \r\n),然后是 JSON 文档结尾的剩余 14 个字节,后跟 \r\n
  • 最终块是一个“空”块,0\r\n\r\n,表示请求结束。

我们很快就会看到行结束符非常重要,所以下图展示了与上面相同的 HTTP 请求,但包含了行结束符:

这就是“正常的”分块传输编码,现在我们来说说块扩展。块扩展是 HTTP 1.1 协议的一部分,它允许向各个块添加键值对形式的元数据。下面的例子展示了与之前相同的请求,但在第二个块中有一个块扩展 ;foo=bar

块扩展由块头部长度后的 ; 表示,后跟一个或多个 key=value 形式的键值对。重要的是要理解块扩展不是请求处理程序看到的数据的一部分;块扩展只是关于各个块的元数据。并且,长话短说,它们完全没用 😅。最接近的近似是,没有人关心块扩展;客户端实现不发送它们,服务器只是忽略它们。

如果是这样,它们怎么会成为 .NET 中如此严重问题的根源呢?问题在于实现如何忽略它们……

具有不正确行尾的无效块扩展

在 HTTP 中,客户端和服务器实现通常试图遵循“发送时要保守,接收时要宽容”的健壮性原则。不幸的是,正是这种宽容有时会让我们陷入困境。毕竟,正是对于同时包含 Content-LengthTransfer-Encoding 头部的请求的宽容,才是原始请求走私漏洞利用的根本原因。

注意,HTTP 1.1 RFC 现在禁止同时转发这两个头部,正是为了避免请求走私攻击。

但对于块扩展来说,宽容通常是意外地内置在服务器实现中的。鉴于没有任何实现实际上对块扩展做任何事情,在解析块头部时处理它们的规范方法就是忽略它们。当解析到 ; 时,通常只是寻找行尾,并忽略其间的一切。

对于 ASP.NET Core(在修复之前),当在块头部找到 ; 时,Kestrel 会“解析”扩展,但实际上,它会搜索回车符 \r,然后检查接下来的 \n,跳过其间的一切,有点像这样(与原代码相比非常简化):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
private void ParseExtension(ReadOnlySequence<byte> buffer)
{
    while(true)
    {
        // Chunk-extensions not currently parsed
        // Just drain the data
        var extensionCursor = buffer.PositionOf(ByteCR);
        var suffixBuffer = buffer.Slice(extensionCursor); // skips over extensionCursor bytes

        var suffixSpan = suffixBuffer.Slice(0, 2).ToSpan();

        if (suffixSpan[1] == '\n')
        {
            // We consumed the \r\n at the end of the extension, so switch modes.
            return;
        }

        // Otherwise, keep reading data until we do find \r\n
        buffer = ReadMoreData();
    }
}

ASP.NET Core 中的实现并不特别;大多数服务器只是跳过字节直到找到 \r\n。大问题是服务器究竟如何搜索 \r\n。如果它们看到单独的 \r 或单独的 \n 会发生什么?它们会将其视为与 \r\n 相同吗?如果发现未配对的 \r\n,它们会抛出错误吗?或者它们会忽略它并继续寻找 \r\n 吗?

这种模糊性正是 CVE-2025-55315 请求走私漏洞的核心。代理和服务器实现在处理块头部中单独的 \r\n 的方式上的差异,使得可以利用这种模糊性进行请求走私攻击。

请注意,根据 RFC,实现者不得将 \r\n 视为块头部的“有效”行终止符,并且 \r\n 不允许出现在块头部的其他地方,因此正确的实现必须拒绝在块头部包含这些单独行结束符的请求。

为了完全清楚,下面的例子与之前的实现相同,但在第二个块的块扩展中有一个无效的块头部。块扩展不是以 \r\n 结尾,而是以单个 \n 结尾:

这就是请求走私漏洞的根本原因,所以在下一节中,我们将看看如何利用这一点来制作恶意的 HTTP 请求。

利用无效块扩展进行请求走私

正如其他请求走私的例子一样,块扩展方法依赖于代理与后续服务器在解析请求方式上的差异。这种差异意味着代理看到一个请求,而目标服务器看到两个请求,并允许我之前讨论的所有相同的漏洞利用。

如前所述,这些例子来自这篇出色的博客文章,因此请参阅该文章以获取更多细节、攻击的变体以及利用该漏洞的其他方法。

下面的示例展示了一个恶意 HTTP 请求,它利用代理和目标服务器在处理行结束符方式上的差异,将对 /admin 端点的请求走私过去。我们可以想象代理通常被配置为自动拒绝到 /admin 的请求,而服务器假设代理会为我们处理此事。

在这个例子中,攻击者通过发送 2;\n 创建一个格式错误的块扩展头部。; 确保代理和服务器都将该头部视为块扩展,但使用 \n 而不是 \r\n 会导致不同的解析:

  • 代理只看到一个请求:
    • 它将 \n 视为块头部的“有效”行结束符。
    • 然后它将 xx 视为块主体。
    • 47 是下一个块头部。
    • 接下来的 71 个字节(47 是十六进制,即十进制的 71)被视为块主体。
    • 最后是空块。
  • 服务器看到两个请求:
    • 服务器忽略单独的 \n,并一直跳过直到 xx\r\n
    • 然后它将 47 视为块主体。
    • 它看到一个结束块 0\r\n\r\n,并认为请求结束了。
    • 剩余的数据被视为一个完全独立的请求,其主体仅包含一个空块。

这几乎是能想到的最简单的例子,但你基本上可以以我先前描述的所有方式利用这种差异。确切地说,这对你的应用程序意味着什么很难说,但考虑到各种安全绕过、凭据窃取和注入攻击都是可能的,就很容易理解为什么这个漏洞获得了 9.9 的 CVSS 评分。

我发现的一个非常有趣的事情是查看其他语言(如 Python aiohttp 和 Ruby puma 服务器)针对相同漏洞的安全公告,这两个公告都只给出了中等严重性评级。在 netty 中甚至给出了低严重性。据我所知,这些服务器基本上与 ASP.NET Core 一样容易受到攻击,所以这只是一个有趣的数据点,我认为这反映了微软确实希望确保这个问题得到应有的关注,并且客户会修补他们的应用程序!

漏洞是如何修复的?

与大多数针对请求走私的修复一样,解决方案是停止对块头部中单独的行结束符的处理方式采取宽容和/或模糊的态度。在 ASP.NET Core 中,修复该问题的 PR 通过显式检查任何行结束符来实现,而不仅仅是寻找 \r。如果它发现一个行结束符并且它严格不是 \r\n,那么 Kestrel 现在会抛出一个 KestrelBadHttpRequestException 并返回 400 响应。

我要提一下,有一个 AppContext 开关,可以在你修补应用程序后选择启用危险/易受攻击的解析行为,但请不要使用它,我相信没有真正好的(或安全的)理由这样做。😅

该漏洞已在 ASP.NET Core 中修复,那么你应该怎么做呢?

你应该做什么?

显然,好消息是 ASP.NET Core 有修复方案。正如原始问题中所描述的,重要的是尽快更新到最新受支持的 ASP.NET Core 版本。

没有公开证据表明该请求走私漏洞在野外被利用,但考虑到请求走私可能被利用的方式如此之多,我们甚至能知道吗?🤔

这意味着你应该更新你的 .NET 8、.NET 9 或 .NET 10 版本:

易受攻击的版本 最低已修复版本
.NET 10 10.0.0-rc1 - 10.0.0-rc2
.NET 9 9.0.0 - 9.0.9
.NET 8 8.0.0 - 8.0.20

如果你在 .NET Framework 上使用 ASP.NET Core 2.3,那么你需要更新你的 Microsoft.AspNetCore.Server.Kestrel.Core 版本:

易受攻击的版本 最低已修复版本
Microsoft.AspNetCore.Server.Kestrel.Core 2.0.0 - 2.3.0

如果你进行应用程序的独立部署,则需要更新到已修复的版本,然后重新部署你的应用程序。

那么如果你使用的是旧版本的 .NET Core 呢?嗯,那你就无法打补丁…… HeroDevs 为不受支持的 .NET 版本提供额外支持(并已确认他们将在 .NET 6 中打补丁),但据我所知,这个漏洞基本上存在于所有版本的 .NET Core 中。我个人测试到 .NET Core 3.0,并且我可以确认漏洞存在,而且不会有补丁给你。最好的办法是更新到受支持的 .NET 版本。

⚠️ 如果你使用 <= .NET Core 3.0、.NET Core 3.1、.NET 5、.NET 6(除非由 HeroDevs 支持)或 .NET 7 运行 ASP.NET Core,那么你是易受攻击的,并且没有补丁。你应该尽快更新到受支持的 .NET 版本。讽刺的是,如果你被困在旧的 .NET Framework Web Forms 或 MVC 应用程序上,你显然不易受攻击。

值得注意的是,如果你被困在这些旧的框架版本上并且无法升级,那么保护自己的最佳方法可能是确保在你的应用程序前面有一个被确认不易受攻击的代理(尽管显然你可能容易受到其他漏洞的攻击 😅)。例如,Azure App Services (AAS) 确认在 AAS 中运行的应用程序不再易受攻击,即使你还没有更新,因为 AAS 使用的代理(本身是一个基于 YARP 的 ASP.NET Core 代理)已经打了补丁。通过在代理级别阻止请求,模糊的请求永远不会到达你的应用程序,因此你受到了保护。

不幸的是,目前尚不清楚如果你使用 AAS 以外的服务托管应用程序,你的处境究竟如何。甚至连 IIS 也尚未被确认为安全或易受攻击,但我在 Windows 11 电脑上进行了一些非官方测试,据我所知,它是易受攻击的。

请注意,原始问题中的一些人正试图通过使用 Content-Length/Transfer-Encoding 版本的请求走私来测试 IIS,但这不适用于这里;我们感兴趣的是基于块扩展的版本。

另一个有趣的点是,这只是 HTTP/1.0 和 HTTP/1.1 中的漏洞;它不是 HTTP/2 或 HTTP/3 中的漏洞。HTTP/2 和 HTTP/3 不支持分块传输编码,而是使用不同的、更高效的二进制分帧层进行数据流传输。因此,保护那些你无法升级的应用程序的另一种方法可能是强制要求客户端只能使用 HTTP/2 或 HTTP/3。但要注意,这很可能会破坏许多仍在使用 HTTP/1.1 的客户端!

你可以通过配置 Kestrel 端点来配置允许的 HTTP 协议。文档展示了各种方法来实现这一点。

如何知道你是否受影响?

“最简单”的方法来知道你是否受影响,是检查你用于运行应用程序的 .NET 版本,使用 dotnet --info 并验证你正在使用已修复的版本之一。如果是,你就是安全的。这是唯一“受支持的”确认安全的方法,也是我推荐的方法。

据我所知,目前还没有一个通用的工具可以指向一个应用程序来找出它是否易受攻击,尽管编写一个这样的工具应该是可能的。HeroDevs 的人员将原始 ASP.NET Core 修复中的功能测试重新实现为一个针对多个 ASP.NET Core 版本编译的控制台应用程序。他们用这个来确认未打补丁的 .NET 8 - .NET 10 版本是易受攻击的,而已打补丁的版本则不是。他们还用这个来验证 .NET 6 是易受攻击的,我调整了它来确认至少到 .NET Core 3.0 的所有版本都是易受攻击的。仓库中的测试通过向 ASP.NET Core 发送一个带有无效行结束符的分块传输编码请求来工作。当 ASP.NET Core“挂起”、等待更多数据,直到最终超时时,就识别出了漏洞。已“修复”的版本会立即抛出修复中包含的 BadRequest 异常。

我在网上看到一些关于这个测试的困惑;论点是“如果修复版和损坏版都抛出异常,那有什么关系”?然而,这不是测试的重点。Kestrel 暂停等待更多数据的事实表明,一个被走私的 HTTP 请求将会被执行。你可以在块扩展博客或 PortSwigger 的网站上看到这如何被利用来泄露数据或攻击其他用户。

我使用了类似的方法来尝试理解 IIS 是否可能易受攻击,通过向 IIS 发送相同的精心构造的 HTTP 请求,看看它是否挂起直到超时:在我的 IIS 版本(10.0.26100.1882)上它确实如此:

1
2
3
4
# Send an HTTP request with an invalid chunk extension, and see
# if it times out or if it's rejected with a 400... It times out 🙁
echo -e "GET / HTTP/1.1\r\nHost:\r\nTransfer-Encoding: chunked\r\n\r\n1;\n" \
  | nc localhost 80

那么这是否肯定意味着 IIS 是易受攻击的呢?不,不要相信我,我不是安全研究员 😅 但在你听到其他消息之前,我会谨慎行事,假设 IIS 不会保护你免受块扩展请求走私攻击。一般来说,我会对你基础设施中依赖的任何其他代理应用相同的规则。

最后提醒一下,尽管请求走私通常使用服务器前面的代理来描述和演示,但仅仅不使用代理并不意味着你自动安全。如果你在 ASP.NET Core 中直接读取、操作或转发请求流,而不是仅仅依赖内置的模型绑定,那么你可能会面临请求走私攻击的风险。最好谨慎行事,修补你的应用程序,并尽可能将操作请求的复杂性留给 ASP.NET Core。

总的来说,我会确保订阅 GitHub 上的 ASP.NET Core 问题,因为任何关于该问题的更多公告也可能在那里报告。

总结

在这篇文章中,我讨论了最近的 ASP.NET Core 漏洞:Microsoft Security Advisory CVE-2025-55315: .NET Security Feature Bypass Vulnerability。该公告警告了一个请求走私漏洞,它影响了几乎所有版本的 ASP.NET Core。

我描述了请求走私在一般情况下是如何工作的,使用一个简单的请求走私例子来展示 HTTP 解析中的模糊性如何导致 HTTP 代理和 HTTP 服务器以不同的方式处理相同的 HTTP 请求。这可能导致服务器看到两个请求,而代理只看到一个请求。

在逐步介绍了一个请求走私示例之后,我讨论了攻击者可以利用请求走私漏洞的一些方式。其中包括向应用程序的其他用户反射恶意数据、从客户端请求中泄露身份验证凭据或其他数据、调用不应公开访问的端点以及各种其他攻击。

接下来,我逐步介绍了在 CVE-2025-55315 中识别的特定请求走私漏洞。这利用了在使用分块传输编码发送请求时解析块扩展的模糊性。块扩展通常被所有服务器忽略,但宽容的处理可能导致代理和服务器之间的处理差异,从而为请求走私提供了途径。

最后,我逐步介绍了你应该采取的缓解步骤:修补你的应用程序。我描述了目前掌握的关于易受攻击或已修复的代理服务器的信息,以及旧版本的 ASP.NET Core 将不会获得补丁,因此将保持易受攻击状态(再次向支持 .NET 6 的 HeroDevs 致敬)。如果你在 AAS 中运行,那么你是安全的,否则,你需要与你的代理提供商核实以确定你是否易受攻击。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计