http://qs321.pair.com?node_id=176957


in reply to Hacking CGI - security and exploitation

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 (b0iler@hotmail.com) 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.

 
______crazyinsomniac_____________________________
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.