NCSA PHP/FI CGI *2 HOLES*

Summary
Description:First of all, this rather pathetic cgi allows anyone to trivially read any file on the system which is readabl by the owner of the httpd process (usually nobody or daemon). It also has a buffer overflow.
Author:Shamanski <jshaman@M-NET.ARBORNET.ORG> posted the read-any-file exploit, The SNI advisory is by David Sacerdote
Compromise:read files and execute code as the httpd process owner (remote)
Vulnerable Systems:Those with php.cgi 2.0beta10 or earlier, distributed with NCAA httpd, possibly others.
Date:16 April 1997
Details

Exploit:

From jshaman@M-NET.ARBORNET.ORG Fri Apr 18 22:29:09 1997
Date: Wed, 16 Apr 1997 21:01:12 -0400
From: Shamanski 
To: BUGTRAQ@NETSPACE.ORG
Subject: Update on PHP/FI hole

============================================================================
[DiS] Advisory 97-347.1
Issue date: April 16, 1997
Topic:  REMOTE Vulnerability in PHP/FI
----------------------------------------------------------------------------

A vulnerability has been found by DiS in PHP/FI, a NCSA httpd cgi enhancment.
This vulnerability allows unauthorized users to view arbitrary file contents
on the machine running httpd by sending the file name wishing to be displayed
as the QUERY_STRING.

I. Exploit

   simply use any web browser to send the following URL:

   http://boogered.system.com/cgi-bin/php.cgi?/file/to/view

   Note: this exploit has not been tested on a system that has compiled
         PHP/FI as an apache module. This information may or may not
         be applicable on such a system.

II. Impact

    Remote, unauthorized users can view arbitrary file contents on the
    system with the same privileges as the httpd (HTTP daemon) child process.


III. Solution

    The author has propsed the following sollution:

>> ...The workaround is to set the following in php.h
>>
>> #define PATTERN_RESTRICT ".*\\.phtml$"
>>
>> This will limit the php.cgi parser to only display files ending in .phtml
>>
>> The exact same adviasory applies to any other parser someone might decide
>> to stick in their cgi-bin directory.  This is in no way specific to PHP/FI.
>>
>> You can also avoid the problem by using either CGI redirection or
>> by using the Apache module version.
>>
>> -Rasmus

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

The current PHP/FI distribution may be obtained from http://www.vex.net/php

J-Man Th' Shaman [DiGiTAL iNFORMATiON SOCiETY]
jshaman@m-net.arbornet.org
jamin@avatar.ml.org


--SNI advisory:

From davids@SECNET.COM Fri Apr 18 22:29:51 1997
Date: Thu, 17 Apr 1997 16:02:07 -0600
From: David Sacerdote 
To: BUGTRAQ@NETSPACE.ORG
Subject: PHP/FI command line buffer overflow

X-Premail-Auth: Key matching expected Key ID 9E55000D not found

-----BEGIN PGP SIGNED MESSAGE-----

                    ######    ##   ##    ######
                    ##        ###  ##      ##
                    ######    ## # ##      ##
                        ##    ##  ###      ##
                    ###### .  ##   ## .  ######.

                         Secure Networks Inc.

                          Security Advisory

                           April 17, 1997

                      Buffer Overflow in php.cgi

This advisory describes a remotely exploitable buffer overflow in the PHP
cgi program.  This is *NOT* the PATTERN_RESTRICT issue described in
earlier bugtraq discussion.


Problem Description
~~~~~~~~~~~~~~~~~~~

In the function FixFilename() function in file.c, PHP attempts to pass
strings whose length may be as long as  8 kilobytes into buffers as small
as 128 bytes.  This overwrites the stack, making it possible for an
attacker to obtain shell access to the machine running the web server.



Technical Details
~~~~~~~~~~~~~~~~~

The filename argument to FixFilename is derived from the command line
used to invoke to the CGI script, or from the QUERY_STRING environment
variable passed to it.  The total length of either can be as long as
eight kilobytes, but the fn string is a mere 128 bytes long.  An
excerpt from the flawed code reads:

