一个shell来处理它们

介绍

红队参与期间, 利用网络应用程序中的漏洞通常提供了在目标基础设施中建立立足点或损害内部资产以进行横向移动的好机会。从那时起,一种常见的方法是上传Web shell并开始寻找权限升级机会。当我们谈论 Windows 环境时,这种从Web shell 的权限升级通常依赖于 使用公共存储库中可用的各种“ Potato”漏洞来滥用SeImpersonate和/或SeAssignPrimaryToken权限。  

然而,由于这些是众所周知的技术,有时它可能不是最好的方法,特别是在处理高度监控的环境时。在这些场景中以及一般情况下,在修改初始安全上下文以实现权限升级或执行横向移动时拥有更广泛的替代方案非常重要。 

这篇文章的主要目标是提出一种从Web shell修改初始安全上下文的替代方法:滥用泄露的用户令牌句柄。打开句柄的重用并不是一项新技术,它已经在不同的场景和不同的目的中被探索和滥用(例如,在不打开新进程句柄的情况下转储 LSASS)。尽管如此,这种技术应用于破坏网络应用程序后的后利用活动具有一定的优势:  

  • 由于软件要求,用于在 Windows 上运行 Web 服务器的用户帐户几乎总是具有模拟权限。这允许直接使用令牌句柄来生成在不同安全上下文上运行的进程。 
  • Web 服务器托管着各种具有不同程度的复杂性和功能的应用程序,这使得它们最终更有可能泄漏句柄等资源。有时,这种泄漏会由于不良的编程实践而引起,但在其他情况下,它的出现仅仅是因为 Web 应用程序设计本身。 
  • IIS 服务器具有多种内置功能,使它们成为该技术的完美目标:Windows 身份验证、用户模拟、委派、远程虚拟 Web 目录等。在这篇文章中,我们将看到这些合法功能如何导致令牌句柄泄漏,即使它们使用得当。 

接下来,我们将探讨由于不同原因(从软件设计要求编程错误)在IIS服务器进程中可能泄漏用户令牌句柄的几种情况。这些并不是例外或罕见,因为它们可以在StackOverflow等非常知名的网站(尽管没有人会在不调查其安全含义的情况下从 Internet 复制源代码,对吧?)以及 Microsoft 文档本身中找到。  

语境

我们将在本文中评论的所有场景都来自在 IIS Web服务器上运行的ASP.NET Web应用程序。但在此之前,我们需要对这两种技术的工作原理以及它如何可能导致句柄泄漏有一个基本的了解。  

如今,单个 IIS 服务器可以使用所谓的应用程序安全地运行多个 Web应用程序。A P是一种隔离可能运行在同一 IIS 服务器上的不同 Web应用程序的方法。每个AP都有自己的工作进程(w3wp.exe),运行在自己的应用程序池身份的安全上下文中,这是特殊的“虚拟帐户” 。因此,每个工作进程将在不同用户帐户的安全上下文中运行。 

这种具有不同安全上下文的单独进程的组合在应用程序池之间提供了强大的隔离。在实施此功能之前(即在 IIS 7.5 发布之前),所有工作进程都默认作为内置身份网络服务运行,一旦其中一个工作进程受到威胁,就允许在工作进程之间跳转。 

由于应用程序池提供的隔离,这与滥用泄漏的令牌句柄有关。如果我们破坏了在应用程序A中运行的Web应用程序,我们将只能访问该应用程序或同一A P A中运行的任何其他应用程序泄漏的句柄(单个A P可以运行任意数量的应用程序)Web应用程序的)。这意味着,默认情况下,如果同一服务器正在运行在应用程序B中运行的第三个 Web应用程序,我们将无法访问该应用程序泄漏的任何句柄,因为它将在单独的进程中运行不同的安全上下文。  

至于 ASP.NET,它 是一个 使用.NET 进行Web 应用程序开发的框架,这可能是它产生如此多句柄泄漏情况的主要原因。由于其托管性质, .NET 开发人员通常将垃圾收集器等内置功能委托给应用程序资源的自动管理和释放。然而,当 .NET程序使用非托管资源(如令牌句柄)时,问题就会出现,这些资源无法由 GB 释放并需要手动管理,这在此类编程语言中并不常见。  

