小编采访

nope,Windows内核缝隙使用教程,龘

仓库溢出缝隙

首要,咱们将从HackSysExtremeVulnerableDriver中的vanilla栈溢出缝隙开端讲起。

当向仓库上的缓冲区寄存的数据超出其存储容量时(例如,向16字节缓冲区(这儿的缓冲区可所以字符数组或相似目标)中寄存20个字节时),多出来的数据将会写入邻近的内存中,然后掩盖或损坏仓库。

这儿的中心思维是操控溢出进程,以便能够掩盖保存在仓库中的回来地址,并在履行当时(易受进犯的)函数后,将回来咱们的掩盖值,其间寄存的是相应的shellcode。

留意:在履行咱们的shellcode之后,代码履行流程有必要回到相应的应用程序,就这儿来说,是交还给内核,不然,就会损坏应用程序。一般状况下,应用程序溃散后,咱们能够重新启动它,可是假如内核内存发作损坏的话,内核宣布kernel panic,导致蓝屏死机,这是咱们最不想要的。

为了处理这个问题,咱们需求康复履行途径,以便在履行shellcode之后,将履行流程回来到履行易受进犯的函数后边相应的函数。

含有仓库溢出缝隙的代码

现在,咱们现已了解了进犯思路,下面,让咱们调查一下易受进犯的代码(坐落StackOverflow.c文件中的函数TriggerStackOverflow)。首要,该函数会创立一个ULONG型数组,它能够包容512个成员元素(在common.h头文件中,BufferSize被设置为512)。

存在仓库溢出缝隙的函数

然后,内核会查看缓冲区是否驻留在用户空间中,并在非分页池中为其分配内存。

完结上述操作后,内核会将数据从用户空间的缓冲区仿制到内核空间的KernelBuffer中,实践上,它本质上便是一个ULONG型数组。

溢出点

仓库溢出

请咱们留意RtlCopyMemory(它本质上便是memcpy)函数的第三个参数Size,它是用户空间缓冲区的长度,而非内核空间缓冲区的长度。这儿便是发作缓冲区溢出的要害点。

缝隙验证

现在,为了验证这儿是否为该缝隙的实践方位,咱们将编写一个函数,让它调用函数StackOverflowIOCTLHandler的IOCTL。需求阐明的是,详细IOCTL代码请拜见exploit/common.h文件。

留意:咱们本能够从编译后的驱动程序自身取得IOCTL代码,可是已然咱们有这样的优势,为什么不必呢?

什么是IOCTL代码?

“I/O操控码(IOCTL)用于用户形式应用程序和驱动程序之间的通讯,或用于仓库中驱动程序之间的内部通讯。I/O操控代码能够经过IRP进行发送。”——Microsoft.com

基本上,假如驱动程序具有相应的IOCTL代码,就能够直接在驱动程序中调用内核函数。

要运用IOCTL代码,咱们能够借助于DeviceIoControl函数,该函数的详细阐明请参阅这儿。

DeviceIoControl函数的原型是:

DeviceIoControl函数的原型

我运用C++言语编写了一个函数,它能够经过DeviceIoControl来调用StackOverflowIoctlHandler,后者又会调用TriggerStackOverflow——一个含有仓库溢出缝隙的函数。

咱们知道该缓冲区是长度为512个ULONG型元素,所以,咱们能够再附加由me tasploit结构中的pattern_create.rb生成的100字节形式。

最终,将这个缓冲区的内容发送到HEVD,看看会发作什么状况。

留意:这个函数坐落头文件StackOverflow.h中,而且由main函数来调用它。完好的代码,请拜访我的代码库。

用于运用仓库溢出的POC

用于运用仓库溢出的POC

在Win7体系上编译并履行二进制文件后,咱们能够在WinDbg中看到:

发作在WinDbg中的溃散

如您所见,这儿存在拜访违例,EIP指向了31624130。

运用me tasploit的pattern_offset.rb的形式之后,咱们会发现其偏移量为32。下面,咱们开端运用这个缝隙。

仓库溢出缝隙的运用办法

为了运用这个缝隙,咱们只需求用HEVD中供给的TokenStealingPayloadWin7 shellcode掩盖保存的回来地址,就能够了。

留意:为了防止溃散,或许需求对shellcode稍加修正,这一个使命留作作业。

获取Shell

让咱们首要查看当时身份是否为普通用户。

普通用户

能够看出,当时身份仅仅普通用户。

在运转缝隙运用代码之后,回身变为ntauthority/system用户。

NT Authority/SYSTEMShell

