最近我刚刚开始学习Windows内核漏洞利用,因此决定以博客的形式分享一些我的学习心得。 之前的部分我介绍了如何搭建环境: 初学Windows内核漏洞利用(二):熟悉HEVD 初学Windows内核漏洞利用(二):熟悉HEVD 初学Windows内核漏洞利用(一):搭建实验环境 初学Windows内核漏洞利用(一):搭建实验环境 现在我们将接触熟悉用于权限提升的载荷。 本部分我所用到的工具环境如下: 在(1)和(2)中所描述的环境; 在(1)和(2)中所描述的环境; nasm工具(下载网址:http://www.nasm.us/ ); nasm工具(下载网址:http://www.nasm.us/ ); HxD工具(下载网址:https://mh-nexus.de/en/hxd/ )。 HxD工具(下载网址:https://mh-nexus.de/en/hxd/ )。 回顾一下,我们的攻击目标是存在漏洞的驱动程序,我们将从用户层向其提交一段缓冲区数据。上一部分中,我们通过提交畸形的输入数据,成功触发了一些崩溃场景;然而我们的目标并不是破坏执行流程,而是通过精心构造输入来控制执行流程重定向到我们的代码中。 通常,传输载荷被用于提升攻击者应用程序的权限;而这可以通过窃取拥有更高权限的应用程序的访问凭证(关于访问凭证的具体含义,可参考相关维基百科,网址:https://en.wikipedia.org/wiki/Access_token)来实现。 查看访问凭证 系统中运行的每个进程都有其对应的EPROCESS数据结构,其中封装了所有与之相关的数据。该结构的完整定义,详见网址https://www.nirsoft.net/kernel_struct/vista/EPROCESS.html(EPROCESS数据结构在Windows操作系统的不同版本之间会有细微差别,更多信息参见网址https://www.geoffchappell.com/studies/windows/km/ntoskrnl/structs/eprocess/index.htm )。EPROCESS结构的某些成员,比如PEB(Process Environment Block,进程环境块,具体含义可参考维基百科,网址:https://en.wikipedia.org/wiki/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!<structure name> 例如: 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 )如下图所示。 如果想避免麻烦,我们可以将函数声明为裸代码类型(更多内容详见网址:https://msdn.microsoft.com/en-us/library/5ekezyy2.aspx );这可以通过在函数之前添加一个特殊声明来实现,例如如下代码(网址:https://github.com/hasherezade/wke_exercises/blob/master/stackoverflow_expl/payload.h#L16 ): __declspec(naked) VOID TokenStealingPayloadWin7() 另一个选择是外部编译其汇编代码,例如使用NASM编译器;之后,我们可以将编译缓冲区内容导出为十六进制字符串。 作为练习,我们还将对上述载荷代码加以细微的修改,使其能够保持引用次数不变,具体代码(网址:https://github.com/hasherezade/wke_exercises/blob/master/stackoverflow_expl/shellc.asm )如下图所示。 使用如下命令,编译代码: nasm.exe shellc.asm 然后,我们使用十六进制编辑器打开编译结果,并复制字节;某些十六进制编辑器(比如HxD)甚至支持以特定编程语言的数组格式来复制数据,如下图所示。 在我针对HEVD的栈溢出漏洞利用示例中,你可以找到内嵌和外部编译两个版本的载荷代码,具体代码网址:https://github.com/hasherezade/wke_exercises/tree/master/stackoverflow_expl,编译后代码网址:https://drive.google.com/open?id=0Bzb5kQFOXkiSWTJOS2VZZ0JiU3c。 利用该漏洞的细节将在下一部分详细介绍,也可以阅读附录中所提到的Osanda和Sam的文章。 本文由 看雪翻译小组 木无聊偶 编译,来源 hasherezade's 1001 nights 转载请注明来自看雪论坛
如果你喜欢的话,不要忘记点个赞哦! 热门阅读文章: 从内核角度分析 Dirty Cow 原理 从内核角度分析 Dirty Cow 原理 来自内部的威胁以及如何防御 来自内部的威胁以及如何防御 硬盘 LED 灯中泄露的数据 (一) 硬盘 LED 灯中泄露的数据 (一) 硬盘 LED 灯中泄露的数据 (二) 硬盘 LED 灯中泄露的数据 (二) ...... ...... 更多优秀文章,长按下方二维码,“关注看雪学院公众号”查看! 看雪论坛:http://bbs.pediy.com/ 微信公众号 ID:ikanxue 微博:看雪安全 商务合作:[email protected]