|
COMMAND uncgi SYSTEMS AFFECTED uncgi PROBLEM Khamba Staring posted following. He recently found a number of vulnerabilities in the CGI wrapper program `uncgi'. Un-CGI is a little program that parses options in i.e. QUERY_STRING and starts a CGI script. Since all parsing is done by uncgi, the CGI scripts themselves are simple and quick to make (all options/variables passed to the CGI script via the URL are translated into seperate environment variables). It is possible to run uncgi as a stand-alone executable or use it in library form. The problems described in this post are located in the executable, not the library. 1. uncgi does no relative directory checking; this means anyone can execute any program on the remote system as the http user (to some extent, permission wise of course) using the simple dot-dot-slash trick. 2. uncgi does not check if the script it will execute has any executable bits turned on. As most CGI scripts are just that-- scripts, uncgi will try to execute the program located behind #! on the first line of the CGI script and feed the CGI script filename itself as an argument. This means the CGI script doesn't have to be executable for uncgi to be able to execute it. SOLUTION Patch: --- uncgi.c.old Thu Jul 12 12:42:09 2001 +++ uncgi.c Thu Jul 12 13:24:35 2001 @@ -60,6 +60,14 @@ char *id = "@(#)uncgi.c 1.33 11/24/97"; + +void four_oh_three() +{ + printf("Content-Type: text/htm\n\n"); + printf("You have no permission!\n"); + exit(1); +} + /* * Convert two hex digits to a value. */ @@ -373,6 +381,18 @@ char *shell, *script; { char *argvec[4], **ppArg = argvec, *pz; + struct stat f_stat; + + if(stat(script, &f_stat) == -1) + html_perror("stat (something like this; dunno what html_perror does exactly)"); + +/* +** this should probably be expanded a bit; maybe check for S_IXUSR, S_IXGRP +** and S_IXOTH or the likes. Maybe add extra checks for suid or let the +** shell figure that out? +*/ + if(!(f_stat.st_mode & S_IXUSR)) + html_perror("not executable"); /* * "shell" really points to the character following the "#!", @@ -542,6 +562,21 @@ #endif } +int check_path(char *evilpath) +{ +#define RP_PATHLEN 1024 + char resolved_path[RP_PATHLEN]; + + if(!realpath(evilpath, resolved_path)) + return(0); /* evil path cannot be read; this can't be good! */ + + if(strncmp(SCRIPT_BIN, resolved_path, strlen(SCRIPT_BIN) - 1) == 0) + return(1); /* yay! */ + else + return(0); /* boo! */ +} + + #ifndef LIBRARY /* { */ main(argc, argv) int argc; @@ -600,6 +635,11 @@ strcpy(program, SCRIPT_BIN); strncat(program + sizeof(SCRIPT_BIN) - 1, pathinfo, proglen); +#ifndef VOID_SECURITY + if(!check_path(program)) + four_oh_three(); +#endif + #ifdef DEBUG printf("Program path is '%s'\n", program); fflush(stdout); @@ -700,6 +740,9 @@ */ argvec[0] = program; argvec[1] = NULL; +/* +** shouldn't we check for suid stuff here?! +*/ execv(program, argvec); #ifdef __MSDOS__ /* { */ Author released a fix for the ../ hole: http://www.midwinter.com/~koreth/uncgi.html has a link to the new version. Adding relative directory checking beyond that would have little security benefit. The following two-line shell script demonstrates why: #!/bin/sh /run/a/malicious/program/somewhere/else Put that script in Un-CGI's script directory and you're off and running. If you can put a symbolic link into the script directory, you can put a script like this there instead, so blocking symbolic links doesn't make your system particularly more secure. With the exception of the ../ hole, Un-CGI's security is exactly the same as the security of your script directory. Which, really, when you think about it, is also true of a typical CGI-capable Web server; as soon as you let random users stick programs in the cgi-bin directory you're opening yourself up to potential security problems.