参考资料

  • HackSysTeam
  • FuzzySecurity

类型混杂缝隙

什么是类型混杂缝隙?

类型混杂是这样一种缝隙,即应用程序没有验证目标的类型(函数、数据类型等),就直接按预期类型对其进行处理,所以,当传递给程序的其实是其他类型的目标时,就会呈现这种类型的安全缝隙。

含有类型混杂缝隙的代码

现在,咱们现已了解了类型混杂缝隙的概念,下面,让咱们开端调查含有这种类型的缝隙的代码(坐落typeconfusion.c中的函数triggerTypeConfusion中)。

首要,内核会查看缓冲区是否坐落用户空间中,然后,在非分页池中为其分配内存空间。完结上述操作后,内核将objectID从用户空间缓冲区赋值给内核空间缓冲区,并对目标类型履行相同的操作。

为objectID和objectType赋值

之后,内核会对目标调用TypeConfusionInitializer函数(内核形式而非用户形式)。

为目标调用TypeConfusionInitializer函数

让咱们调查一下这个函数:

函数类型ConfusionobjectInitializer

这个函数首要接纳目标,并调用目标中的函数指针。

让咱们看看kernel_type_confusion_object的结构(本质上是一个结构体),它坐落typeconfusion.h头文件中。这个头文件保存了用户空间目标和内核空间目标的界说,这使得该缝隙的运用办法要比仓库溢出缝隙的运用办法更简单一些。

目标原型

首要,让咱们看看用户形式目标中所包括的内容。实践上,这个用户形式目标是一个包括2个成员的结构体,这些成员为:

l 目标ID

l 目标类型

在内核形式目标的状况下,它也是一个包括2个成员的结构:

l 目标ID

l 第二个成员是UNION,能够保存:

1. 目标类型

  1. 回调函数(函数指针)

咱们知道UNION变量一次只能寄存一个成员,这儿它可所以一个object Type,也可所以一个指向TypeConfusionInitializer函数调用的函数的指针。

当函数TriggerTypeConfusion函数没有验证第二个成员是objectType仍是Callback时,就会触发类型混杂缝隙。

类型混杂缝隙的运用办法

为了运用这种类型的缝隙,只需传递一个结构体,而且让该结构体的第二个成员为咱们想要从内核空间调用的函数的地址即可。

就这儿来说,该结构体的第二个成员寄存的是令牌盗取Shellcode代码的地址,以替换咱们的进程的令牌,这样,当创立新进程时,将运用该令牌。

可是,需求留意的是,这儿需求运用HEVD供给的shellcode(TokenStealingPayloadWin7无法正常运用,而且会导致体系溃散)。

修正shellcode

因为函数TypeConfusionInitializer会调用Callback指针,已然它是一个函数,所以,咱们需求设置函数的prologue和epilogue,并将ret 8改为ret。

留意:这儿我将shellcode函数编译为裸函数,假如您不这样做的活,也能够直接运用供给的shellcode。之所以这么做,仅仅不喜欢编译器将额定的代码添加到shellcode代码中罢了。

我的缝隙运用代码能够从这儿下载。

取得Shell

让咱们首要查看当时身份是否为普通用户。

普通用户

能够看出,当时身份仅仅普通用户。

运转缝隙运用代码后,咱们将富丽变身为ntauthority/system用户。

运用类型混杂缝隙获取SYSTEM Shell

整数溢出

下面,咱们开端介绍怎么运用HacksysExtremeVulnerableDriver中的整数溢出缝隙。

什么是整数溢出缝隙?

关于不了解整数溢出的人来说,听到这个称号的时分或许会十分困惑——整数怎么会溢出呢?

实践的整数是不会溢出。CPU会将整数存储在固定长度的内存空间中(留意,这儿咱们不会讨论堆或相似的内容)。假如您了解C/C++之类的编程言语的话,您或许还记得各种数据类型都具有固定的长度。

在大多数机器和操作体系上,字符变量长度为1字节,整型变量的长度为4字节。这意味着char数据类型能够保存长度为8比特的值,取值规模从0到255,假如是带符号的值,则取值规模为-128到127。整型变量也是如此,在整型变量长度为4字节的机器上,能够保存0到2的32次方-1之间的值(无符号值)。

现在,让咱们考虑运用一个最大值为2的32次方-1或0xFFFFFFF的无符号整型变量。取最大值后,假如再加1,会发作什么状况呢?因为一切32位上的值均为1,因而,加1将使其变为一个长度为33位的值,但因为存储器只能包容32位,因而这32位上的值将被设为0。

