Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation

Hacking CGI - security and exploitation

by IlyaM (Parson)
on Jun 24, 2002 at 17:01 UTC ( #176857=perlmeditation: print w/replies, xml ) Need Help??

Just found decent paper on common mistakes in Perl CGI programming: Hacking CGI - security and exploitation by b0iler. I hope it is interesting for other Perl monks.

Ilya Martynov (

  • Comment on Hacking CGI - security and exploitation

Replies are listed 'Best First'.
Re: Hacking CGI - security and exploitation
by cjf (Parson) on Jun 24, 2002 at 20:54 UTC

    A couple small problems with the paper:

    • He does mention, but then proceeds to ignore it and continually try stuff like @pair = split(/&/, $ENV{'QUERY_STRING'}); throughout the paper.
    • It's too long and not very well formatted. I mostly just read the code, the target audience definately won't read through the whole thing. Presentation is very important for these type of papers.
    • He should have had a big sign at the start saying "Don't trust user input" because that's basically what all the problems result from.

    On the plus side, it was fairly in-depth (could have been broken down into separate parts though) and it's always good to see coverage of cross-site scripting and other commonly ignored security issues.

    Update: In question 12 ("I heard "homemade" CGI scripts are more vulnerable to being hacked than distributed") he could have mentioned NMS scripts as a quality alternative. For bonus points he could start a flamewar and say "but crackers have access to their source code" ;).

Re: Hacking CGI - security and exploitation
by crazyinsomniac (Prior) on Jun 24, 2002 at 21:47 UTC
    Hmm, is it me, or is this a whole lot of hooey, and I quote:

    Perl Length Limits

    I might as well mention this here just because I haven't seen it in any other papers. I have only seen this problem only a few times but things like this do exist and 99% of the perl coders out there never even think about it. This is when perl limits filename sizes, variable sizes, and limits other such things which can effect how things in a script work. With this example you can effect things such as -e check, open, unlink, and other file handling functions operate.

    The problem is simple, take this code as an example, although long should be simple enough for newbies to understand:

    #check for bad characters if($FORM{'path'} =~ m/\0|\r|\n/ig){ die "illegal characters"; } #check for .htaccess file in /home/user/accounts/$FORM{path} $htaccess = "/home/user/accounts/$FORM{user}/.htaccess"; if(-e $htaccess){ #read .htaccess open(HTACCESS, "<", $htaccess) or die "could not open .htaccess file"; @lines = <HTACCESS>; close(HTACCESS); #get username and password ($correctuser,$correctpassword) = split(/:/,$lines[0]); #check if they are right, give access if($FORM{'user'} eq $correctuser && $FORM{'pass'} eq $correctpassword){ print "access granted"; access(); } else{ print "access denied"; } } #if the .htaccess does not exist then create a new account. else{ #makes the directory #error unless the directory already exists #if it exists than the script thinks it's just missing .htaccess mkdir($FORM{'user'},0755) or die "error accessing user directory" unless (-d $FORM{user}); #create .htaccess file and print username:password #this should be encrypted but it is just an example. $accessfile = $FORM{'user'} . "/.htaccess"; open(USERACCESS, ">", $useraccess) or die "could not create user file"; print USERACCESS "$username:$password"; close(USERACCESS); }

    So what does this code do? It will check if /home/user/accounts$FORM{'path'}/.htaccess exists, if it does it will check the submitted username and password against the real one. If it doesn't exist then it will create a new user directory and a .htaccess in it with the submitted username and password. This looks secure from all the previous types of attacks, but because perl limits filename sizes to around 2050 bytes (atleast that is what it is on my box) it can be exploited.

    So lets say someone has the account with the username of admin. Their home directory would be /home/user/accounts/admin/ and their username:password would be in /home/user/accounts/admin/.htaccess usually this would protect people from accessing this directory. But if an attacker submits ././././././././././././[another 2000 bytes of this[./././admin as $FORM{'user'} there is trouble. The attacker will need to make ././././[etc#&093;./././admin/.htaccess a valid length so that the .htaccess file is created when the script does open(USERACCESS, ">" $useraccess) but will fail the if(-e $htaccess) when another 20 bytes are added from the '/home/user/accounts/'.

    There are other possible ways to exploit scripts based on how perl sets size limits, this is a very tricky thing to find and even harder to remind yourself of these limits while coding. Best stratigy is to limit sizes of all input to a reasonable length (few hundred characters) and be very aggressive when checking if files/values exist. I would also suggest using sysopen instead of open, take this for example:

        sysopen(FILE, $file, O_WRONLY | O_CREAT);

    No need to worry about perl's length restrictions as sysopen will not overwrite a file. Also helps those silly race conditions that old perl versions have.. not really a CGI problem though. You can easily check what your perl limits filenames to by doing something like this:

        linux:~ # perl -e 'while(1){$n++;unless(-e "./" x $n){ die "perl sets limit at " . (--$n);}}'

    This will tell you the limit on the number of characters perl allows before it cannot open, unlink, check for existance, or any other simular file handling functions. I'd be interested in hearing if anyones is way off from 2050 ( or if this is a constant value. Also if anyone else can think of a way to abuse other perl limits, I have found a few.. but they seem too high to exploit or there is no situation where they would cause a problem.

    Of all the things I've lost, I miss my mind the most.
    perl -e "$q=$_;map({chr unpack qq;H*;,$_}split(q;;,q*H*));print;$q/$q;"

    Edited: ~Mon Jun 24 22:21:50 2002 (GMT),
    by Footpad: Adjusted formatting to address complaints from Mozilla users mentioned via CB.

      Well, he at least appears to be trying to use imaginary variables. If you change some of them around, you can eventually get a script that works (if you can call it that), you'll also have to run it from the 'accounts' directory, I didn't fix that:

      $FORM{'user'} = "cjf"; $FORM{'pass'} = "1234"; # why was the following line there? # if($FORM{'path'} =~ m/\0|\r|\n/ig){ die "illegal characters"; } #check for .htaccess file in /home/user/accounts/$FORM{path} $htaccess = "/home/cjf/accounts/$FORM{user}/.htaccess"; if (-e $htaccess){ open(HTACCESS, "<", $htaccess) or die "could not open .htaccess f +ile"; # added chomp chomp(@lines = <HTACCESS>); close(HTACCESS); ($correctuser,$correctpassword) = split(/:/,$lines[0]); if ($FORM{'user'} eq $correctuser && $FORM{'pass'} eq $correctpass +word){ print "access granted"; access(); } else { print "access denied"; } } else { mkdir($FORM{'user'},0755) or die "error accessing user directory" +unless (-d $FORM{user}); $accessfile = $FORM{'user'} . "/.htaccess"; # changed $useraccess to $accessfile # changed $username to $FORM{'user'} # changed $password to $FORM{'pass'} open(USERACCESS, ">", $accessfile) or die "could not create user f +ile"; print USERACCESS "$FORM{'user'}:$FORM{'pass'}"; close(USERACCESS); }

      Now I'm still not sure what he's saying about filename/variable limits in Perl and how they could result in a vulnerability. It certainly doesn't sound accurate. Can someone clarify this?

        Any time the system does something the programmer doesn't expect, you have potential problems.

        In this case the programmer is using apparently equivalent file names - one for testing existence of a file and one for creating it. They are not equivalent though because the filesystem limit means that one name is invalid and the other is a file that already exists. So the code thought it was creating a new file to represent a new permission - but instead was replacing an existing access file.

        So yes. The code presented makes the mistake described. But it would be a non-issue without a whole series of supporting mistakes - first and foremost of which is testing a different filename than you are creating!

        Oh, to answer your other question? The "following line" was there because disagreements between Perl and system calls on the meaning of a null byte can cause all sorts of fun. Also shell scripts being confused by returns can cause other fun and games. Those characters were therefore known to be dangerous, and therefore were eliminated.

      Those limits are very real, but have nothing to do with Perl. They are a function of your OS and filesystem.

      Of course not checking for directory traversal (../../..) is an even worse mistake. But bonus points for three arg open...

Re: Hacking CGI - security and exploitation
by meraxes (Friar) on Jun 24, 2002 at 19:10 UTC

    I didn't really see too too much that was new on that article that couldn't have been found here.

    Many of the vulnerabilities mentioned are things that should set off alarms in a programmers head in the first place. I can't imagine anyone actually providing a direct portal to files via a form. The SSI, VB and Javascript stuff was interesting, but I'd already read about that sort of thing here.

    There was a tone in the article that implied Perl was not suited for CGI as it was not written with the net in mind, but neither was much else. I felt like b0iler was placing the responsibility on the language as opposed to the programmer. I didn't like that.

    Every language has its vulnerabilities and good coding practice in any language is important. 'Twas a nifty little article and it had some valid points, but anyone who does anything in CGI should study the topic very closely before they use a script anyway.

      I can't imagine anyone actually providing a direct portal to files via a form.

      There have been two recent cases on this site where someone has linked to code they've inherited/written that has done this (and more). Luckily, in both cases they were very open to suggestions and took the code down immediately and went off to learn more about security.

      anyone who does anything in CGI should study the topic very closely before they use a script anyway.

      Should and do are two very different things. It's no secret that many people first come into contact with Perl by trying to write a script for their website. Saying "well you should have studied security" after the fact is of little use. The more that is written on the subject, and the more commonplace it becomes, the better.

        Fair enough. I guess it was a bit of a knee jerk reaction. I'm just not fond of those who blame the tool instead of the user (and to me that seemed to be what the author was doing). The presentation seemed a little cavalier to me.

        I'm mediocre at best (but improving, thanks perl monks) and tend to be very paranoid. However, it still seems horrifically lax not to look up these sorts of things (to me at least). I do mostly data munging so I'm hardly an expert.

        You are right though. Consider me properly chastised. :)

      I didn't really see too too much that was new on that article that couldn't have been found here.

      I agree. There is nothing really new but I've never seen before one paper which summaries several different vulnerabilities like this one. I like this article because it is good introduction for newbie programmers as it covers several topics at same time.

      Ilya Martynov (

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://176857]
Approved by chaoticset
Front-paged by cjf
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (5)
As of 2020-10-28 17:24 GMT
Find Nodes?
    Voting Booth?
    My favourite web site is:

    Results (262 votes). Check out past polls.