#!/usr/bin/perl # Girex Local/Remote File Inclusion Scanner 17/04/09 use LWP::UserAgent; my $lwp = new LWP::UserAgent; banner(); my $dirtoget = shift or die "usage: perl $0 \n"; get_php_funcs(); recurse( $dirtoget ); sub recurse() { my $path = shift; $path =~ tr/\\/\//; opendir(DIR, $path) or die "Cannot open directory: $path\n"; my @files = grep { !/^\.{1,2}$/ } readdir (DIR); @files = map { $path . '/' . $_ } @files; closedir(DIR); foreach $f (@files) { if(-d $f) { recurse( $f ); } elsif( -e $f and $f =~ /\.php$/) { scan_file( $f ); } } } sub scan_file() { my $i = 1, $php = 0; my $file = shift; my @def_vars = (); open(FILE, "<", $file) or die "Cannot open file: $file\n"; while(chomp(my $line = )) { $line = trim( $line ); next if $line =~ /^\/\//; # Check for comments if($line =~ /^\/\*/ and $line !~ /\*\/$/) { do { chomp($line = ); $i++; } while ($line !~ /\*\/$/ and $line) } if($php == 0) # Take only php code { if($line =~ /<\?(php)?(.*)\?>/) { $line = trim( $2 ); } elsif($line =~ /<\?(php)?(.*)/) { $line = trim( $2 ); $php = 1; } else { $i++; next; } } elsif($php == 1) { if($line =~ /(.*)\?>/) { $line = trim( $1 ); $php = 0; } } last if $line =~ /^(function|class)/; # Check for function or class definition last if $line =~ /die|exit\s*([(]?.*[)]?)\s*;/; # Check for die/exit push(@def_vars, $1) if $line =~ /\$(\w+)\s*=\s*.*/; # Saving defined vars if($line =~ /@?(\w+)\s*\(.*\)/) { my $func = $1; if($func !~ /^(if|else|elseif|while|for|switch)/) { last if not in_array(lc($func), @php_funcs); } } if($line =~ /^@?(include|require|eval)(_once)?\s*([(]?.*[)]?)\s*;/) # Check includes { if($3 =~ /\$(\w+)/) { print "\nLine: $i\nFile: $f\n$line\n\n" if not in_array($1, @def_vars); } last; } $i++; } close(FILE); } sub get_php_funcs() { our @php_funcs = (); my $res = $lwp->get('http://www.php.net/quickref.php'); if($res->is_error) { die("Cannot connect to php.net to retrieve function's list\n"); } my @php_lines = split("\n", $res->content); foreach $php_line (@php_lines) { if($php_line =~ /(\w+)<\/a>/) { push(@php_funcs, lc($1)); } } } sub banner() { print "\n". "-" x 50 ."\n\nGirex Local/Remote File Inclusion Scanner 17/04/09\n\n"."-" x 50 ."\n\n"; } sub in_array($, @) { my $find = shift; my @array = @_; foreach $x(@array) { return 1 if $find eq $x; } return 0; } sub trim() { my $string = shift; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string; }