在履行上面的操作时,CPU一般会将数字加载到32位寄存器(此处指x86)中,加1时会设置进位标志,而寄存器各位的值为0,因为现在一切32位上的值都为0。

现在,假如进行长度查看,查看值的长度是否大于指定的值,比方10,则该查看将回来fail,但假如不存在长度约束,则比较操作将回来true。

为了加深了解,让咱们来调查一下详细的缝隙代码:怎么运用HEVD中的整数溢出缝隙来取得Windows内核中的代码履行权限。

含有整数溢出缝隙的代码

现在现已了解了整数溢出缝隙的相关概念,接下来,咱们来剖析一下含有该缝隙的代码(该缝隙坐落IntegerOverflow.c中的函数TriggerIntegerOverflow中)。

首要,该函数会创立一个ULONG型数组,该数组能够寄存512个成员元素(在common.h头文件中,BufferSize被设置为512)。

IntegerOverflow.c中含有整数溢出缝隙的函数

然后,内核会查看缓冲区是否坐落用户空间中,然后,它还会为咱们打印一些信息。这些信息关于咱们来说十分有协助。

完结上述操作后,内核会查看数据的长度(以及终结符的长度,即4个字节)是否大于KernelBuffer的长度。假如是的话,则退出,而且不会将用户空间中的缓冲区内容拷贝到内核空间的相应缓冲区中。

长度查看

可是,假如状况并非如此,则持续进行,并将数据仿制到内核缓冲区中。

这儿要留意的另一件事是,假如它在用户区缓冲区中遇到BufferTerminator,就会中止仿制,并持续履行后边的代码。因而,咱们需求将BufferTerminator放在用户形式缓冲区的结尾。

将用户空间数据仿制到内核空间的函数仓库

整数溢出

IntegerOverflow.c的第100行代码的问题在于,假如咱们供给的size参数为0xFFFFFFFC,然后再加上BufferTerminator的长度(这儿是4个字节),则有用长度变为:0xFFFFFFFC+ 4 = 0x00000000,即大于KernelBuffer的长度,可是,因为咱们经过了数据长度的查看,所以,能够将该缓冲区内容仿制到内核空间。

缝隙验证

现在,为了验证这个缝隙,咱们将把缓冲区内容发送到HEVD,可是将0xFFFFFFFC作为缓冲区的长度进行传递。现在,咱们不必设置一个巨大的缓冲区来令内核溃散,相反,只需发送一个小型的缓冲区并承认缝隙即可。

触发整数溢出的PoC

因为咱们知道缓冲区长度为512个ULONG型元素,因而,咱们能够发送这么长的数据,并查看内核的反响。

留意:这儿的重点是DeviceIoControl的第4个参数,而不是实践数据。

最终,将该缓冲区内容发送到HEVD,看看到底会发作什么状况。

成功触发整数溢出缝隙

正如您看到的那样,UserBufferSize的值为0xFFFFFFFC,但咱们仍设法绕过了长度的有用性查看并触发了整数溢出缝隙。

咱们发现,经过设置0xFFFFFFFC,咱们能够绕过长度查看,接下来要做的工作,便是在UserBuffer之后放置一个形式(一个唯一无二的形式),然后放置终结符,以找到保存的回来指针。

假如您不清楚该怎么操作,请阅览本文的前面部分,那里有详细的介绍。

下面,咱们开端介绍怎么运用这个缝隙。

整数溢出的运用办法

下面,咱们会经过HEVD供给的TokenStealingPayloadWin7 shellcode来掩盖保存的回来地址,这样,咱们就功德圆满了。

留意:为了防止溃散,需求对shellcode稍作修正,这项使命留作课后作业。

取得shell

下面,首要来查看一下当时的身份是否为普通用户。

普通用户

能够看出,当时身份仅仅普通用户。

运转咱们的缝隙代码之后,咱们的身份现已变为ntauthority/system。

成功运用整数溢出缝隙

完好的代码,咱们能够从作者的代码库中下载。

参考资料

  • HackSysTeam:https://github.com/hacksysteam
  • FuzzySecurity:http://www.fuzzysecurity.com/

原文地址:https://pwnrip.com/windows-kernel-exploitation-part-1-stack-buffer-overflows/

白帽汇从事信息安全,专心于安全大数据、企业要挟情报。

公司产品:FOFA-网络空间安全搜索引擎、FOEYE-网络空间检索体系、NOSEC-安全消息渠道。

为您供给:网络空间测绘、企业财物搜集、企业要挟情报、应急呼应服务。

推荐新闻