char *FixFilename(char *filename, int cd, int *ret) {
 ...
        char fn[128], user[128], *s;
 ...
        s = strrchr(filename,'/');
        if(s) {
                strcpy(fn,s+1);
 ...



Impact
~~~~~~

Attackers can remotely obtain shell or command line access to any vulnerable
system.


Vulnerable Systems
~~~~~~~~~~~~~~~~~~

Any computer running a web server with php.cgi 2.0beta10 or earlier
is vulnerable, irrespective of what operating system it is running,
provided that PHP is run as a cgi, and not as an Apache module.  When
compiled as an Apache module, PHP does not appear to execute the
problem code.

To determine whether a system is running a web server with php.cgi installed
as a cgi, use your favorite web browser to access the URL

http://hostname/cgi-bin/php.cgi

If you see something like:

PHP/FI Version 2.0b10
 ...

Then the machine hostname is running PHP/FI.


Fix information
~~~~~~~~~~~~~~~

Use the patch program to apply the following diffs to file.c, then recompile
php.cgi.  These diffs are against version 2.0b10.

*** file.c      Thu Apr 17 09:36:07 1997
- --- file.c.fixed      Thu Apr 17 09:36:00 1997
***************
*** 295,315 ****

        s = strrchr(filename,'/');
        if(s) {
!               strcpy(fn,s+1);
                o=*s;
                *s='\0';
!               strcpy(path,filename);
                *s=o;
        } else {
  #ifdef PHP_ROOT_DIR
!               strcpy(path,PHP_ROOT_DIR);
  #else
                path[0] = '\0';
  #endif
!               strcpy(fn,filename);
        }
        if(fn && *fn=='~') {
!               strcpy(path,fn);
                fn[0]='\0';
        }
        if(*path) {
- --- 295,320 ----

        s = strrchr(filename,'/');
        if(s) {
!               strncpy(fn,s+1, sizeof (fn));
!               fn[sizeof(fn) - 1] = '\0';
                o=*s;
                *s='\0';
!               strncpy(path,filename, sizeof (path));
!               path[sizeof(path) - 1] = '\0';
                *s=o;
        } else {
  #ifdef PHP_ROOT_DIR
!               strncpy(path,PHP_ROOT_DIR, sizeof(path));
!               path[sizeof(path) -1] = '\0';
  #else
                path[0] = '\0';
  #endif
!               strncpy(fn,filename, sizeof (fn));
!               fn[sizeof(fn) - 1] = '\0';
        }
        if(fn && *fn=='~') {
!               strncpy(path,fn, sizeof (path));
!               path[sizeof(path) - 1] = '\0';
                fn[0]='\0';
        }
        if(*path) {
***************
*** 319,328 ****
                                o=*s;
                                *s='\0';
                        }
!                       strcpy(user,path+1);
                        if(s) {
                                *s=o;
!                               strcpy(temp,s);
                        } else temp[0]='\0';
  #ifdef HAVE_PWD_H
                        if(*user) {
- --- 324,335 ----
                                o=*s;
                                *s='\0';
                        }
!                       strncpy(user,path+1, sizeof (user));
!                       user[sizeof(user) - 1] = '\0';
                        if(s) {
                                *s=o;
!                               strncpy(temp,s, sizeof (temp));
!                               temp[sizeof(temp) - 1] = '\0';
                        } else temp[0]='\0';
  #ifdef HAVE_PWD_H
                        if(*user) {
***************
*** 333,339 ****
                                  pd = getenv(PHP_PUB_DIRNAME_ENV);
  #endif
                                  if (pd == 0) pd = PHP_PUB_DIRNAME;
!                                 sprintf(path,"%s/%s%s",pw->pw_dir,pd,temp);
                                }
                        }
  #endif
- --- 340,351 ----
                                  pd = getenv(PHP_PUB_DIRNAME_ENV);
  #endif
                                  if (pd == 0) pd = PHP_PUB_DIRNAME;
!                                 strcpy (path,pw->pw_dir);
!                                 strcat (path,"/");
!                                 strncat (path, pd,
!                                       sizeof(path) - strlen(path) - 1);
!                                 strncat (path, temp,
!                                        sizeof (path) - strlen(path) - 1);
                                }
                        }
  #endif
