Leaking ObjRefs to Exploit HTTP .NET Remoting

Although already considered deprecated in 2009, .NET Remoting is still around. Even where developers might not expect it such as in ASP.NET web applications, both on-premises and on Azure.
尽管 .NET Remoting 已在 2009 年被认为已被弃用,但它仍然存在。即使在开发人员可能意想不到的地方,例如在本地和 Azure 上的 ASP.NET Web 应用程序中。

In this blog post, we will elaborate on an hidden attack surface in ASP.NET web applications that might unknowingly leak internal object URIs, which can be used to perform .NET Remoting attacks via HTTP, possibly allowing unauthenticated remote code execution.
在这篇博文中,我们将详细介绍 ASP.NET Web 应用程序中的隐藏攻击面,该攻击面可能会在不知不觉中泄漏内部对象 URI,从而可用于通过 HTTP 执行 .NET 远程攻击,从而可能允许未经身份验证的远程代码执行。

Introduction 介绍

.NET Remoting was already considered a legacy technology back in 2009:
早在 2009 年,.NET Remoting 就已经被认为是一种遗留技术:

This topic is specific to a legacy technology that is retained for backward compatibility with existing applications and is not recommended for new development. Distributed applications should now be developed using the Windows Communication Foundation (WCF).
本主题特定于保留旧技术是为了向后兼容现有应用程序,不建议用于新开发。现在应该使用 Windows Communication Foundation (WCF) 来开发分布式应用程序。

And while .NET Framework 4.8 appears to be the final major release of .NET Framework 4.x (i. e., there probably won’t be a 4.9 release) in favor of its cross-platform successor .NET Core (since version 5 only called “.NET”), it still is and certainly also will still be around for several years if not even decades. Many popular Microsoft products such as Exchange, SharePoint, or Skype for Business are built on .NET Framework / ASP.NET technology.
虽然 .NET Framework 4.8 似乎是 .NET Framework 4.x 的最终主要版本(即可能不会有 4.9 版本),但有利于其跨平台后继者 .NET Core(因为版本 5 仅称为“.NET”),它仍然存在,而且肯定还会存在几年,甚至几十年。许多流行的 Microsoft 产品(例如 Exchange、SharePoint 或 Skype for Business)都是基于 .NET Framework/ASP.NET 技术构建的。

In 2022, our blog post .NET Remoting Revisited already covered the internals and dangers of .NET Remoting in general. While the supported transports TCP and IPC are rather rarely found in the wild, the HTTP channel exposed via IIS / ASP.NET is available by default. So let’s have a look at it.
2022 年,我们的博客文章 .NET Remoting Revisited 已经全面介绍了 .NET Remoting 的内部结构和危险。虽然支持的传输 TCP 和 IPC 在野外很少见,但默认情况下可以使用通过 IIS / ASP.NET 公开的 HTTP 通道。那么让我们来看看吧。

HTTP Server Channel Chains
HTTP 服务器通道链

.NET Remoting services via HTTP transport can either be provided using a standalone listener or integrated in an ASP.NET web application via IIS. Depending on that, the call stack in front of the server channel chain looks differently:
通过 HTTP 传输的 .NET Remoting 服务可以使用独立侦听器提供,也可以通过 IIS 集成到 ASP.NET Web 应用程序中。根据这一点,服务器通道链前面的调用堆栈看起来会有所不同:

From there on, the default HTTP server channel sink chain created by HttpServerChannel.CreateDefaultServerProviderChain() looks as follows:
从那时起,由 HttpServerChannel.CreateDefaultServerProviderChain() 创建的默认 HTTP 服务器通道接收器链如下所示:

After deserializing the IMessage request message, it gets handed over to the DispatchChannelSink for dispatching.
IMessage 请求消息反序列化后,交给 DispatchChannelSink 进行调度。

We will focus on the IIS + ASP.NET scenario.
我们将重点关注 IIS + ASP.NET 场景。

Calling methods require knowledge of the object’s URI on which the method is to be called on. These may either be well-known names (i.e., registered types that are meant to be made available remotely, often referred to as “service name”) or randomly generated ones for objects that are returned by reference. The latter applies to types that derive from MarshalByRefObject. In such cases, the RemotingSurrogateSelector and RemotingSurrogate ensure that a ObjRef gets created and registered at the server and the ObjRef gets returned to the client instead of the object.
调用方法需要了解要调用该方法的对象的 URI。这些名称可以是众所周知的名称(即,旨在远程可用的注册类型,通常称为“服务名称”),也可以是为通过引用返回的对象随机生成的名称。后者适用于派生自 MarshalByRefObject 的类型。在这种情况下, RemotingSurrogateSelector 和 RemotingSurrogate 确保 ObjRef 在服务器上创建并注册,并且 ObjRef 返回到服务器客户端而不是对象。

