欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

Windows漏洞利用技巧:从任意目录创建到任意文件读取

来源:本站整理 作者:佚名 时间:2017-08-11 TAG: 我要投稿

一、前言
在过去的几个月里,我在几次会议上介绍了我的“Windows逻辑权限提升指南”心得。会议时长只有2个小时,本来我想介绍的许多有趣的技术及技巧不得已都被删掉了。随着时间的推移,想在培训课程中完整讲述相关知识已经越来越难,因此我决定发表一系列文章,详细介绍Windows漏洞利用中一些小型的、自洽的技巧,这样当我们遇到Windows中类似的安全漏洞时,我们就能直接利用这些技巧开展工作。
在这篇文章中,我会向大家介绍从任意目录创建漏洞到任意文件读取漏洞的漏洞利用技巧。我们可以在很多地方看到任意目录创建漏洞的存在,比如,Linux子系统中就存在这样一个漏洞。然而,与任意文件创建漏洞相比(任意文件创建漏洞只涉及到将某个DLL文件释放到某个目录中),这类漏洞的利用途径却不是那么明显。你可以滥用DLL重定向支持这个功能,创建一个名为program.exe.local的目录来实现DLL植入,然而这种方法并不是特别可靠,因为你只能重定向不在同一目录中的那些DLL(如System32目录),并且只能通过并行(Side-by-Side)模式实现DLL加载。
在本文中,为了演示方便,我会使用代码仓库中的一个示例驱动,该驱动已经包含一个目录创建漏洞,我们会使用NtObjectManager模块,编写Powershell脚本来利用这个漏洞。这里我介绍的技术并不属于漏洞范畴,但如果你发现了一个单独的目录创建漏洞,你可以尝试着使用这种技巧。
二、快速回顾
当使用Win32 API来处理文件时,我们经常会使用两个函数:CreateFile以及CreateDirectory。这两个函数在功能上有所不同,因此分成两个函数也能理解。然而,在原生API(Native API)层面,所涉及的函数只有ZwCreateFile,内核在调用ZwCreateFile时,会将FILEDIRECTORYFILE或者FILE_NONDIRECTORYFILE传递给CreateOptions参数,借此区分文件以及目录。虽然这个系统调用是用来创建文件的,但所使用的标志的命名方式让人觉得目录才是主要的文件类型,这一点令我难以理解。
以内核驱动中一个非常简单的漏洞为例,如下所示:
NTSTATUS KernelCreateDirectory(PHANDLE Handle, PUNICODESTRING Path) {
IOSTATUSBLOCK iostatus = { 0 };
OBJECTATTRIBUTES objattr = { 0 };
InitializeObjectAttributes(&objattr, Path, OBJCASE_INSENSITIVE | OBJKERNELHANDLE);
return ZwCreateFile(Handle, MAXIMUMALLOWED, &objattr, &iostatus, NULL, FILEATTRIBUTENORMAL, FILESHAREREAD | FILESHARE_DELETE, FILEOPENIF, FILEDIRECTORYFILE, NULL, 0); }
这段代码中有三个关键点需要注意,这三个关键点决定了这段代码是否存在目录创建漏洞。
第一点,代码将FILEDIRECTORYFILE传递给CreateOptions参数,这意味着代码准备创建一个目录。
第二点,代码将FILEOPENIF传递给Disposition参数,这意味着如果目录不存在,代码会创建该目录,如果目录已存在,代码会打开这个目录。
第三点,可能也是最重要的一点,驱动调用了Zw函数,这意味着用来创建目录的调用会直接以内核权限运行,因此就会导致所有的访问检查过程失效。在这种情况下,防御目录创建漏洞的方法是将OBJFORCEACCESSCHECK属性标志传递给OBJECTATTRIBUTES,但我们从传给InitializeObjectAttributes的标志中,可以看到程序没有设置正确的标志。
单从这段代码中,我们无法判断目的路径的来源,目的路径可能来自用户输入,也可能是个固定路径。只要这段代码是在当前进程的上下文中运行(或者在用户账户上下文中),那么这个不确定因素就不会造成任何影响。为什么代码运行在当前用户的上下文环境中是非常重要的一个因素?因为这样就能确保当目录被创建时,资源的所有者是当前用户,这意味着你可以修改安全描述符(Security Descriptor),以拥有目录的完全访问权限。但在许多情况下,这并不是一个非常必需的条件,因为许多系统目录拥有CREATOR OWNER访问控制权限,以确保目录所有者能够立刻获取全部访问权限。
三、创建任意目录
如果你想追随本文的脚步,你需要创建一个Windows 10虚拟机(32位或者64位都可以),然后根据zip文件中的setup.txt的详细说明进行操作,这个文件同时也包含了我的示例驱动。接下来你需要安装NtObjectManager Powershell模块。你可以在Powershell Gallery中找到这个模块,Powershell Gallery是一个在线的模块仓库,因此你可以访问此链接以了解更多安装细节。
一切准备就绪后,我们可以开始工作了。首先我们来看看如何调用驱动中存在漏洞的代码。驱动程序向用户提供了一个Device Object(设备对象)接口,名为\Device\WorkshopDriver(我们可以在源代码中找到这个信息)。我们可以向设备对象发送设备IO控制(Device IO Control)请求来执行漏洞代码。负责IO控制处理的代码位于device_control.c中,我们非常感兴趣的是其中的调度(dispatch)部分。我们所寻找的正是ControlCreateDir,它接受用户的输入数据,没有检查输入数据就将其当成UNICODE_STRING传递程序代码,以创建目录。如果我们搜索创建IOCTL编号的代码,我们会发现ControlCreateDir为2,因此我们可以使用如下PS代码来创建任意目录。
Get an IOCTL for the workshop driver.
function Get-DriverIoCtl { Param([int]$ControlCode) [NtApiDotNet.NtIoControlCode]::new("Unknown",` 0x800 -bor $ControlCode, "Buffered", "Any") }
function New-Directory { Param([string]$Filename) # Open the device driver. Use-NtObject($file = Get-NtFile \Device\WorkshopDriver) { # Get IOCTL for ControlCreateDir (2) $ioctl = Get-DriverIoCtl -ControlCode 2 # Convert DOS filename to NT $ntfilename = [NtApiDotNet.NtFileUtils]::DosFileNameToNt($Filename) $bytes = [Text.Encoding]::Unicode.GetBytes($ntfilename) $file.DeviceIoControl($ioctl, $bytes, 0) | Out-Null } }
New-Directory函数首先会打开设备对象,将路径转化为原生的NT格式(字节数组),然后在设备上调用DeviceIoControl函数。对于控制代码,我们可以只传递一个整数值,但我编写的NT API库拥有一个NtIoControlCode类型,可以替你封装所需的整数值。我们可以试一下,看看能否创建一个“c:\windows\abc”目录。

[1] [2] [3]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载