为了处理这个问题,微软建议使用接口IDisposable。任何实现此接口的类都将被迫拥有一个Dispose( ) 方法,负责释放 该类的对象创建的任何非托管资源。根据官方文档,在对象超出范围之前, 应始终通过使用显式块或通过语句调用Dispose 方法try/finallyusing 。 

分类

接下来,我们将探讨在 IIS 服务器上运行的ASP.NET应用程序可能泄漏令牌句柄的不同场景。为此,我们将根据泄漏令牌的特征及其使用将提供的访问级别对场景进行简单的分类:  

  • 安全上下文切换:允许转义 IIS 工作进程安全上下文的令牌被泄露,但它与没有缓存凭据的用户会话绑定。这意味着它将不允许我们访问网络资源。根据我们的观察,如果用户属于管理员组,则该令牌将会提升。  
  • 访问网络资源:泄露的令牌指向具有缓存凭据的用户会话,因此,它可用于执行横向移动并访问网络资源。在这种情况下,我们还可以根据用户的会员资格找到中等和高度完整性令牌。 

在很多情况下,我们都可以发现这种行为,但本文不会对此进行探讨。例如,在 IIS 服务器上使用 HTTP 基本身份验证将默认泄漏每个登录应用程序的用户的令牌句柄。此外,这些代币还将提供对网络资源的访问。 

最后,本文的主要目标是从理论上和实践上证明该技术的不同方面和用例,以及我们如何在交战期间滥用它。 

安全上下文切换

Windows身份识别 

当启用 Windows 身份验证来访问 Web 应用程序时,通常需要获取已登录用户的身份。在 ASP.NET 中,更常见的方法是使用 类HttpContext。 

使用此类,可以访问WindowsIdentity链接到 HTTP 请求的内容。在本例中,WindowsIdentity代表已登录Web应用程序的系统用户,根据官方文档,该类实现了之前注释的接口IDisposable。这意味着我们必须Dispose在对象超出范围之前调用该方法来释放该对象使用的非托管资源。 

Windows身份实现

尽管文档中明确警告需要调用该方法Dispose,但同一页面中显示的代码并未显式或通过该 using语句使用它,这可能会导致混乱。 

WindowsIdentity备注

无论如何,假设出于某种原因,我们的 Web应用程序需要访问已登录用户的组成员身份。在 Google 上快速搜索会返回来自Microsoft 论坛codeprojectcsharpcorner等的多个结果,这些结果向我们展示了如何从 ASP.NET 完成此任务。一般来说,所有情况下建议的代码如下:  

ArrayList groups = new ArrayList(); 
foreach (System.Security.Principal.IdentityReference group in System.Web.HttpContext.Current.Request.LogonUserIdentity.Groups)
{
groups.Add(group.Translate(typeof(System.Security.Principal.NTAccount)).ToString());
}

通过调用,System.Web.HttpContext.Current.Request.LogonUserIdentity 我们将创建该类的一个新实例WindowsIdentity ,其中包含有关登录用户的信息,并在后台生成用户令牌的新句柄。但是,由于我们没有将新实例分配给我们可以在循环WindowsIdentity 结束时操作的对象,因此我们无法调用该方法,从而阻止我们关闭新句柄。Dispose 此代码有效地检索了用户的成员资格,但它也泄漏了令牌句柄,该句柄将在工作进程的上下文中无限期地保持打开状态,并允许攻击者冒充先前登录的用户:  

处理属性

Google搜索抛出了 其他替代方案来完成相同的结果,但它们犯了同样的错误:它们实例化了类,但它们没有通过调用方法来释放非托管资源。因此,开发人员选择的替代方案并不重要,因为除非他们深入研究 Microsoft 的文档(您有很长的路要走,并且您需要清楚地了解您正在寻找的内容),否则 Web 代码将结束发现登录应用程序的用户泄漏的令牌句柄。WindowsIdentityDisposeWindowsIdentity HttpConxtext 