By default, exploiting any of the publicly known vulnerabilities in .NET Remoting via HTTP requires knowledge of a valid object URI. A leaked ObjRef would work, though.
默认情况下,通过 HTTP 利用 .NET Remoting 中的任何公开已知漏洞需要了解有效的对象 URI。不过,泄露的 ObjRef 会起作用。

Leaking ObjRefs 泄漏 ObjRef s

One crucial aspect of this vulnerability is that within the call stack there are only two try … catch statements. The one in HttpRemotingHandler only returns a generic textual error message. The other in SoapServerFormatterSink/BinaryServerFormatterSink, however, creates a ReturnMessage and serializes it.
此漏洞的一个重要方面是调用堆栈中只有两个 try … catch 语句。 HttpRemotingHandler 中的仅返回一般文本错误消息。然而, SoapServerFormatterSink / BinaryServerFormatterSink 中的另一个创建 ReturnMessage 并将其序列化。

Within the ReturnMessage constructor, the current LogicalCallContext gets assigned to the message. That context “[p]rovides a set of properties that are carried with the execution code path during remote method calls.”
在 ReturnMessage 构造函数中,当前的 LogicalCallContext 被分配给消息。该上下文“[p]提供了一组在远程方法调用期间随执行代码路径携带的属性。”

To leak an ObjRef, there are two conditions to be met:
要泄漏 ObjRef ,需要满足两个条件:

  • There is a way to reach the exception handling in SoapServerFormatterSink/BinaryServerFormatterSink.
    有一种方法可以在 SoapServerFormatterSink / BinaryServerFormatterSink 中实现异常处理。
  • Some class instance deriving from MarshalByRefObject gets stored in the LogicalCallContext.
    一些从 MarshalByRefObject 派生的类实例存储在 LogicalCallContext 中。

We’ll first look at the former.
我们首先看前者。

Trust Issues 信任问题

In Finding and Exploiting .NET Remoting over HTTP using DeserialisationSoroush Dalili already noticed that it is possible to overwrite somewhat trusted values returned from HttpRequest with values from corresponding HTTP headers:
在使用反序列化通过 HTTP 查找和利用 .NET Remoting 中,Soroush Dalili 已经注意到可以用相应 HTTP 标头中的值覆盖从 HttpRequest 返回的某些可信值:

The HTTP verb could be changed to any arbitrary verb such as GET as long as the __RequestVerb header was set to POST.
只要 __RequestVerb 标头设置为 POST,HTTP 动词就可以更改为任意动词,例如 GET。

The service name could also be removed from the URL and could be sent in the __requestUri header.
服务名称也可以从 URL 中删除,并可以在 __requestUri 标头中发送。

This happens in the HttpHandlerTransportSink.HandleRequest(HttpContext) method:
这发生在 HttpHandlerTransportSink.HandleRequest(HttpContext) 方法中:

BaseTransportHeaders requestHeaders = new BaseTransportHeaders();

requestHeaders["__RequestVerb"] = httpRequest.HttpMethod;
requestHeaders["__CustomErrorsEnabled"] = HttpRemotingHandler.CustomErrorsEnabled(context);
requestHeaders.RequestUri = (string)context.Items["__requestUri"];

NameValueCollection headers = httpRequest.Headers;
String[] allKeys = headers.AllKeys;

for (int httpKeyCount=0; httpKeyCount< allKeys.Length; httpKeyCount++)
{
    String headerName = allKeys[httpKeyCount];
    String headerValue = headers[headerName];
    requestHeaders[headerName] = headerValue;
}

This trick can be used to pass validation and proceed to the SoapServerFormatterSink/BinaryServerFormatterSink:
这个技巧可用于通过验证并继续进行 SoapServerFormatterSink / BinaryServerFormatterSink :

GET /RemoteApplicationMetadata.rem?wsdl HTTP/1.1
Host: localhost
__RequestVerb: POST