***************
*** 343,352 ****
                                o=*s;
                                *s='\0';
                        }
!                       strcpy(user,path+2);
                        if(s) {
                                *s=o;
!                               strcpy(temp,s);
                        } else temp[0]='\0';
  #if HAVE_PWD_H
                        if(*user) {
- --- 355,366 ----
                                o=*s;
                                *s='\0';
                        }
!                       strncpy(user,path+2, sizeof (user));
!                       user[sizeof(user) - 1] = '\0';
                        if(s) {
                                *s=o;
!                               strncpy(temp,s,sizeof(temp));
!                               temp[sizeof(temp) - 1] = '\0';
                        } else temp[0]='\0';
  #if HAVE_PWD_H
                        if(*user) {
***************
*** 357,363 ****
                                  pd = getenv(PHP_PUB_DIRNAME_ENV);
  #endif
                                  if (pd == 0) pd = PHP_PUB_DIRNAME;
!                                 sprintf(path,"%s/%s%s",pw->pw_dir,pd,temp);                   }
                        }
  #endif
                }
- --- 371,383 ----
                                  pd = getenv(PHP_PUB_DIRNAME_ENV);
  #endif
                                  if (pd == 0) pd = PHP_PUB_DIRNAME;
!                                 strcpy (path,pw->pw_dir);
!                                 strcat (path,"/");
!                                 strncat (path, pd,
!                                       sizeof(path) - strlen(path) - 1);
!                                 strncat (path, temp,
!                                        sizeof (path) - strlen(path) - 1);
!                               }
                        }
  #endif
                }