带有未处理异常的模拟

模拟是 IIS 服务器的一项内置功能,允许Web 应用程序在应用程序池身份之外的用户的安全上下文中运行。此功能主要与 Windows 身份验证相结合,允许服务器在登录用户的安全上下文中运行 Web 代码。这在根据登录用户的成员身份实现对文件系统或其他本地服务的访问控制时非常方便。 

为了实现这种模拟,IIS 本身会操纵已登录用户的令牌并将其分配给新线程,并在执行完成后正确关闭句柄。尽管如此,如果在模拟过程中出于任何原因引发了未处理的异常,执行将突然结束,并且 IIS 将无法关闭句柄,该句柄将保持打开状态,直到工作进程结束: 

未处理的异常

Windows 身份验证、用户模拟和未处理的异常的结合可能会导致令牌句柄的大量泄漏。 

反射性启用用户权限 

尽管 Microsoft 未记录下一项技术,但它作为.NET Web 应用程序中可能发生非托管资源泄漏的许多情况的示例包含在内。 

在不需要使用 P/Invoke 的情况下在用户令牌中启用权限的一种非常规方法是使用内部类的反射: System.Security.AccessControl.Privilege 

Type privilegeType = Type.GetType("System.Security.AccessControl.Privilege");
object privilege = Activator.CreateInstance(privilegeType, "SeDebugPrivilege");
privilegeType.GetMethod("Enable").Invoke(privilege, null);

从开发人员的角度来看,这段代码非常简单且非常有效,但是,与前面的示例一样,令牌句柄被泄漏,我们再次无法阻止它。 在这里我们可以看到为什么会发生这种泄漏(线程的令牌被操作但句柄在函数结束时没有关闭),尽管这不能被视为编程错误,因为该方法Enable可能不应该直接调用使用反射。  

如果这段代码在模拟登录用户的 IIS 服务器中使用,则泄漏的令牌将指向这些用户的会话,从而允许恶意攻击者从 Web shell 切换初始安全上下文。 

访问网络资源

与 Windows API 交互 

尽管.NET 提供了与操作系统交互的巨大抽象,但在许多情况下仍需要直接调用 Windows API 函数来执行特定操作。在大多数情况下,此交互是通过P/Invoke执行的,它允许从 .NET 调用非托管代码。 

除了增加代码复杂性之外,使用 P/Invoke 的主要缺点之一(如果我们可以这样称呼它的话)是它会生成与我们之前讨论 IDisposable 对象时描述的情况类似的情况:它会创建新的对垃圾收集器无法自行释放的非托管资源的引用。 

毫不奇怪,手动释放资源对于 .NET 开发人员来说可能是一个需要处理的额外问题,他们习惯于依赖框架的托管性质,这使得他们可以忽略此类任务。 

回到当前的主题,在无数情况下,使用 P/Invoke 会导致创建新的令牌句柄,这意味着需要对每个令牌句柄进行调用以防止泄漏。 CloseHandle  

最直接的例子之一是函数。成功调用此函数将创建一个新会话,并将向调用者返回一个代表登录用户的新令牌句柄。然后可以使用此令牌来模拟指定的用户以代表他们执行任何任务:LogonUser 

public string LeakToken()
{
    IntPtr hToken = IntPtr.Zero;
    string username = "mdiaz.adm";
    string password = "SuperStrongPassw0rd!";
    string domain = "BLACKARROW";
    var result = LogonUser(username, domain, password, 8, 0, ref hToken);

    WindowsIdentity id = new WindowsIdentity(hToken);
    WindowsImpersonationContext impersonatedUser = id.Impersonate();
    var directoryPath = @"\\172.16.100.1\C$\RT";
    var localPatt = @"C:\RT\file.txt";
    directoryPath = directoryPath + @"\file.txt";
    File.Copy(directoryPath, localPatt);
    impersonatedUser.Undo();

    return "Leaked!";
}

