OSEC

Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
 
From: Khamba Staring (purrcatedoropolis.org)
Date: Tue Jul 17 2001 - 05:48:12 CDT

  • Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]

    I recently found a number of vulnerabilities in the CGI wrapper program
    `uncgi'. I was amazed to find out this was never reported before (at least;
    the archives don't show it).

    Description
    -----------

    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.

    Two very serious matters; I mailed the writer midwinter.com and he
    was kind enough to add a little `bugs' section to his uncgi page. However,
    I don't believe _that_ will change much. As these vulnerabilities are
    so easy to exploit, I almost know for sure these vulnerabilities are
    already being exploited.
    Don't get mad at me; I just want this to become known so things will
    get fixed. I attached a patch which should fix the problems I pointed
    out in this post. This patch will almost certainly break things on
    insecure websites.

    Kind regards,

    -- Khamba Staring

    -----------------------------------------------------------------------------
    --- 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__ /* { */