Section 8.6. Complete Source Code


8.6. Complete Source Code

The rest of this chapter contains the complete source code for the two scripts developed and outlined in this chapter.

8.6.1. simpleScanner.pl

Example 8-8 shows the full source code for the simpleScanner.pl script.

Example 8-8. Code for simpleScanner.pl
#!/usr/bin/perl use LWP::UserAgent; use strict; use Getopt::Std; my %args; getopts('c:o:v', \%args);   printReport("\n** Simple Web Application Scanner **\n"); if ($#ARGV < 1) {   die "\n$0 [-o <file>] [-c <cookie data>] [-v] inputfile  http://hostname\n\n-c: Use HTTP Cookie\n-o: Output File\n-v: Be Verbose\n";  } # Open input file open(IN, "< $ARGV[0]") or die"ERROR => Can't open file $ARGV[0].\n";   my @requestArray = <IN>; my ($oRequest,$oResponse, $oStatus, %dirLog, %paramLog); printReport("\n** Beginning Scan **\n\n"); # Loop through each of the input file requests foreach $oRequest (@requestArray) {  # Remove line breaks and carriage returns  $oRequest =~ s/(\n|\r)//g;  # Only process GETs and POSTs  if ($oRequest =~ /^(GET|POST)/) {   # Check for request data   if ($oRequest =~ /\?/) {      # Issue the original request for reference purposes      ($oStatus, $oResponse) = makeRequest($oRequest);       #Populate methodAndFile and reqData variables    my ($methodAndFile, $reqData) = split(/\?/, $oRequest, 2);    my @reqParams = split(/\&/, $reqData);       my $pLogEntry = $methodAndFile;       # Build parameter log entry    my $parameter;    foreach $parameter (@reqParams) {     my ($pName) = split("=", $parameter);     $pLogEntry .= "+".$pName;    }    $paramLog{$pLogEntry}++;    if ($paramLog{$pLogEntry} eq 1) {        # Loop to perform test on each parameter     for (my $i = 0; $i <= $#reqParams; $i++) {          my $testData;          # Loop to reassemble the request parameters      for (my $j = 0; $j <= $#reqParams; $j++) {         if ($j == $i) {        my ($varName, $varValue) = split("=",$reqParams[$j],2);        $testData .= $varName."="."---PLACEHOLDER---"."&";        } else {        $testData .= $reqParams[$j]."&";       }      }      chop($testData);      my $paramRequest = $methodAndFile."?".$testData;      ## Perform input validation tests      my $sqlVuln = sqlTest($paramRequest);      my $xssVuln = xssTest($paramRequest);     } # End of loop for each request parameter    } # End if statement for unique parameter combos   } # Close if statement checking for request data       my $trash;   ($trash, $oRequest, $trash) = split(/\ |\?/, $oRequest);   my @directories = split(/\//, $oRequest);   my @checkSlash = split(//, $oRequest);   my $totalDirs = $#directories;   # Start looping through each directory level   for (my $d = 0; $d <= $totalDirs; $d++) {    if ((($checkSlash[(-1)] ne "/") && ($d == 0)) || ($d != 0)) {     pop(@directories);    }    my $dirRequest = "GET ".join("/", @directories)."\/";       # Add directory log entry    $dirLog{$dirRequest}++;    if ($dirLog{$dirRequest} eq 1) {     my $dListVuln = dirList($dirRequest);     my $dPutVuln = dirPut($dirRequest);    } # End check for unique directory   } # End loop for each directory level  } # End check for GET or POST request } # End loop on each input file entry printReport("\n\n** Scan Complete **\n\n"); sub dirPut {  my ($putRequest, $putStatus, $putResults, $putVulnerable);  ($putRequest) = @_;  # Format the test request to upload the file  $putRequest =~ s/^GET/PUT/;  $putRequest .= "uploadTest.txt?ThisIsATest";  # Make the request and get the response data  ($putStatus, $putResults) = makeRequest($putRequest);  # Format the request to check for the new file  $putRequest =~ s/^PUT/GET/;  $putRequest =~ s/\?ThisIsATest//;  # Check for the uploaded file  ($putStatus, $putResults) = makeRequest($putRequest);  if ($putResults =~ /ThisIsATest/) {   $putVulnerable = 1;  # If vulnerable, print something to the user   printReport("\n\nALERT: Writeable Directory Detected:\n=> $putRequest\n\n");  } else {   $putVulnerable = 0;  }  # Return the test results.  return $putVulnerable; } sub dirList {  my ($dirRequest, $dirStatus, $dirResults, $dirVulnerable);  ($dirRequest) = @_;  # Make the request and get the response data  ($dirStatus, $dirResults) = makeRequest($dirRequest);  # Check to see if it looks like a listing  if ($dirResults =~ /(<TITLE>Index of \/|(<h1>|<title>)Directory Listing For|<title>Directory of|\"\?N=D\"|\"\?S=A\"|\"\?M=A\"|\"\?D=A\"| - \/<\/title>|&lt;dir&gt;| - \/<\/H1><hr>|\[To Parent Directory\])/i) {   $dirVulnerable = 1;   # If vulnerable, print something to the user   printReport("\n\nALERT: Directory Listing Detected:\n=> $dirRequest\n\n");  } else {   $dirVulnerable = 0;  }  # Return the test results.  return $dirVulnerable; } sub xssTest {  my ($xssRequest, $xssStatus, $xssResults, $xssVulnerable);  ($xssRequest) = @_;  # Replace the "---PLACEHOLDER---" string with our test string  $xssRequest =~ s/---PLACEHOLDER---/"><script>alert('Vulnerable');<\/script>/;  # Make the request and get the response data  ($xssStatus, $xssResults) = makeRequest($xssRequest);  # Check to see if the output matches our vulnerability signature.  if ($xssResults =~ /"><script>alert\('Vulnerable'\);<\/script>/i) {   $xssVulnerable = 1;   # If vulnerable, print something to the user   printReport("\n\nALERT: Cross-Site Scripting Vulnerability Detected:\n=> $xssRequest\n\n");  } else {   $xssVulnerable = 0;  }  # Return the test results  return $xssVulnerable; } sub sqlTest {  my ($sqlRequest, $sqlStatus, $sqlResults, $sqlVulnerable);  ($sqlRequest) = @_;  # Replace the "---PLACEHOLDER---" string with our test string  $sqlRequest =~ s/---PLACEHOLDER---/te'st/;  # Make the request and get the response data  ($sqlStatus, $sqlResults) = makeRequest($sqlRequest);  # Check to see if the output matches our vulnerability signature.  my $sqlRegEx = qr /(OLE DB|SQL Server|Incorrect Syntax|ODBC Driver|ORA-|SQL command  not|Oracle Error Code|CFQUERY|MySQL|Sybase| DB2 |Pervasive|Microsoft Access|MySQL| CLI Driver|The string constant beginning with|does not have an ending string  delimiter|JET Database Engine error)/i;  if (($sqlResults =~ $sqlRegEx) && ($oResponse !~ $sqlRegEx)) {   $sqlVulnerable = 1;   printReport("\n\nALERT: Database Error Message Detected:\n=>   $sqlRequest\n\n");  } else {   $sqlVulnerable = 0;  }  # Return the test result indicator  return $sqlVulnerable; } sub makeRequest {  my ($request, $lwp, $method, $uri, $data, $req, $status, $content);      ($request)=@_;  if ($args{v}) {   printReport("Making Request: $request\n");  } else {   print ".";  }  # Setup LWP UserAgent  $lwp = LWP::UserAgent->new(env_proxy => 1,               keep_alive => 1,               timeout => 30,               );  # Method should always precede the request with a space  ($method, $uri) = split(/ /, $request);  # PUTS and POSTS should have data appended to the request  if (($method eq "POST") || ($method eq "PUT")) {   ($uri, $data) = split(/\?/, $uri);  }  # Append the URI to the hostname and setup the request  $req = new HTTP::Request $method => $ARGV[1].$uri;  # Add request content for POST and PUTS   if ($data) {   $req->content_type('application/x-www-form-urlencoded');   $req->content($data);  }  # If cookies are defined, add a COOKIE header  if ($args{c}) {   $req->header(Cookie => $args{c});  }  my $response = $lwp->request($req);  # Extract the HTTP status code and HTML content from the response  $status = $response->status_line;  $content = $response->content;  if ($status =~ /^400/) {   die "Error: Invalid URL or HostName\n\n";  }  return ($status, $content); } sub printReport {  my ($printData) = @_;  if ($args{o}) {    open(REPORT, ">>$args{o}") or die "ERROR => Can't write to file $args{o}\n";   print REPORT $printData;   close(REPORT);  }  print $printData; }

