任意文件移动导致的Windows提权攻击分析 – 作者:Kriston

本文介绍了如何滥用Windows上特权进程执行文件操作来实现本地特权升级(用户到管理员/系统),同时介绍了利用这些类型的错误的现有技术以及漏洞利用工具。

特权文件操作错误

高权限运行的进程会和所有进程一样对操作系统中的文件进行操作。但是当一个高权限的进程在没有足够的安全措施的情况下访问用户控制的文件或目录时,就有可能成为一个安全漏洞,因为恶意程序有可能滥用该特权进程执行的操作,做一些不该做的事情。对用户控制的资源进行特权访问很多时候都可能造成安全问题,文件只是其中一个部分。

人们熟知的例子包括修改用户可写服务可执行文件和DLL种植。如果你对特权服务将执行的文件有写权限,或者对它将寻找DLL的目录有写权限,你就可以在这个特权进程中执行你的payload。这是一个众所周知的漏洞,除了偶尔的配置错误,现在大多数在特权层面运行的软件都能防御这种攻击。

然而,对文件系统操作的潜在滥用似乎并不为人所知,但却同样危险:如果你能让一个有特权的进程为你创建、复制、移动或删除任意文件,那么美好的SYSTEM权限的shell有可能就在不远处。

另外,由于这些漏洞是逻辑漏洞,它们利用起来通常非常稳定(不涉及内存损坏),通常可以在代码重构中存活(只要文件操作逻辑不改变),而且无论处理器架构如何,都可以用完全相同的方式进行利用。这些特点使它们对攻击者来说非常有价值。

寻找bug

用户可写位置

虽然大多数特权程序不会直接操作一些非特权用户的文件(有一些例外,如杀毒软件),但许多程序会对可能位于用户可以摆弄的地方的文件进行操作。非特权用户有某种形式的写访问权限的有趣位置包括:

  • 用户自己的文件和目录,包括其AppDataTemp文件夹,如果你运气好或运行杀毒软件,他们当中的一些特权进程可能会使用这些文件和目录。
  • 公共用户的文件和目录:idem。
  • 在 “C:\”中创建的目录有默认的ACL(Access Control List):默认情况下,在分区根部创建的目录允许用户写。
  • C:\\ProgramData的子目录,有默认的ACL:默认情况下,用户可以创建文件和目录,但不能修改现有的文件和目录。这往往是找漏洞过程中首先要看的地方。
  • C:\Windows/Temp的子目录:默认情况下,用户可以创建文件和目录,但不能修改现有的文件和目录,也不能读取文件/访问其他用户创建的目录。对于安装程序和其他有特权的软件和脚本,如果它们准时运行,不检查是否有预先存在的文件和目录,就会产生很有意思的问题。

