Return-Path: Delivered-To: new-httpd-archive@hyperreal.org Received: (qmail 1902 invoked by uid 6000); 25 Jan 1999 22:43:05 -0000 Received: (qmail 1821 invoked from network); 25 Jan 1999 22:42:54 -0000 Received: from imo26.mx.aol.com (198.81.17.70) by taz.hyperreal.org with SMTP; 25 Jan 1999 22:42:54 -0000 Received: from TOKILEY@aol.com by imo26.mx.aol.com (IMOv18.1) id 7DOWa00811 for ; Mon, 25 Jan 1999 17:37:58 -0500 (EST) From: TOKILEY@aol.com Message-ID: <5f71a0ed.36acf246@aol.com> Date: Mon, 25 Jan 1999 17:37:58 EST To: new-httpd@apache.org Mime-Version: 1.0 Subject: WIN32 CGI - SECURITY THREAT - 4 OF 4 Content-type: text/plain; charset=US-ASCII Content-transfer-encoding: 7bit X-Mailer: AOL 3.0 16-bit for Windows sub 41 Sender: new-httpd-owner@apache.org Precedence: bulk Reply-To: new-httpd@apache.org WIN32 PROBLEM: WIN32 CGI POSES SECURITY THREAT RELATES TO: A number of currently open Apache WIN32 CGI PR REPORTS The following is from the latest version of ..\APACHE_1.3.4\SRC\MAIN\UTIL_SCRIPT.C My comments are all preceded with //: The USC 'Berky-jerky' coding style has been re-organized to make the code easier to follow... API_EXPORT(int) ap_call_exec( request_rec *r, child_info *pinfo, char *argv0, char **env, int shellcmd ) { int pid = 0; //: Top leg includes handling of all the RLIMIT_XXXX flags... #ifdef OS2 //: OS2 handler is in this leg... #elif defined(WIN32) { char interpreter[2048]; /* hope it's enough for the interpreter path */ interpreter[0] = 0; pid = -1; //: Code attempts to determine nature of executable file... //: If it doesn't have one of the HARD-CODED executable types //: then the file is 'opened', 2047 bytes are read, and the //: code checks for 'EL-BANGO' (SHA-BANG). //: If EL-BANGO is seen then here's where the danger lies... if (!strncmp(interpreter, "#!", 2)) { //: If EL-BANGO is 'seen' then assume it's a script... is_script = 1; //: The rest of this pickup simply accepts //: all characters following EL-BANGO up //: to the first CR or LF as the INTERPRETER //: that should be run for this script... //: Could be ANYTHING here. No checks are made. //: This is actually a BIG SECURITY HOLE //: A user can create a CGI 'script' that can do //: just about ANYTHING here since the buffer is //: 2047 characters and WIN32 'commands' can be //: 'ganged' on a line. //: EXAMPLES... Apache will happily execute the //: following thinking the commands are script //: interpreters... //: Apache wipes out system dir... prompt supressed... //: !#DELTREE /Y C:\WINDOWS\SYSTEM //: Launches a secondary command processor //: and allows it to funtction as the PRIMARY //: command processor. DOS will not automatically //: return to the parent processor. (EXIT won't work). //: Can also launch any program in new shell //: that becomes 'un-killable'... //: !#COMMAND /P COMMAND.COM //: BIZARRE BUT PERHAPS POSSIBLE... //: On most machines this will launch a brand //: new DOS PROMPT that takes over the process, //: starts a new TELNET session with the LOCAL //: TCP/IP SERVER NODE and redirects all output //: back out COM1: Crazy... but can work if a //: hacker gets lucky. //: #!COMMAND /K:TELNET 127.0.0.1 1> COM1: //: THERE ARE LOTS OF OTHER COMBINATIONS OF //: COMMANDS AND SWITCHES THAT RUN 'NEW SHELLS' //: WITH THEIR OWN ENVIRONMENTS AND FULL SECURITY //: OVERRIDES IF 'ENVIRONMENTS' ARE NOT 'PASSED ALONG'. //: Apache checks nothing. It executes whatever it finds. //: Obviously with some creativity someone could do //: a lot of damage... if certain 'conditions' are //: true on the Server... but that is usually the //: cause of all security problems. Administrators //: 'assume' that the software will stop someone //: and they 'forget' to cover all the bases. //: With this situation in Apache there is a LOT //: that an Admin would have to do to make it safe //: beyond setting some USER permissions and tweaking //: the HTTPD,SRM,ACCESS config files. for (i = 2; i < sizeof(interpreter); i++) { if ((interpreter[i] == '\r') || (interpreter[i] == '\n')) { break; } } interpreter[i] = 0; //: Next 2 lines just remove leading spaces //: from upcoming command line and left-shifts //: the buffer. Still no checks being made on //: the content of the line that will execute... //: Head 'em up... for (i = 2; interpreter[i] == ' '; ++i) ; //: Move 'em out... memmove(interpreter+2,interpreter+i,strlen(interpreter+i)+1 ); } else { //: The first 2 bytes of the file are NOT EL-BANGO... //: End of 'else'... EL-BANGO '#!' was NOT SEEN... } //: End 'if( !is_exe )' which means the file did NOT //: have one of the HARD-CODED executable file extensions. } /* Bail out if we haven't figured out what kind of * file this is by now.. */ if ( !is_exe && !is_script && !is_binary ) { //: If we haven't passed ANY of the 'tests' then it's //: Goodnight Gracie... log error and bail... ap_log_rerror( APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r, "%s is not executable; ensure interpreted scripts have " "\"#!\" first line", r->filename); //: Turn and burn >> 'pid' is still '0' at this point... return (pid); } //: End if( !shellcmd )' pickup section... } //: The rest... return (pid); } }// End of ap_call_exec()...