Depending on the provided Content-Type, either the SoapServerFormatterSink or BinaryServerFormatterSink processes the request. As the requested object URI is probably not registered to a server identity, an exception gets thrown and returned in a ReturnMessage object:
根据提供的 Content-Type , SoapServerFormatterSink 或 BinaryServerFormatterSink 处理请求。由于请求的对象 URI 可能未注册到服务器身份,因此会引发异常并在 ReturnMessage 对象中返回:

Leaking ObjRefs to Exploit HTTP .NET Remoting

Known Suspects 已知嫌疑人

We have observed or suspect that the following libraries use the LogicalCallContext to store a MarshalByRefObject (most often a ObjectHandle), that leaks an ObjRef:
我们观察到或怀疑以下库使用 LogicalCallContext 存储 MarshalByRefObject (最常见的是 ObjectHandle ),从而泄漏 ObjRef :

The first one is also used if you add Application Insights to an ASP.NET web application for .NET Framework 4.5.x or if you enable Application Insights in the Monitoring tab during creation of an Azure App Service Web Application with ASP.NET 3.5 or 4.8 stack.
如果将 Application Insights 添加到 .NET Framework 4.5.x 的 ASP.NET Web 应用程序,或者在使用 ASP.NET 3.5 创建 Azure 应用服务 Web 应用程序期间在“监视”选项卡中启用 Application Insights,也会使用第一个4.8 堆栈。

Exploitation 开发

Note that with default configuration the deserialization in the SoapServerFormatterSink/BinaryServerFormatterSink happens under Code Access Security (CAS) restrictions with TypeFilterLevel.Low. That means no direct remote code execution.
请注意,使用默认配置时, SoapServerFormatterSink / BinaryServerFormatterSink 中的反序列化发生在 TypeFilterLevel.Low 的代码访问安全 (CAS) 限制下。这意味着不能直接执行远程代码。

But it is possible to use another bypass trick and an indirection to finally gain remote code execution:
但可以使用另一种旁路技巧和间接方法来最终获得远程代码执行:

Leaking ObjRefs to Exploit HTTP .NET Remoting

We won’t elaborate on that here.
我们在这里不做详细说明。

The Patch 补丁

