windows file_exists 返回false_Windows内核逻辑漏洞:IO管理器访问模式不匹配

概述本文深入介绍了Windows内核中一个有趣的逻辑漏洞,以及我与Microsoft的合作伙伴共同修复的过程。如果内核和驱动程序的开发人员在访问设备对象时未考虑IO管理器的操作方式,那么漏洞所产生的最大影响将会是本地权限提升。本篇文章重点说明了我发现漏洞的过程,并详细分析了技术背景。关于进一步调查的更多信息、修复方式和如何避免使用漏洞类编写新代码,可以参考MSRC的博客文章。 技术背景我...
摘要由CSDN通过智能技术生成

20d3808529dbcdda857613fc1d914134.gif

8114a11d57e36b9076fbc1387f05f954.png概述

本文深入介绍了Windows内核中一个有趣的逻辑漏洞,以及我与Microsoft的合作伙伴共同修复的过程。如果内核和驱动程序的开发人员在访问设备对象时未考虑IO管理器的操作方式,那么漏洞所产生的最大影响将会是本地权限提升。本篇文章重点说明了我发现漏洞的过程,并详细分析了技术背景。关于进一步调查的更多信息、修复方式和如何避免使用漏洞类编写新代码,可以参考MSRC的博客文章。

8114a11d57e36b9076fbc1387f05f954.png技术背景

我在尝试对Issue#779进行漏洞利用时,偶然发现了这个存在漏洞的类。该问题是一个文件TOCTOU绕过了自定义字体加载的缓解策略。在Windows 10中,引入了缓解策略,以限制可利用字体内存损坏漏洞的影响。通常,可以轻松使用文件和对象管理器符号链接的组合,来利用文件TOCTOU问题。使用符号链接的漏洞利用过程可以以普通用户的身份进行,而不会位于沙箱中。我并没有在这个影响较小的问题上花费太多的时间,并没有使用符号链接,而是使用了Shadow Object Directories来实现漏洞利用。Microsoft将该漏洞编号为CVE-2016-3219。我在我的待办清单中添加了一个意外行为的标注,以便日后跟进。

时间过去了一年,我决定回过头去研究一下是否存在更加深入的意外行为。失败的代码类似于以下内容:

HANDLE OpenFilePath(LPCWSTR pwzPath) {

 UNICODE_STRING Path;

 OBJECT_ATTRIBUTES ObjectAttributes;

 HANDLE FileHandle;

 NTSTATUS status;

 RtlInitUnicodeString(&Path, pwzPath);

 InitializeObjectAttributes(&ObjectAttributes,

                            &Path,

                            OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE);

 status = IoCreateFile(

              &FileHandle,

              GENERIC_READ,

              &ObjectAttributes,

              // ...

              FILE_OPEN,

              FILE_NON_DIRECTORY_FILE,

              // ...

              IO_NO_PARAMETER_CHECKING | IO_FORCE_ACCESS_CHECK);

 if (NT_ERROR(status))

   return NULL;

 return FileHandle;

}

当该代码尝试在路径中打开包含对象管理器符号链接的文件时,对IoCreateFile的调用因STATUS_OBJECT_NAME_NOT_FOUND而失败。通过进一步的挖掘,我发现了ObpParseSymbolicLink中错误的来源,如下所示:

NTSTATUS ObpParseSymbolicLink(POBJECT_SYMBOLIC_LINK Object,

                             PACCESS_STATE AccessState,

                             KPROCESSOR_MODE AccessMode) {

 if (Object->Flags & SANDBOX_FLAG

   && !RtlIsSandboxedToken(AccessState->SubjectSecurityContext, AccessMode))

   return STATUS_OBJECT_NAME_NOT_FOUND;

 // ...

}

在这里,失败的检查是Microsoft在Windows 10中引入的符号链接缓解的一部分。我在沙箱中创建了符号链接,它将在对象的结构中设置SANDBOX_FLAG。在打开字体文件时,解析符号链接的过程将会进行此项检查。在设置沙箱标志后,内核还会调用RtlIsSandboxedToken来确定调用者是否仍然位于沙箱中。由于打开字体文件的调用是在沙箱进程中,因此线程RtlIsSandboxedToken应该会返回TRUE,函数将会继续执行。相反,实际上它返回的是FALSE,这使得内核认为调用是来自于权限更高的进程,并返回STATUS_OBJECT_NAME_NOT_FOUND,从而缓解任何可能的漏洞利用。

在这时,我明白了我的漏洞利用是在哪里失败的,但并不清楚为什么会失败。具体而言,我不清楚为什么RtlIsSandboxToken会返回FALSE。深入研究这个函数后,我得到了一个重要的想法:

BOOLEAN RtlIsSandboxedToken(PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,

                           KPROCESSOR_MODE AccessMode) {

 NTSTATUS AccessStatus;

 ACCESS_MASK GrantedAccess;

 if (AccessMode == KernelMode)

   return FALSE;

 if (SeAccessCheck(

        SeMediumDaclSd,

        SubjectSecurityContext,

        FALSE,

        READ_CONTROL,

        0,

        NULL,

        &RtlpRestrictedMapping,

        AccessMode,

        &GrantedAccess,

        &AccessStatus)) {

   return FALSE;

 }

 return TRUE;

}

其中,有一个重要的参数是AccessMode,它的类型为KPROCESSOR_MODE,可以设置为UserMode或KernelMode这两个值中的其中一个。如果AccessMode参数设置为值KernelMode,则该函数将自动返回FALSE,表示当前调用者不在沙箱中。在内核调试器中,我们在这个函数中设置断点,以进行确认。当从我的漏洞利用中调用时,AccessMode被设置为KernelMode。那么,RtlIsSandboxToken为什么会返回TRUE呢?为了理解内核的运行方式,我们还需要更加深入地了解AccessMode参数所代表的内容。

8114a11d57e36b9076fbc1387f05f954.png先前访问模式

Windows中的每个线程都具有与之关联的先前访问模式(Previous Access Mode)。这一先前访问模式存储在KTHREAD结构的PreviousMode成员之中。第三方使用ExGetPreviousMode访问该成员,并返回KPROCESSOR_MODE类型。如果用户模式线程由于系统调用转换而正在运行内核代码,则会将先前访问模式设置为UserMode。作为示例,下图展示了通过NTDLL中的系统调用调度存根(System Call Dispatch Stub)从用户模式应用程序到系统调用NtOpenFile的调用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值