Monday, July 21, 2008

OSCON: Perl Security

This afternoon I'm breaking my no Perl rule and I'm sitting in "Perl Security" given by Paul Fenwick. I'm sitting next to Brad and Chris, and Sam is supposedly in here somewhere...


From the looks of things, Paul is trying to pull a Dick Hardt with his talk. If you've ever seen Dick's Identity 2.0 talk you'll know that this tutorial is going to be virtually un-bloggable...

Update: First pointer is to his own autodie module, which was released onto CPAN (very) late last night. It's a lexical equivalent of Fatal for Perl 5.10, it also upgrades the Fatal module to contain better diagnostics and reporting.

Update: Paul is talking about exposing vulnerabilities in CGI code, and trying to emphasize that you must validate your input data, from users, from files and very much from the network. You need to use taint mode. He's also recommending that you don't use "baby taint" mode and call Perl with -t...

You may not use data derived from outside your program to affect something else outside your program - at least, not by accident. - perlsec

Update: Interesting he's just shown a three line example that will allow you to get root access by running any Perl script that respects the PERL5LIB environment variable.

Update: But there are problems with taint mode

my ($url, $file) = @ARGV;
$url =~ m/ pattern match /;
my $safe_url - $1;
$file =~ / pattern match /;
my $safe_file = $1;
If the regular expression match for $safe_file fails then $safe_file is set to $safe_url and that could easily be set to something like http://foo&/bin/sh, which would be bad. You always need to check for success, either use an if( ) block or by explicitly check the return value from the regular expression.

Update: One of the things that Perl is good for is making tasks easy. One of those things is opening a file. There are lots of ways to open files in Perl, which means there are lots of way to break things. If you are opening a file you should always specify a mode, and never use the two argument version of open which does much deep magic. Use the three argument version instead.

open($fh, "<", $filename );
However this doesn't get you out of validating your input, you still need to do that...

Update: Symbolic links (are awesome but) can be used to do evil things. Don't use temporary files with predictable names, you could even use anonymous files

use autodie qw(open);
open($fh, "+>", undef );

or you could just use the Tim's File::Temp module instead...

Update: Now talking about system and back ticks, Paul really hates system. You really need to use the two argument version of system rather than the one argument version, except of course

@args = ();
system( $cmd, @args );

if @args is empty, then it calls the one argument version of system, which in turn calls the shell rather than executes the passed command directly. Which means that you can this happens,

system ( "finger $username; rm -rf *", ( ) );

which is rather bad.

Back ticks are worse; "this" is a string, 'this' is a string and `this` is executing arbitrary code on your system. Depending on your font, it's rather hard to tell the difference.

The alternative is IPC::System::Simple, which works all the way back to Pelr 5.6 and (magically) doesn't have any dependencies. Which from the sounds of it goes a long way to fixing a lot of the problems with system. It also provides capture which replaces back ticks.

Update: We're breaking for afternoon coffee...

Update: ...and we're back and talking about setuid and setgid programs. Apparently Perl is ignorant of the saved uid, which means that it's really hard to drop privileges and make it stick. Also a dark secret, Perl's $< and $> variables are cached. Ouch!

Update: On to database security and injection attacks. He's advising us not to do our own quoting and use instead use place holders. As I've mentioned before, I rarely have to do heavy weight database work, and I'd view my knowledge of DBI as only fairly sparse, and even I know about place holders. Why does everyone think they're worth talking about at length. Bemusing!

Update: On to tricks and tips... and the poisoned null byte. Strings in Perl (are awesome but) can contain any character you want, including control codes and null bytes. In Perl a null byte is just another character, but in C it represents the end of a string. So if you can get a null byte down to the C layer, bad things can happen, and it's easy to pass a null byte can be easily passed in URLs.

Update: ...and we're done (with the main material) about an hour ahead of time. The course notes, although not the slides, for the tutorial are available online. On to the 'bonus' material, random numbers and cryptography...

Update: ...we're done. Now go read Brad's and Chris' posts on the Perl Security tutorial as well.