The security updates in January 2024 changed the default behavior of parsing HTTP headers in HttpHandlerTransportSink.HandleRequest(HttpContext), and no longer allow overwriting of trusted values from HttpRequest with untrusted values from HTTP headers (AppSettings.LateHttpHeaderParsing defaults to false):
2024 年 1 月的安全更新更改了解析 HttpHandlerTransportSink.HandleRequest(HttpContext) 中 HTTP 标头的默认行为,并且不再允许使用 HTTP 标头 ( AppSettings.LateHttpHeaderParsing

diff --git a/System.Runtime.Remoting/Runtime/Remoting/Channels/Http/HttpHandlerTransportSink.cs b/System.Runtime.Remoting/Runtime/Remoting/Channels/Http/HttpHandlerTransportSink.cs
index 97738b7..3c112ba 100644
--- a/System.Runtime.Remoting/Runtime/Remoting/Channels/Http/HttpHandlerTransportSink.cs
+++ b/System.Runtime.Remoting/Runtime/Remoting/Channels/Http/HttpHandlerTransportSink.cs
@@ -4,6 +4,7 @@ using System.Collections.Specialized;
 using System.Globalization;
 using System.IO;
 using System.Net;
+using System.Runtime.Remoting.Configuration;
 using System.Runtime.Remoting.Messaging;
 using System.Web;
 
@@ -21,15 +22,24 @@ namespace System.Runtime.Remoting.Channels.Http
 			HttpRequest request = context.Request;
 			HttpResponse response = context.Response;
 			BaseTransportHeaders baseTransportHeaders = new BaseTransportHeaders();
-			baseTransportHeaders["__RequestVerb"] = request.HttpMethod;
-			baseTransportHeaders["__CustomErrorsEnabled"] = HttpRemotingHandler.CustomErrorsEnabled(context);
-			baseTransportHeaders.RequestUri = (string)context.Items["__requestUri"];
+			if (AppSettings.LateHttpHeaderParsing)
+			{
+				baseTransportHeaders["__RequestVerb"] = request.HttpMethod;
+				baseTransportHeaders["__CustomErrorsEnabled"] = HttpRemotingHandler.CustomErrorsEnabled(context);
+				baseTransportHeaders.RequestUri = (string)context.Items["__requestUri"];
+			}
 			NameValueCollection headers = request.Headers;
 			foreach (string text in headers.AllKeys)
 			{
 				string value = headers[text];
 				baseTransportHeaders[text] = value;
 			}
+			if (!AppSettings.LateHttpHeaderParsing)
+			{
+				baseTransportHeaders["__RequestVerb"] = request.HttpMethod;
+				baseTransportHeaders["__CustomErrorsEnabled"] = HttpRemotingHandler.CustomErrorsEnabled(context);
+				baseTransportHeaders.RequestUri = (string)context.Items["__requestUri"];
+			}
 			baseTransportHeaders.IPAddress = IPAddress.Parse(request.UserHostAddress);
 			Stream inputStream = request.InputStream;
 			ServerChannelSinkStack serverChannelSinkStack = new ServerChannelSinkStack();

You can make you web app vulnerable again by setting the microsoft:Remoting:LateHttpHeaderParsing app setting to true, for example, in the Azure Console:
您可以通过将 microsoft:Remoting:LateHttpHeaderParsing 应用程序设置设置为 true 再次使您的 Web 应用程序容易受到攻击,例如在 Azure 控制台中:

%SystemRoot%\System32\inetsrv\appcmd.exe set config "%WEBSITE_SITE_NAME%" /apphostconfig:"%APP_POOL_CONFIG%" /section:appSettings /+"[key='microsoft:Remoting:LateHttpHeaderParsing',value='true']"

Timeline 时间线

  • 2023-11-03: Report was filed in MSRC Researcher Portal.
    2023-11-03:报告已提交至 MSRC 研究人员门户。

  • 2023-11-03: Report status changed from New to Review / Repro.
    2023-11-03:报告状态从“新建”更改为“审核/重现”。

  • 2023-12-14: CODE WHITE added a note to the case that Azure App Services were also found to be affected by default with step-by-step instructions on how to create a vulnerable Web App instance using the ASP.NET 4.8 runtime stack.
    2023 年 12 月 14 日:CODE WHITE 添加了一个注释,指出 Azure 应用服务默认情况下也受到影响,并提供了有关如何使用 ASP.NET 4.8 运行时堆栈创建易受攻击的 Web 应用实例的分步说明。

  • 2023-12-28: MSRC closed the case with the following remark:
    2023年12月28日:MSRC结案,并发表以下评论:

    […] after careful investigation, we determined this case does not meet our bar for immediate servicing.
    […]经过仔细调查,我们确定此案例不符合我们立即维修的标准。

    This was followed by a usage recommendation for .NET Remoting:
    接下来是 .NET Remoting 的使用建议:

    .NET Remoting is a legacy product that is supported only for backward compatibility. It is not recommended for use across mixed-trust environments because it cannot maintain the separate trust levels between client and server. For example, you should never expose a .NET Remoting endpoint to the Internet or to untrusted clients. We recommend existing Remoting applications be migrated to newer technologies.
    .NET Remoting 是一个遗留产品,仅支持向后兼容。不建议在混合信任环境中使用它,因为它无法维护客户端和服务器之间单独的信任级别。例如,您绝对不应该将 .NET Remoting 端点暴露给 Internet 或不受信任的客户端。我们建议将现有的远程应用程序迁移到更新的技术。

  • 2024-01-09: Microsoft released the security updates for January 2024, mentioning the following as security improvement (e. g., in KB5033911):
    2024-01-09:Microsoft 发布了 2024 年 1 月的安全更新,提到以下安全改进(例如,在 KB5033911 中):

    .NET Framework Remote Code Execution Vulnerability
    .NET Framework远程代码执行漏洞

    This security update addresses a remote code execution vulnerability to HTTP .NET remoting server channel chain.
    此安全更新解决了 HTTP .NET 远程处理服务器通道链的远程代码执行漏洞。

    The build timestamp of the affected library System.Runtime.Remoting.dll is 2023-11-30.
    受影响的库 System.Runtime.Remoting.dll 的构建时间戳是2023年11月30日。

This concludes the case. No CVE was assigned, nor was there any acknowledgment.
本案至此结束。没有分配 CVE,也没有任何确认。

原文始发于Markus Wulftange:Leaking ObjRefs to Exploit HTTP .NET Remoting

版权声明:admin 发表于 2024年2月28日 下午3:04。
转载请注明:Leaking ObjRefs to Exploit HTTP .NET Remoting | CTF导航

相关文章