Data Execution Prevention (DEP) has always been a hot topic in modern software exploitation.  This is a security feature implemented in most popular operating systems, designed to prevent a program from executing in a non-executable memory location.  So when a malicious code tries to inject payload in memory, it should fail during execution, and then simply crashes.  But here's the thing, although DEP plays an important role to your computer's countermeasures, it is not without a kryptonite.  When researchers such as Hovav Shacham introduced the Return-Oriented Programming (ROP) technique, it pretty much became the standard way to bypass DEP, and is still in use today.

However, when done manually, ROP can be a time-consuming task, sometimes painful.  A couple of years ago, if you were able to ROP anything, you were a ROP star!  As the technique became more well-understood by the general exploit dev community, tutorials and better tools were written to collect gadgets in order to speed up exploit development, and then ROP was a bit easier.  Eventually, Peter Van Eeckhoutte created mona.py to automate ROP generation -- getting a ROP chain done can be as simple as typing: "!mona rop".  Nowadays, many Metasploit modules (especially the browser ones) are just copy-and-pasting the same ROP chains to get code execution... but what's the point of repeating the same code over and over again?  The new RopDB mixin puts an end to that.

Metasploit RopDB addresses these needs based on our development habits:

  • Allow more reusable ROP chains in browser exploit development.
  • Allow two common attack vectors: non-ASLR plugins, or info leaks.
  • Simplify ROP maintenance.

The RopDB Database

There are mainly two components: the database, and the mixins.  The database itself consists of multiple XML files that store battle-ready ROP chains, each for a specific DLL.  The XML structure is best explained by the following image:

A "gadget" in this case, serves two different purposes:

  • "offset" - This is used to store the actual offset (to the base address).
  • "value" - This is used to store an integer that's not an address (offset). Or, to store a symbol, which will be converted to an integer during payload generation.  These are the symbols the mixin supports:
    • "nop" - A NOP
    • "junk" - A 4-byte junk
    • "size" - The payload size
    • "size_negate" - Sometimes a ROP chain may use the "NEG" instruction to calculate the payload size.

The RopDB Functions

Now, let's talk about the API.  There are three functions you can use in an exploit, they are:

  • generate_rop_payload() - This is used when the exploit does not have to modify the ROP chain at all.  It will generate a ROP payload in the following layout, with the stack pivot optional (in case you need to put it somewhere else):
Stack Pivot ROP Chain Payload
  • select_rop() - This is used in case the exploit needs to modify the ROP chain more freely.  When select_rop() is used, you're basically overriding rop_payload() too in order to build the payload.
  • has_rop?() - This is used in case you need to check if a ROP chain is actually available before picking one.

Code Examples

1. Generating a basic ROP payload

require 'msf/core'  
  
class Metasploit3 < Msf::Exploit::Remote  
  Rank = NormalRanking  
  
  include Msf::Exploit::RopDb  
  
  def initialize(info={})  
  super(update_info(info,  
  'Name'          => "RopDb Example 1",  
  'Description'    => %q{RopDb Example 1},  
  'License'        => MSF_LICENSE,  
  'Author'        => [ 'sinn3r' ],  
  'References'    => [ [ 'URL', 'http://metasploit.com' ] ],  
  'Platform'      => 'win',  
  'Targets'        => [ [ 'Automatic', {} ] ],  
  'Privileged'    => false,  
  'DisclosureDate' => "Oct 2 2012",  
  'DefaultTarget'  => 0))  
  end  
  
  def exploit  
  # This will generate a payload including our Java ROP  
  rop_payload = generate_rop_payload('java', payload.encoded)  
  
  # Print out the payload for inspection  
  print_line(Rex::Text.to_hex_dump(rop_payload))  
  end  
end  

2. Select a ROP chain, and then modify it

require 'msf/core'  
  
class Metasploit3 < Msf::Exploit::Remote  
  Rank = NormalRanking  
  
  include Msf::Exploit::RopDb  
  
  def initialize(info={})  
  super(update_info(info,  
  'Name'          => "RopDb Example 1",  
  'Description'    => %q{RopDb Example 2},  
  'License'        => MSF_LICENSE,  
  'Author'        => [ 'sinn3r' ],  
  'References'    => [ [ 'URL', 'http://metasploit.com' ] ],  
  'Platform'      => 'win',  
  'Targets'        => [ [ 'Automatic', {} ] ],  
  'Privileged'    => false,  
  'DisclosureDate' => "Oct 2 2012",  
  'DefaultTarget'  => 0))  
  end  
  
  def exploit  
  rop = select_rop('msvcrt')  
  
  # Modify dwSize for VirtualProtect()  
  rop[0] = 0x00000300  
  
  # Print the ROP chain for inspection  
  print_line(Rex::Text.to_hex_dump(rop))  
  end  
end  

3. Generate a ROP payload with a specific target version, a different base address, and a stack pivot):

require 'msf/core'  
  
class Metasploit3 < Msf::Exploit::Remote  
  Rank = NormalRanking  
  
  include Msf::Exploit::RopDb  
  
  def initialize(info={})  
  super(update_info(info,  
  'Name'          => "RopDb Example 1",  
  'Description'    => %q{RopDb Example 3},  
  'License'        => MSF_LICENSE,  
  'Author'        => [ 'sinn3r' ],  
  'References'    => [ [ 'URL', 'http://metasploit.com' ] ],  
  'Platform'      => 'win',  
  'Targets'        => [ [ 'Automatic', {} ] ],  
  'Privileged'    => false,  
  'DisclosureDate' => "Oct 2 2012",  
  'DefaultTarget'  => 0))  
  end  
  
  def exploit  
  pivot = [  
  0x20004171, # POP EDI # POP ESI # RETN (1e0d0000)  
  0x0c0c0c0c,  
  0x2001d755, # xchg eax, esp # ret (1e0d0008)  
  ].pack("V*")  
  
  p = payload.encoded  
  
  rop_payload = generate_rop_payload('flash', p, {'pivot'=>pivot, 'target'=>'11.3.300.268', 'base'=>0x20000000})  
  
  print_line(Rex::Text.to_hex_dump(rop_payload))  
  
  end  
end  

If you're new to Metasploit module development, please also check our Metasploit Development Environment for tips on setting that all up, and then get ROPpin' like a ROP star.

===

UPDATE:

  • Oct 4th 2012 - mona.py now supports RopDb database XML format.