编写Windows文件系统驱动之难:NTFS安全描述符继承漏洞分析

本文深入分析了Windows NTFS文件系统中一个存在多年的安全描述符继承漏洞,详细讲解了如何通过$INDEX_ALLOCATION技巧绕过目录继承规则,并探讨了该漏洞的潜在利用场景。

@jonasLyk的一条推文让我想起几个月前在NTFS中发现的一个漏洞,经核实该漏洞在Windows 10 2004版本中依然存在。虽然无法直接用于突破安全限制,但在攻击链中可能具有利用价值。NTFS的复杂性充分证明了编写Windows文件系统驱动的难度,因此出现各种边缘案例也就不足为奇了。

这个漏洞涉及创建新目录时的默认安全描述符(SD)分配机制。熟悉Windows SD的人都知道,可以通过CONTAINER_INHERIT_ACE和/或OBJECT_INHERIT_ACE标志来指定继承规则,这些标志决定了当新条目是目录或文件时是否应从父目录继承ACE。让我们看看NTFS用于为新文件分配安全性的代码,你能发现其中的问题吗?

代码使用SeAssignSecurityEx基于父SD和调用者提供的显式SD来创建新SD。要使继承生效就不能指定显式SD。SeAssignSecurityEx是否应用目录或文件的继承规则取决于IsDirectoryObject参数的值,该参数在调用NtCreateFile时传递了FILE_DIRECTORY_FILE选项标志时会被设为TRUE。看起来没问题——如果不指定FILE_DIRECTORY_FILE标志就无法创建目录,默认情况下会创建文件。

但等等,事实并非如此。如果指定形如ABC::$INDEX_ALLOCATION的名称,无论传递什么标志NTFS都会创建目录。因此漏洞在于:当使用$INDEX_ALLOCATION技巧创建目录时,新SD会像文件而非目录那样继承权限。我们可以在命令提示符中验证这个行为:

1
2
3
C:\> mkdir ABC
C:\> icacls ABC /grant "INTERACTIVE":(CI)(IO)(F)
C:\> icacls ABC /grant "NETWORK":(OI)(IO)(F)

首先创建目录ABC并授予两个ACE:一个针对INTERACTIVE组的ACE将继承到目录,另一个针对NETWORK的ACE将继承到文件。

1
2
C:\> echo "Hello" > ABC\XYZ::$INDEX_ALLOCATION
Incorrect function.

接着用$INDEX_ALLOCATION技巧创建子目录XYZ。当CMD尝试向目录对象写入"Hello"时输出的"Incorrect function"证明操作已生效。

1
2
3
4
C:\> icacls ABC\XYZ
ABC\XYZ NT AUTHORITY\NETWORK:(I)(F)
        NT AUTHORITY\SYSTEM:(I)(F)
        BUILTIN\Administrators:(I)(F)

查看XYZ子目录的SD可以发现ACE是基于文件而非目录继承的,我们看到了NETWORK而非INTERACTIVE的ACE。最后用dir命令确认ABC确实是目录:

1
2
3
4
5
6
7
8
9
C:\> dir ABC
 Volume in drive C has no label.
 Volume Serial Number is 9A7B-865C

 Directory of C:\ABC

2020-05-20  19:09    <DIR>          .
2020-05-20  19:09    <DIR>          ..
2020-05-20  19:05    <DIR>          XYZ

这个漏洞有用吗?老实说可能用处不大。唯一能想到的场景是:当某个系统服务在继承文件访问会授予权限而继承目录访问不会的位置创建文件时,可以通过指定路径来创建可控目录。但这确实有些牵强。如果有人能想到更好的利用方式,请联系我或微软:-)

有趣的是,这再次证明了$INDEX_ALLOCATION在确定对象是目录还是文件时没有得到正确验证。另一个典型案例是CVE-2018-1036,该漏洞允许仅用FILE_ADD_FILE权限创建新目录。为何设计上会在使用流类型时自动创建目录的原因尚不清楚,我们可能永远无法得知。

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