写文章 初学Windows内核漏洞利用(三):窃取访问凭证

最近我刚刚开始学习Windows内核漏洞利用,因此决定以博客的形式分享一些我的学习心得。

之前的部分我介绍了如何搭建环境:

初学Windows内核漏洞利用(二):熟悉HEVD

初学Windows内核漏洞利用(一):搭建实验环境

现在我们将接触熟悉用于权限提升的载荷。

本部分我所用到的工具环境如下:

在(1)和(2)中所描述的环境;

nasm工具(下载网址:NASM);

HxD工具(下载网址:HxD - Freeware Hex Editor and Disk Editor)。

回顾一下,我们的攻击目标是存在漏洞的驱动程序,我们将从用户层向其提交一段缓冲区数据。上一部分中,我们通过提交畸形的输入数据,成功触发了一些崩溃场景;然而我们的目标并不是破坏执行流程,而是通过精心构造输入来控制执行流程重定向到我们的代码中。

通常,传输载荷被用于提升攻击者应用程序的权限;而这可以通过窃取拥有更高权限的应用程序的访问凭证(关于访问凭证的具体含义,可参考相关维基百科,网址:Access token - Wikipedia)来实现。

查看访问凭证

系统中运行的每个进程都有其对应的EPROCESS数据结构,其中封装了所有与之相关的数据。该结构的完整定义,详见网址struct EPROCESS(EPROCESS数据结构在Windows操作系统的不同版本之间会有细微差别,更多信息参见网址EPROCESS)。EPROCESS结构的某些成员,比如PEB(Process Environment Block,进程环境块,具体含义可参考维基百科,网址:Process Environment Block),用户模式下即可访问;而另一些,比如所提到的访问凭证,只能在内核模式下访问。我们可以通过如下命令,使用WinDbg调试器查看EPROCESS结构的所有域成员,结果如下图所示。

dt nt!_EPROCESS

可见,结构起始位置到域成员Token的偏移为0xF8。

通过使用如下命令,让我们查看凭证中所包含类型的细节,结果如下图所示。

dt nt!_EX_FAST_REF

凭证存储于一个联合结构体_EX_FAST_REF中,其有两个域成员:RefCnt(引用计数)和Value。我们只对替代Value感兴趣;出于应用程序的稳定性考虑,最好不要改变引用计数。

现在,让我们查看被调试方主机上运行的某些应用程序的凭证。我们可以使用如下命令来列举进程:

!dml_proc

示例

结果如下图所示。

图中所示的第一列,是对应于特定进程的EPROCESS结构首地址。

现在,使用图中的地址,我们可以通过如下命令来发现更多选定进程相关的细节:

!process [address of EPROCESS]

在如下图所示的各个域成员之中,我们可以看到访问凭证。

通过如下命令,我们还可以在更低层次上查看凭证的具体内容:

dt nt!_EX_FAST_REF [address of EPROCESS] + [offset to the Token field]

命令执行结果如下图所示。

或者使用如下命令:

dd [address of EPROCESS] + [offset to the Token field]

结果如下图所示。

从上面的结果我们可以看出,!process命令会自动应用掩码,并从显示信息中过滤引用计数;我们可以通过使用最右3比特置零的掩码,在如下表达式求值的帮助下,人工实现相同的功能:

?[token] & 0xFFFFFFF8

结果如下图所示。

通过WinDbg调试器窃取访问凭证

作为练习,我们将在被调试方主机运行cmd.exe,并在调试方主机使用WinDbg调试器来提升其权限。

首先,列举所有进程;然后,显示查看选定进程System和cmd的访问凭证;之后,将System进程的访问凭证复制到cmd进程内,在这个过程中为了保持引用计数不变我们需要使用相应的掩码;最终,cmd.exe提权成功。

窃取凭证的载荷

现在我们需要通过注入代码来重现以上过程;当然这并不简单,因为我们不能再借助WinDbg调试器了。