一般来说,此令牌对于代表登录用户访问网络资源有效(除非登录类型已设置为LOGON32_LOGON_NETWORK),并且如果用户属于管理员组,则该令牌将被提升。 

一旦请求的 ASP.NET 代码完成执行并考虑到CloseHandle 尚未进行调用,结果将是提供对网络资源的访问的潜在提升令牌的句柄泄漏: 

手柄漏水

根据我们的经验,很少会发现 C 或 C++ 代码片段中CloseHandle没有进行相应的调用以释放每个句柄。然而,当我们检查野外可用的 .NET 代码时,这种情况经常发生,这可能是由于 .NET 使用的教学方式,或者是因为与 Windows API 的直接交互在托管编程语言中不太常见。 

无论如何,我们认为 ASP.NET 与 Windows API 的交互可能会导致泄露令牌句柄的宝贵来源。 

网络目录 

当在 IIS 服务器上部署新网站时,必须配置的设置之一是根 Web 目录所在的物理路径。此设置允许使用 UNC 路径,这意味着可以将远程路径设置为根 Web 目录: 

使用 UNC 路径

网站部署向导还允许您插入 IIS 用于访问根 Web 目录的替代身份。默认情况下,IIS 将使用其应用程序池标识来访问此目录,如果物理路径是远程目录,则将使用计算机的用户帐户。   

如果需要一组替代凭据来访问根 Web 目录,部署向导会附带“连接为…”选项,该选项将打开一个新对话框,要求输入用户名和密码: 

使用替代凭据集

这组替代凭据不会更改工作进程的安全上下文,相反,每次需要新文件来正确响应 HTTP 请求时,它们将用于访问设置为该特定网站的物理路径的 UNC 路径。 

此设置的有趣之处在于 IIS 处理 Web 目录访问的方式。由于我们已经指出必须使用备用用户帐户访问 Web 目录(在下面的示例中,我们使用域用户blackarrow\mdiaz.adm的身份),因此 IIS 将在后台执行调用以LogonUser创建新帐户用户会话。然后,可以通过其令牌使用这个新会话以所提供用户的身份访问 Web 目录。 

这正是高级设置 UI 显示的内容,还允许我们设置要使用的登录类型:  

设置登录类型

根据指定的登录类型,生成的令牌会略有不同(以下分类认为用户属于本地管理员组): 

  • 交互式:将创建未提升的代币和提升的代币。在这两种情况下,这些令牌都将授予网络访问权限。 
  • 网络:没有网络访问权限的提升令牌。当指定的根 Web 目录位于远程主机中时,我们将不会看到这种登录类型。  
  • 批处理和明文(默认):它将生成具有完全管理员权限的令牌,并且使用它也将授予网络访问权限。 

一旦工作进程启动,就会为用户 mdiaz.adm 创建一个新会话,并生成用户令牌的多个句柄,这些句柄将保持打开状态并可无限期地从进程的上下文中使用:  

句柄无限期保持打开状态

上图显示,由于 mdiaz.adm 属于本地管理员组,并且默认登录类型为 ClearText,因此生成的令牌具有完全管理员权限。此外,这些令牌将与具有缓存凭据的会话绑定,这意味着它们的使用将授予对网络资源的访问权限。  

我们将其称为句柄泄漏,因为尽管这是设计使然,并且似乎是期望的行为,但具有此设置的网站的妥协将自动允许我们逃脱应用程序池身份安全上下文并执行横向移动(除非,当我们之前已经说过,登录类型已设置为网络,在这种情况下我们将只能切换安全上下文)。  

此外,单个网站可以有多个虚拟 Web 目录,每个目录都有自己的替代访问凭据,这意味着此设置可能为攻击者提供多种选择来修改初始安全上下文。  

概念证明

