http://www.perlmonks.org?node_id=306617


in reply to Vetting a CGI script

In addition to the helpful responses posted here, I appreciate Limbic~Region's reminder in the ChatterBox that we can't rely on the HTML form to impose length and content restrictions. It is easy to download a local copy of the page and modify it (or even to manually construct a posting URL).

In particular, Limbic~Region mentions the possibility of potential modification of the $CGI::DISABLE_UPLOADS and $CGI::POST_MAX values.

For me, this possibility places a greater burden on the receiving script. A)Nothing dangerous (like a malevolent cgi script) should be uploaded to a place where it could be invoked from the web and B)Massive return values from the form fields should probably be simply discarded rather than attempting to process/forward/store them.

In the current case, as best I can tell, uploads are not an issue. I assume someone could construct and post a response containing a dangerous or large upload. But without intervention by the receiving script, I presume it would simply languish in a tmp directory. A large, ininvited upload might slow the server down a bit or threaten the harddisk capacity, but there are other places (e.g. httpd.conf) to deal with that.

On the other hand, over-large form data needs to be anticipated and handled appropriately within the receiving script.

------------------------------------------------------------
"Perl is a mess and that's good because the
problem space is also a mess.
" - Larry Wall

Replies are listed 'Best First'.
Re: Re: Vetting a CGI script
by jdtoronto (Prior) on Nov 12, 2003 at 20:45 UTC
    Contemplate this, a one-time colleague wrote a CGI that had once had an upload feature in it, the code was taken out, but his temp directory was in fact the cgi-bin directory. Someone who recognised the cgi (it was foolishly placed on a CGI download site) knew that he could upload a script to replace one that was already in the directory - but no longer used. Can you see where I am going! Somebody did just that, they uploaded a script, then they uploaded another, called them innocuously from the browser and siezed control of the machine, looked in the code for the original CGI, got the info for the database, downloaded his entire database (about 2 million records) and then proceeded to delete the database and then force a backup (another of the CGI's functions) that cleared his backup of data as well. By the time he got to the office the next day it was all over. The company went belly up and he along with it.

    PROTECT YOURSELF FROM UPLOADS!

    I learned a lot about CGI security from that experience.
    jdtoronto

      Great story. I'm bookmarking that.

      And consider this: even if you don't have a million records to protect, you have computer resources to protect. If someone breaks into your machine, they can use it as a staging platform against someone else (or a warez site), diverting the blame (at least temporarily) toward you.

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

      Ok, I see how they were able to take over the machine in that example, but assuming you *have* to offer file upload, how can you protect against that? It's been a long time since I've worked with CGI's that offer file upload capability, and I think when we did, we handled it with CGI.pm. I don't recall specifying a "temp" directory. Is the solution to the problem you presented fixed by specifying a temp directory that is *NOT* the cgi-bin directory?

      I just read some in 'perldoc CGI' - there's a section titled "-private_tempfiles" that describes security issues with file uploads and the snifibility of info being written to those temp files.

      I guess I'm wondering what the *right* way to program file uploads - is using CGI.pm to do that a good way?

      TIA.
        Hi hmerrill,

        Well, you are asking me to stretch back into history. The raid took place in late 1997 and the cgi would have been written between late 1996 and mid-1997. It is in fact quite possible that cgi-lib.pl (Which was a popular predecessor to cgi.pm, written by Steve Brenner of Stanford and last updated in 1999).

        The cgi.pm documentation says: "temporary files are created in /usr/tmp or /tmp and should be deleted automatically." Assuming this is the case there would be little to worry about. Using the PRIVATE_TEMPFILES is a nice trick, at least on *nix systems where the trick works.

        As I recall cgi-lib.pl had some user specifiable variables in the first few lines of code. One that I was always chagning was the maximum file size, but there was also one to specify where the file was written. I think this was the vulnerability. The cgi-lib variable wrote files into a directory that was executable under cgi-bin.

        The moral of the story is that you need to think before you do ANYTHING! Currently I use CGI.pm through CGI::Application under mod_perl. But there are alternatives, most notable CGI::Upload which I have never used. As to the right way? Thou dost speak heresay! Any way is good, there is no right way, but many wrong ways. Make sure you know where temp files go. Make sure that you somehow 'untaint' anything you get from a user - even files.

        jdtoronto

        Definitely use CGI.pm when doing file uploads. It handles all the details.

        It also writes the uploads to temp files. Since these are randomly named and placed in a temporary directory, these won't overwrite anything important. CGI.pm also takes care of removing the temp files once the script is done. With '-private_tempfiles', the file is deleted right after it is created so that nobody else can read. Only the process with the open filehandle can read it.

        CGI.pm also imposes size limits on uploads. This makes it harder for attackers to fill up the disk or slow down the network connection.

        The next thing to consider is what happens with the uploaded file. Usually it gets copied someplace. It is important that the destination be controlled by the script and not by the uploaded file name. It is a good idea to hard code the destination directory. It should be separate from any script directories. It is also a good idea to keep the uploads separate from the static files. If the filename included with the upload is going to be used, it must be sanitized to remove dangerous characters and any path components.

        Finally, most uploads should only be allowed to authenticated users. Allowing uploads from anonymous users is usually a bad idea.