你可以使用SysInternals的[AccessChk]工具(https://docs.microsoft.com/en-us/sysinternals/downloads/AccessChk)、`icacls`或PowerShell的`Get-Acl`等工具和命令来检查文件权限,或者干脆使用explorer的安全选项卡:高级表格中有一个有效访问选项卡,允许列出特定账户或组对该文件/目录的访问权限。下面的截图显示了在`C://ProgramData`目录下授予用户组的(默认)访问权限。

C:\ProgramData default access rights寻找有特权的文件操作

要找到特权进程进行文件操作的实例,我们可以简单地使用SysInternals的ProcMon,过滤感兴趣的进程的文件事件。当我们看到它访问用户可控的文件&目录时,我们可以检查该进程是否使用了impersonate的方式来进行操作。有的时候没有:

ProcMon on McAfee

当然,这只会给我们提供进程本身所执行的操作(例如,当它启动时),要想找到更多的操作,我们就必须研究无权用户可以执行的操作,可以直接通过UI(如果它有的话),也可以间接通过COM、LPC、网络接口和其他暴露的攻击面。其中有些可能需要对产品进行逆向工程(很酷的例子这里这里这里),对于这个介绍,我们只打算去找那些简单点的例子介绍。

漏洞利用技术和工具

一旦我们发现一些对用户/用户控制的文件&目录进行的文件操作,我们就需要一种方法来劫持这些操作来做一些有趣的事情。

James Forshaw(@tiraniddo)在NTFS文件系统和Windows操作系统内部完成了开创性工作,他在发表了许多相关的文章(symlinkshardlinksNTPathConversionDirCreate2FileReadFileWrite2EoPAccessModeMismatch),并在InfiltrateSyScan。他提出了几种滥用Windows文件系统和路径解析功能的技术(大致总结如下),并在开源的symboliclink-testing-tools工具包NtApiDotNet库中实现了这些技术。他的技术和工具包为许多测试人员打开了去寻找这类bug的大门(包括我自己),使这些bug有可能—甚至很容易—被利用,有效地把它们变成了新的漏洞利用潮流。

NTFS junctions

结点是NTFS的一个特性,它允许将目录设置为文件系统的挂载点,就像Unix中的挂载点一样,但也可以设置为解析到另一个目录(在同一个或另一个文件系统上)。就我们的目的而言,我们可以把它们看作是一种仅有目录的符号链接。

NTFS junctions

有趣的是,在大多数情况下,路径解析会透明地跟随结点(除非明确地设置了一个参数来阻止这一点),所以在上面的设置中,一个试图打开C:/\Dir/\file.txt的程序事实上会打开C:/\Otherfile.txt,因为IO管理器会跟随结点。

结点可以由无权限的用户创建。它们可以跨卷工作,所以你可以将C:\Dir重定向到D:\OtherDir。如果你有写权限,一个现有的目录可以变成一个连接点,但它必须是空的。

NTFS结点是用reparse来实现的,虽然内置的工具不会让你这么做,但可以通过设置自定义reparse点的实现让它们解析到任意路径。CreateMountPoint工具(来自symboliclink-testing-tools)可以让你做到这一点。对于常规的结点,你也可以使用mklink和PowerShell的New-Item加上Type Junction参数做到。

硬链接

无权用户也可以创建硬链接,就像他们的Unix系统一样,硬链接将作为一个现有文件的额外路径。它不适用于目录或跨卷(对于硬链接来说没有意义)。

Hard links

内置的工具不会让你创建一个硬链接到一个你没有写权限的文件,但实际的系统调用可以让你在打开一个文件进行读取的情况下进行创建。使用symboliclink-testing-tools中的CreateHardLink工具(或Ruben Boonen这个PowerShell脚本)来创建你没有写访问权限的文件的硬链接。要注意的是,如果你没有对文件的写访问权限,你将无法删除所创建的链接(就像你无法使用原始路径删除文件一样)。

更新:这一技术正在在即将推出的Windows 10版本中得到缓解

对象符号链接管理器

虽然NTFS确实提供了文件系统的符号链接,但在Windows上,无权限的用户不能在文件系统上创建符号链接:它需要SeCreateSymbolicLinkPrivilege,默认情况下,只有管理员才能获得该权限。

不过,无权限的用户可以在Windows的 “对象管理器 “中创建符号链接,顾名思义,它可以管理进程、部分和文件等对象。对象管理器使用符号链接,例如驱动器字母和命名管道与相应设备相关联。用户可以在可写对象目录中创建对象符号链接,如\RPC CONTROL\,这些符号链接可以指向任意路径—包括文件系统中的路径—无论该路径当前是否存在。

当与NTFS连接点结合时,对象符号链接会做一些有趣的事情。事实上,一个无权限的用户可以将一个挂载点与该目录中的对象管理器符号连接起来,解析到\RPC CONTROL\目录。

Object Manager symbolic links

这给我们提供了一个有点像文件系统符号链接的东西:在上图中,C:\Dir\file.txt解析为C:\Other\stuff.any。当然,这并不是完全等同的,但在很多情况下,这种条件足以让我们进行攻击。

你可以使用CreateMountPointCreateDosDeviceSymlink分别完成这些步骤,但CreateSymlink工具通过一个方便的命令中实现了这种技术。

Opportunistic locks

oplock是一种可以放置在文件上的锁,当其他进程想要访问该文件时,它可以被告知—同时延迟这些进程的访问,以便锁定进程可以在解除锁之前让文件处于适当的状态。oplocks最初是为通过SMB缓存客户端-服务器文件访问而设计的,可以通过调用文件句柄上的特定控制代码设置oplock。

oplock对于利用TOCTOU的bug是很有用的,因为你可以通过锁定一个试图打开的文件或目录来轻松地赢得与进程的竞争。当然,它也有一些限制:你不能细粒度地 “放行 “一个访问(一旦锁被解除,所有待定的访问都会发生),而且它并不适用于所有类型的访问,但它通常非常有效。

SetOpLock工具可以让你创建这些锁,并阻止对文件或目录的访问,直到你按回车键释放锁。它让你在读、写和放行oplock之间进行选择。

同样,James将这一技术与之前的技术相结合,创造了一个强大的primitive,实现一些TOCTOU bug的利用:通过设置一个伪symlink(和之前一样),并在最终文件(symlink的目标)上放置一个oplock,我们可以在打开目标文件时改变symlink(即使目标文件被锁定,symlink也没有被锁定),并使其指向另一个目标文件。

Opportunistic locks

在上述设置中,第一次访问文件C:\Dir/file.txt将打开C:\One/\foo.xxx,第二次访问将打开C:\Two/\bar.yyy

BaitAndSwitch工具用独占的oplocks实现了这种技术,如果你需要读写锁,可以使用SetOpLockCreateSymlink

Exploitation strategies

一个典型的例子

让我们考虑一下产品X的以下行为。

  • C:\ProgramData\Product\Logs(具有默认/继承访问权的目录)中创建日志文件。
  • 日志文件由特权(系统)和非特权(用户)进程创建/写入。
  • 创建日志文件的过程设置了一个明确的ACL,这样每个用户都可以写入文件。

Product X's log file's ACL

这就导致了可以被利用来创建具有任意内容任意文件的一个漏洞。

如果我们删除现有的日志文件,并将日志目录变成与C:\Windows\System32的连接点(由于继承了C:\ProgramData的访问权限),产品X的特权进程将在System32目录下创建日志。

Exploiting Product X using a junction

我们也可以使用symlink技术转移一个特定的日志文件(如some.log),以攻击者选择的名称创建一个任意文件,如程序目录中的DLL。

Exploiting Product X using a symlink

因为特权进程也对日志文件设置了允许写入的ACL,所以我们也可以根据自己的喜好更改文件的内容。

这是一个在很多产品上都发现过的bug,大概是因为它是一个共同需求的简单实现(日志文件可被所有组件—用户和系统组件写入,所有组件的通用日志代码)。在过去一年多的时间里,我们看到了好几个这样的例子。

从任意文件写入到权限升级。

在特权进程的上下文中,通过任意写入文件来获得代码执行的两种常用技术是:

  • DLL劫持:在一个特权进程将加载它的位置创建一个DLL(在应用程序的目录中,在System32WindowsSYSTEM%PATH%上的其他目录中)。它需要一个方法来(重新)启动那个特权进程来加载这个DLL。
  • 覆盖:替换现有的二进制文件/脚本/配置文件/等,会给我们代码执行的权限。除了需要(重新)启动进程外,还需要文件写入操作来允许覆盖现有的文件(另外目标文件不应该被锁定),并且通常对特定的服务/应用程序要求的非常具体。

利用DLL劫持任意写入文件

至少有两种不太知名的技术。

  • 使用C:\Windows/System32/Wow64Log.dll在32位特权进程中加载64位DLL。这个DLL在默认情况下并不存在(Windows10 消费者版本上),它在所有32位进程中加载。然而,这个DLL不能直接通过Kernel32导入,所以如果想导入它必须只使用NTDLL APIs,当然这只有在你有一个32位进程要注入的时候才有效(同样也是一种启动它的方法)。AFAIK这个技巧是由George Nicolaou发现的(我可以找到的第一个参考资料)和由Walied Assar记录的

  • 使用 “Diagnostics Hub Standard Collector Service”:这项技术是由 – 你猜对了 – James Forshaw发现的,在GPZ的一篇博客文章中详细解释,并在example exploit中公布了作为案例研究的bug。这篇文章非常值得一读,其要点是:DiagHub服务(以 “SYSTEM “的形式运行)可以从 “System32 “加载任何扩展名的文件作为DLL。因此,如果你能在System32中创建一个带有有效载荷的文件test.log(当然文件内容必须是DLL),只需使用该技术在特权服务中加载该DLL。然而,这种技术正在在即将到来的Windows 10版本中得到缓解

Exploiting arbitrary file write using the Diagnostics Hub Standard Collector Service

控制内容

这些技术需要对创建的文件内容进行控制:如果你可以劫持创建一个文件到任意位置,但无法控制该文件中的内容,那么它的作用就非常有限。在我们的例子bug中,我们有一个很好的ACL,由特权程序对生成的文件进行设置,但如果我们没有这个奢侈条件呢?

我们可以尝试针对其他操作。在我们的日志记录例子中,假设日志记录功能在日志达到一定大小的时候对文件进行移动,一个特权进程可能会移动或重命名日志文件(例如从abc.logabc.old.log)。那么我们就可以利用符号链接来滥用这个操作。

  • 在重命名/移动操作中,用指向我们的有效载荷(sh.dll)的伪链接替换源文件。
  • 将目标文件替换为我们要创建或替换的文件的伪链接(这里是target.dll)

所以,当重命名操作发生时的布局是这样的。

控制我们的任意文件内容写入

当特权进程试图将abc.log移动或重命名为abc.old.log时,它实际上会将用户拥有的文件sh.dll移动/重命名为target.dll,将我们的有效载荷放在我们想要他在的位置。

可以控制的特权文件移动/重命名/复制的情况如下:

  • 一个受控的移动或重命名给我们提供了任意的文件写的能力
  • 如果能够控制复制的源地址和目的地址也是一样的
  • 复制操作,我们控制源头,而不是目的地,给了我们一个任意的文件读取(如果目的地的位置是用户可读的)
  • 我们控制源头而不控制目标的移动/重命名目的地,给了我们一个任意删除文件的机会

Side notes:
附注:

  • 覆盖目的地的能力取决于执行操作的进程所使用的选项。
  • 如果目标文件已经存在,我们也可以使用硬链接而不是伪链接
  • A common way to abuse arbitrary file read is to get the SAMSECURITY and SYSTEM hives to dump the SAM database and cached credentials
  • 滥用任意文件读取的一个常见方法是让SAMSECURITY以及SYSTEM hive去获得SAM数据库以及其中缓存的凭证。

从任意删除文件到权限提升

我们谈到了任意文件读写,那么删除呢?除了明显的DoS隐患外,我们有时会滥用任意文件删除bug进行EoP:

  • 在一个我们可以写入的位置,即使我们不能覆盖其中已有的文件,如C:\\ProgramData这个目录。
  • 这个将在之后被一个有特权的进程用于读或写操作(无论它是我们滥用删除的同一进程还是不同的进程)

举个例子,如果我们知道如何触发从C:\\ProgramData\Product\fooC:\\ProgramData\Product\bar的移动/重命名,但这些文件已经存在,而且我们没有对它们的写访问权限,我们可以使用一个任意的文件删除错误来删除foo和bar,然后自己重新创建它们(同样假设Product子目录的默认权限)。我们可以利用前面的技术滥用写操作(如果Product目录现在是空的,则伪造symlink,否则硬链接),完成文件链接。

利用杀毒软件

杀毒软件是这一类bug的主要产生的地方,因为它是一个高权限的软件。根据设计,它必须对文件进行操作,包括用户拥有的文件。执行扫描、删除、还原操作的特权进程,会被我们用来执行有趣的文件操作,把杀毒软件的防御组件变成潜在的漏洞利用方式。

AV quarantine & restore

杀毒软件的隔离和恢复功能特别有趣,尤其是当它们可以被无权用户触发时(有时不是在用户界面上,而是通过COM劫持)。触发隔离(或移除)的最简单方法当然是将一个已知的检测到的文件(如EICAR)放到文件系统中。

有趣的是,一些AVs会在删除之前对检测到的文件进行特权操作,比如。

  • 在同一目录下创建/删除临时文件。
  • 将受感染的文件复制或移动到用户可写的位置。
  • 将受感染的文件复制或移动到一个用户可读的隔离区位置(如果你利用了这一点,你的SAM文件就能够被读取)。

临时文件和隔离文件有时会被编码填充,如果你想看看算法(读取结果文件),在启动IDA/Ghidra之前,最好先去HexacornDeXRAY看看。

而还原过程中,如果能被非特权用户触发,则是另一个特权文件写入bug(例子https://bogner.sh/2017/11/avgater-getting-local-admin-by-abusing-the-anti-virus-quarantine/)。要控制内容,要么在删除或还原过程中寻找潜在的TOCTOU,要么让你的payload足够 “恶意”,一开始就被直接隔离。

转移文件删除/移动的位置

如果AV在检测和删除/隔离(TOCTOU)之间没有锁定(或以其他方式阻止访问)。我们可以使用一个有趣的技巧,就是用一个结点来替换它的父目录(在检测之后但在删除之前)。如果我们想删除一些我们没有访问权限的文件(比如C:\Windows\System32\license.rtf),我们可以这样进行。

  1. 将EICAR(或任何可检测的文件)放入我们创建的目录中,与目标文件同名,例如C:\Temp\Test\licence.rtf
  2. 等待AV检测到它
  3. 删除或重命名母目录C:\Temp\Test
  4. 将其改为 “C:/Windows/System32 “的连接点。
  5. AV删去C:\TempTest/licence.rtf',改为C:\Windows/System32/licence.rtf’。

正确的方法是使用 oplocks,然而在实践中并不总是那么容易,因为文件在被删除之前可能会被访问(可变)多次,而且缺乏精细的控制会使这变得很棘手。一个快速的方法是简单地在目录旁边创建结点,然后做一个循环,不断交换两者。根据AV检索要删除的路径和删除文件的方式,我们可能有合理的机会删除击中结点,我们可以根据需要重试。剧透:在几个AV产品上确实有效,在其他产品上完全无效)。

显然,所有这些都不是很隐蔽,但如果没有适当的事件转发,你的第一个目标文件可能就是事件日志:)

Bugs found

去年年初在常见的软件产品中发现了几个这样的bug,并向各自的厂商进行了汇报,其中一些厂商已经发布了修复程序。下表总结了我们发现的错误及其状态。

图片[13]-任意文件移动导致的Windows提权攻击分析 – 作者:Kriston-安全小百科

结论

我希望这篇文章能让一些新人开始寻找与文件相关的逻辑权限升级bug,以及尽可能多的理由让厂商和开发者针对这类bug对其产品进行加固/修复。

当然要感谢James Forshaw给我们提供了这些酷炫的技术,感谢那些反应够快的厂商(特别要提到F-Secure安全团队),感谢GreHackTROOPERS让我上台讲解,也感谢帮我准备讲座和本文的队友们。

原文链接

https://offsec.almond.consulting/intro-to-file-operation-abuse-on-Windows.html

来源:freebuf.com 2020-07-06 21:11:49 by: Kriston

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论