了解了所有这些理论后,是时候将所有部分放在一起构建一个 Web shell,它允许我们列出当前工作进程可用的所有令牌句柄,并使用它们随意修改我们的安全上下文。为此,我们的第一个方法如下: 

  1. 通过调用 检索当前进程中所有可用的句柄NtQueryInformationProcess。获得句柄列表后,我们应用步骤 2 和 3 迭代每个句柄列表。 
  2. 调用以查明它是否是令牌句柄。NtQueryObject 
  3. 通过调用和检索有关令牌所有者的信息。GetTokenInformationLookupAccountSid 
  4. 一旦操作员决定使用哪个可用令牌句柄进行模拟,就会执行调用以生成在新安全上下文中运行的新进程。CreateProcessWithTokenW 

尽管这种方法效果相当好,但我们很快意识到调用NtQueryInformationProcess非常不可靠,并且在很多情况下它不会返回当前工作进程中可用的所有句柄。这迫使操作员在出现所需的句柄之前多次刷新 Web shell ,我们认为这还不够好。 

出于这个原因,我们决定稍微修改一下 Web shell 的行为。但在此之前,重要的是要了解用户空间中的句柄只是引用存储在内核中的进程句柄表中的条目的索引,因此它是一个整数。这些索引是连续分配的,内核倾向于填补索引之间的空白,而不是为每个新句柄分配更高的数字。  

然后我们可以做的是用一个循环替换NtQueryInformationProcess对 [0,1000000] 范围内所有数字的调用,IntPtr为每个数字创建一个新变量(这是我们在 C# 中封装句柄的方法之一)这些索引之一。这个范围是根据我们的测试选择的,因为我们认为具有超过 100 万个打开句柄的进程很少见,并且即使该范围看起来很大,Web shell 仍能保持足够快的响应。 

此时,很明显,并非范围内的所有索引都会对应于有效句柄(实际上,大多数都不会),这个问题通过调用NtQueryObject. 如果索引不对应于有效句柄,则此调用将返回STATUS_INVALID_HANDLE (C0000008) NTSTATUS值,在这种情况下,将继续执行下一个索引。 

这样,我们就获得了一个 Web shell,它允许我们滥用令牌句柄的泄漏来逃避应用程序池身份安全上下文的限制。 

在考虑功能 PoC 之前的最后一件事是检索令牌的完整性级别并确定它是否授予对网络资源的访问权限。这只需通过两次连续调用即可完成。GetTokenInformation 

特别是,为了确定令牌的会话是否缓存了可用于执行横向移动的凭据,我们调用GetTokenInformation询问该值。根据文档,如果使用显式凭据生成令牌,则返回的将包含会话 ID,否则它将为零:TokenOriginTokenOrigin 

Token来源说明

除了少数例外,我们检查了在这种情况下,如果TokenOrigin不同于零,则令牌指向的会话正在存储缓存的凭据。因此,尽管它不是万无一失的,但它是一个不错的方法来了解我们是否可以使用令牌来访问网络资源 而无需管理员权限。 

Webshel​​l 滥用句柄

这个概念验证已经在我们的存储库中提供。作为使这个 PoC 功能齐全的建议,我们至少提出以下改进: 

  • 实现SeAssignPrimaryToken权限的滥用,以便CreateProcessAsUser也能够调用。 
  • 反射加载 .NET 程序集以利用模拟,而无需每次生成新进程。 

结论

在这篇文章中,我们探讨了在运行 ASP.NET 应用程序的 IIS 工作进程上下文中令牌句柄泄漏的几种场景。然而,我们认为这只是一个开始,如果我们更深入,我们可能会发现许多应用程序和网络服务目前正在发生这种情况。  

作为本文中未详细介绍的场景示例,我们可以再次评论 IIS 服务器或 AD CS Web 服务上的 HTTP 基本身份验证的使用,这些服务为登录的所有用户保留开放令牌句柄他们。 

作为我们的最终想法,考虑到任何公司运行的 Web 应用程序数量庞大且多样化,在参与过程中破坏 Web 应用程序后,在本地和 Active Directory 环境中执行权限升级时,此技术可能是一种很有价值的方法。 

原文链接:https://www.tarlogic.com/blog/token-handles-abuse/

© 版权声明
THE END
喜欢就支持一下吧
点赞516赞赏 分享
评论 共1条

请登录后发表评论