在官方的HEVD知识库中,提供了一些用于窃取凭证的载荷的完整例子,作为漏洞利用代码的一部分(网址:https://github.com/hacksysteam/HackSysExtremeVulnerableDriver/blob/master/Exploit/Payloads.c)。

代码中所包含的所有载荷的目的是相同的,即窃取访问凭证;然而我们可以看到,为了适应特定的漏洞,它们之间有一点差别。它们的代码大部分是相同的,只有结尾不同(该部分被称之为“内核恢复桩程序”);这部分代码被用于进行必要的清理工作,以便在载荷部分执行完成返回之后,应用程序不会崩溃。

接着,我们看一个通用版本(网址:https://github.com/hacksysteam/HackSysExtremeVulnerableDriver/blob/master/Exploit/Payloads.c#L186),具体代码如下图所示。

首先,我们必须找到EPROCESS结构的起始位置。使用WinDbg调试器这轻而易举,一条命令就可以显示该信息;现在,我们需要从其他的域来顺藤摸瓜,自己动手找到该结构的起始位置。

我们使用KPCR(Kernel Processor Control Region,内核处理器控制区域)结构作为起点,32位Windows操作系统上的FS寄存器(64位系统上则是GS寄存器)指向该结构。

上图中所述的代码利用了以下结构之间的关系:

KPCR(PrcbData)->KPRCB(CurrentThread)->KTHREAD(ApcState)->KAPC_STATE(Process)->KPROCESS

KPROCESS结构是EPROCESS结构的第一个域,如下图所示;因此,通过找到它我们最终找到了EPROCESS结构的起始位置。

当前进程的EPROCESS结构找到之后,我们将利用其另一个域来找到SYSTEM进程的EPROCESS结构,如下图所示。

LIST_ENTRY是双向链表的一个成员类型,该表将所有正在运行的进程连接到一起。该结构的具体定义如下图所示。

其域成员Flink指向另一个进程的LIST_ENTRY域;因此,通过该指针索引并替代域成员的偏移,我们可以得到指向另一个进程的EPROCESS结构的指针。

然后,我们需要获取PID值(对应于域成员UniqueProcessId),并将其与System进程的特有PID进行比对;PID值在EPROCESS结构中的位置如图所示。

漏洞利用中对应以上过程的代码片段,如下图所示。

在获取我们的进程和System进程的EPROCESS结构之后,我们就可以将凭证从一方复制到另一方。在以下代码中,引用计数并没有保留(如下图所示)。

使用WinDbg调试器查看特定域成员的偏移非常方便,我们可以使用如下命令来显示指定结构的具体定义:

dt nt!

例如:

dt nt!_KPCR

结果如下图所示。

之后执行如下命令:

dt nt!_KPRCB

结果如下图所示。

因此,计算可得_KTHREAD的偏移为 0x120 + 0x004 = 0x124。

代码片段中给出上述偏移,如下图所示。

编写载荷

正如HEVD中的漏洞利用代码(网址:https://github.com/hacksysteam/HackSysExtremeVulnerableDriver/blob/master/Exploit/Payloads.c#L63)所演示的那样,我们可以使用内嵌汇编(封装于C/C++代码之中)来编写载荷代码。

然而,在这种情况下,编译器将对我们的代码进行加工;如下图所示,代码前后添加了多余的前缀和后缀。

这就是我们在执行返回之前,通过堆栈指针(ESP)加上12(0xC)字节的方式,从堆栈中移除多余的DWORD类型数据的原因,具体代码(网址:https://github.com/hacksysteam/HackSysExtremeVulnerableDriver/blob/master/Exploit/Payloads.c#L94)如下图所示。

如果想避免麻烦,我们可以将函数声明为裸代码类型(更多内容详见网址:Naked Function Calls);这可以通过在函数之前添加一个特殊声明来实现,例如如下代码(网址:https://github.com/hasherezade/wke_exercises/blob/master/stackoverflow_expl/payload.h#L16):

__declspec(naked) VOID TokenStealingPayloadWin7()

另一个选择是外部编译其汇编代码,例如使用NASM编译器;之后,我们可以将编译缓冲区内容导出为十六进制字符串。

作为练习,我们还将对上述载荷代码加以细微的修改,使其能够保持引用次数不变,具体代码(网址:hasherezade/wke_exercises)如下图所示。

使用如下命令,编译代码:

nasm.exe shellc.asm

然后,我们使用十六进制编辑器打开编译结果,并复制字节;某些十六进制编辑器(比如HxD)甚至支持以特定编程语言的数组格式来复制数据,如下图所示。

在我针对HEVD的栈溢出漏洞利用示例中,你可以找到内嵌和外部编译两个版本的载荷代码,具体代码网址:hasherezade/wke_exercises,编译后代码网址:https://drive.google.com/open?id=0Bzb5kQFOXkiSWTJOS2VZZ0JiU3c

利用该漏洞的细节将在下一部分详细介绍,也可以阅读附录中所提到的Osanda和Sam的文章。

本文由 看雪翻译小组 木无聊偶 编译,来源 hasherezade's 1001 nights

转载请注明来自看雪论坛

如果你喜欢的话,不要忘记点个赞哦!

你可能感兴趣的:(写文章 初学Windows内核漏洞利用(三):窃取访问凭证)