8.6.2. parseLog.pl

Example 8-9 contains the full source for the parseLog.pl script.

Example 8-9. Code for parseLog.pl
#!/usr/bin/perl use strict; if ($#ARGV < 0) {   die "Usage: $0 LogFile\n";  } open(IN, "< $ARGV[0]") or die"ERROR: Can't open file $ARGV[0].\n";   # Change the input record separator to select entire log entries $/ = "=" x 54;  my @logData = <IN>; # Loop through each request and parse it my ($request,$logEntry, @requests); foreach $logEntry (@logData) {  # Create an array containing each line of the raw request  my @logEntryLines = split(/\n/, $logEntry);  # Create an array containing each element of the first request line  my @requestElements = split(/ /, $logEntryLines[1]);    # Only parse GET and POST requests  if ($requestElements[0] eq "GET" || $requestElements[0] eq "POST" ) {   if ($requestElements[0] eq "GET" ) {    print $requestElements[0]." ".$requestElements[1]."\n";   }   # POST request data is appended after the question mark   if ($requestElements[0] eq "POST" ) {    print $requestElements[0]." ".$requestElements[1]."?".$logEntryLines[-2]."\n";   }  } # End check for GET or POST } # End loop for input file entries



Network Security Tools
Network Security Tools: Writing, Hacking, and Modifying Security Tools
ISBN: 0596007949
EAN: 2147483647
Year: 2006
Pages: 110

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net