***************
*** 370,376 ****
                        }
                }
                if(*fn) {
!                       sprintf(temp,"%s/%s",path,fn);
  #ifndef WINDOWS
                        st = stat(temp,&gsb);
  #else
- --- 390,399 ----
                        }
                }
                if(*fn) {
!                       strncpy (temp, path, sizeof (temp));
!                       temp[sizeof(temp) - 1] = '\0';
!                       strcat (temp,"/");
!                       strncat(temp,fn,sizeof(temp) - strlen(temp) - 1);
  #ifndef WINDOWS
                        st = stat(temp,&gsb);
  #else
***************
*** 382,394 ****
                                st = -1;
  #endif
                        if((st!=-1) && (gsb.st_mode&S_IFMT)==S_IFDIR) {
!                               sprintf(temp,"%s/%s/index.html",path,fn);
                                st = stat(temp,&gsb);
                                if(st==-1) {
!                                       sprintf(temp,"%s/%s/index.phtml",path,fn);
                                        st = stat(temp,&gsb);
                                }
!                               sprintf(path,"%s/%s",path,fn);
                        } else if(st==-1) {
                                l = strlen(temp);
                                if(strlen(fn)>4) {
- --- 405,431 ----
                                st = -1;
  #endif
                        if((st!=-1) && (gsb.st_mode&S_IFMT)==S_IFDIR) {
!                               strncpy (temp,path,sizeof(temp));
!                               temp[sizeof(temp) - 1] = '\0';
!                               strcat (temp, "/");
!                               strncat (temp,fn,
!                                       sizeof(temp) - strlen (temp) - 1);
!                               strncat (temp,"/index.html",
!                                       sizeof(temp) - strlen (temp) - 1);
                                st = stat(temp,&gsb);
                                if(st==-1) {
!                                       strncpy (temp,path,sizeof(temp));
!                                       temp[sizeof(temp) - 1] = '\0';
!                                       strcat (temp, "/");
!                                       strncat (temp,fn,
!                                            sizeof(temp) - strlen (temp) - 1);
!                                       strncat (temp,"/index.html",
!                                            sizeof(temp) - strlen (temp) - 1);
                                        st = stat(temp,&gsb);
                                }
!                               strcat (path,"/");
!                               strncat (path, fn,
!                                       sizeof(path) - strlen(path) - 1);
                        } else if(st==-1) {
                                l = strlen(temp);
                                if(strlen(fn)>4) {
***************
*** 410,422 ****
                                st = -1;
  #endif
                        if((st!=-1) && (gsb.st_mode&S_IFMT)==S_IFDIR) {
!                               sprintf(temp,"%s/index.html",path);
                                st = stat(temp,&gsb);
                                if(st==-1) {
!                                       sprintf(temp,"%s/index.phtml",path);
                                        st = stat(temp,&gsb);
                                }
!                       } else strcpy(temp,path);
                }
        } else {
  #ifndef WINDOWS
- --- 447,468 ----
                                st = -1;
  #endif
                        if((st!=-1) && (gsb.st_mode&S_IFMT)==S_IFDIR) {
!                               strncpy (temp, path, sizeof (temp));
!                               temp[sizeof(temp) - 1] = '\0';
!                               strncat (temp, "/index.html",
!                                       sizeof (temp) - strlen (temp) - 1);
                                st = stat(temp,&gsb);
                                if(st==-1) {
!                               strncpy (temp, path, sizeof (temp));
!                               temp[sizeof(temp) - 1] = '\0';
!                               strncat (temp, "/index.phtml",
!                                       sizeof (temp) - strlen (temp) - 1);
                                        st = stat(temp,&gsb);
                                }
!                       } else {
!                               strncpy(temp,path, sizeof (temp));
!                               temp[sizeof (temp) - 1] = '\0';
!                       }
                }
        } else {
  #ifndef WINDOWS
***************
*** 430,442 ****
                        st = -1;
  #endif
                if((st!=-1) && (gsb.st_mode&S_IFMT)==S_IFDIR) {
!                       sprintf(temp,"%s/index.html",fn);
                        st = stat(temp,&gsb);
                        if(st==-1) {
!                               sprintf(temp,"%s/index.phtml",fn);
                                st = stat(temp,&gsb);
                        }
!               } else strcpy(temp,fn);
        }
        *ret=st;
        return(temp);
- --- 476,498 ----
                        st = -1;
  #endif
                if((st!=-1) && (gsb.st_mode&S_IFMT)==S_IFDIR) {
!                       strncpy (temp, fn, sizeof (temp));
!                       temp[sizeof(temp) - 1] = '\0';
!                       strncat (temp, "/index.html",
!                               sizeof (temp) - strlen (temp) - 1);
                        st = stat(temp,&gsb);
                        if(st==-1) {
!                               strncpy (temp, fn, sizeof (temp));
!                               temp[sizeof(temp) - 1] = '\0';
!                               strncat (temp, "/index..phtml",
!                                       sizeof (temp) - strlen (temp) - 1);
!
                                st = stat(temp,&gsb);
                        }
!               } else {
!                       strncpy(temp,fn,sizeof (temp));
!                       temp[sizeof(temp) - 1] = '\0';
!               }
        }
        *ret=st;
        return(temp);


Additional Information
~~~~~~~~~~~~~~~~~~~~~~

If you have any questions about this advisory, feel free to mail me at
davids@secnet.com. Past Secure Networks advisories can be found at
ftp://ftp.secnet.com/pub/advisories, and Secure Networks papers can be
found at ftp://ftp.secnet.com/pub/papers.

PHP/FI was written by Rasmus Lerdorf .  Additional
information about PHP/FI can be found at http://www.vex.net/php

This advisory does NOT address a recently published hole in the php.cgi
which allows attackers to obtain copies of any file on the web server
which is readable by the user the php.cgi program runs as.

FIRST and vendor contacts please note that this advisory was expedited.
This is becuase we felt that previous public post (by another) party would
lead to the eventual discovery of this bug. As a result of this we therefore
wanted a fix to be availible to the public as soon as possible.

The following PGP key is for davids@secnet.com, should you wish to encrypt
any message traffic to the author of this advisory:

- -----BEGIN PGP PUBLIC KEY BLOCK-----
Version: 2.6.2

mQCNAzJ4qJAAAAEEAOgB7mooQ6NgzcUSIehKUufGsyojutC7phVXZ+p8FnHLLZNB
BLQEtj5kmfww2A2pR29q4rgPeqEUOjWPlLNdSLby3NI8yKz1AQSQLHAwIDXt/lku
8QXClaV6pNIaQSN8cnyyvjH6TYF778yZhYz0mwLqW6dU5whHtP93ojDw1UhtAAUR
tCtEYXZpZCBTYWNlcmRvdGUgPGRhdmlkc0BzaWxlbmNlLnNlY25ldC5jb20+
=LtL9
- -----END PGP PUBLIC KEY BLOCK-----

Feel free to send responses and commments to sni@secnet.com.  If you
should wish to encrypt such traffic, please use the Secure Networks Inc.
key:

- -----BEGIN PGP PUBLIC KEY BLOCK-----
Version: 2.6.2

mQCNAzLaFzIAAAEEAKsVzPR7Y6oFN5VPE/Rp6Sm82oE0y6Mkuof8QzERV6taihn5
uySb31UeNJ4l6Ud9alOPT/0YdeOO9on6eD1iU8qumFxzO3TLm8nTAdZehQSAQfoa
rWmpwj7KpXN/3n+VyBWvhpBdKxe08SQN4ZjvV5HXy4YIrE5bTbgIhFKeVQANAAUR
tCVTZWN1cmUgTmV0d29ya3MgSW5jLiA8c25pQHNlY25ldC5jb20+iQCVAwUQM03n
27Tl3s+VYMi5AQHdGwP+N3hhILzzhSvhx1gj6ZElgsLa7Q1P3cTlc/Xqx50/wkcX
qIwiPudH+9UHvpL8fUNaHc9iZf3y8YZz0HWz56Vm5SG7uBfB/ksq4x04pQ65dQ1m
v51DYCvLG9u0jL4hC3Mz9WvIMANXqOUlAhuU1iy0wM41joE8aHdh2jsLHlB5qlSJ
AJUDBRAzTlbK/3eiMPDVSG0BAcTNA/9eF0X4Ei8LM4CXFW7JTB5vwXxerR6FmKI8
0JXt6KTrjGBzTfBrDGUZHNakPELjQPQI+fqg6hKJ7Ro1eSL4QbtX2BTO+wIWoLJG
hQmccKleuEK5N9vFgzvPTRknfkbqL1Ta7g3Z9tE8TQhFbj0x4yNFAPB/hOhVvY3s
YOkUx4T12A==
=ljNl
- -----END PGP PUBLIC KEY BLOCK-----


Copyright Notice
~~~~~~~~~~~~~~~~

The contents of this advisory are Copyright (C) 1997 Secure Networks Inc,
and may be distributed freely provided that no fee is charged for
distribution, and that proper credit is given.

PHP sources distributed as part of this advisory fall under the GNU
Public license, version 2.



-----BEGIN PGP SIGNATURE-----
Version: 2.6.2

iQCVAwUBM1ZjwbgIhFKeVQANAQE/HQP/cuvfviM3RdAtMFw4JlafVfAZ8KNYaP61
dHcg0KmEZYeChOFgtRULHj9d2bhYniAjwVkioO4vIwvsmfNZSGnP3kMMQRv0oSkJ
9MNqeupqeF3cs3i88m8bT8TH9qNOvsbHAGix/TNHvgSK63rzUfzbfDbId8YwA2JD
2892qweY4b0=
=vuDt
-----END PGP SIGNATURE-----



More Exploits!

The master index of all exploits is available here (Very large file)
Or you can pick your favorite operating system:
All OS's Linux Solaris/SunOS Micro$oft
*BSD Macintosh AIX IRIX
ULTRIX/Digital UNIX HP/UX SCO Remote exploits

This page is part of Fyodor's exploit world. For a free program to automate scanning your network for vulnerable hosts and services, check out my network mapping tool, nmap. Or try these Insecure.Org resources: