Article Figure 1 Listing 1 aug2006.tar

Listing 1 NiktoRAT

#!/usr/bin/perl
#
# NiktoRAT -- Nikto Results Analysis Tool
#
# This script will process a text Nikto results file 
# and generate a series of navigable web pages that 
# contain an HTML dump of the vulnerability URL, the HTTP
# request and response headers, and data for each finding.  
#
# Written for Nikto 1.35 reports.  Other versions may not work.
# This WILL NOT work for CSV or HTML Nikto reports.
#
# Usage:  ./niktorat.pl <nikto-report.txt> <output-directory>
#
# Brian Reilly <niktorat@gmail.com>
#
# Version 1.0, Initial Release
#

use Tie::File;
use File::Path;
use HTML::Entities;
use URI::Escape;

# Change the following as appropriate
$CURL_BIN = '/usr/bin/curl';
$CURL_ARGS = '-k -g'; # allow insecure SSL connections, disable URL globbing

###############################################################

$count = 0;
$foundurl = 0;

select (STDOUT);
$|  = 1 ; #Unbuffer STDOUT

#Make sure we have the right number of arguments
if ($#ARGV != 1) { die "Usage:  $0 <text-nikto-report-file> \
  <output-directory>\n\n" } 

print "\n************\n* NiktoRAT *\n************\n\n";
#Make sure we can run curl
if (! -x $CURL_BIN) { die "Cannot execute curl \
  binary: $CURL_BIN\nExiting.\n\n"; 
} 

$nikto_file = $ARGV[0];
$output_dir = $ARGV[1];

open (FH, "$nikto_file") || die \
  "ERROR:  Cannot open file $nikto_file\nExiting.\n\n";

if (! -d $output_dir) { 
  print "Directory $output_dir doesn't exist.  Would you like to \
    create it (y/n)? ";
  $bool = <STDIN>;
  chomp $bool;
  if ($bool =~ /^y$|^yes$/i) { mkpath ("$output_dir"); } 
} 

print "Reading file: $nikto_file\n";

while (<FH>) {
  chomp $_;
  if ($_ =~ /^\+ Target IP:\s+\d+/) {
     ($ip) = ($_ =~ /^\+ Target IP:\s+([^ ]*)/);
     print "\nIP Address Found: $ip\n";
     $foundurl = 0;
     $hostname = "";
     $port = "";
     $ssl = 0;
     push (@nomatch,$_);
   }
  elsif ($_ =~ /^\+ Target Hostname:\s+/) {
     ($hostname) = ($_ =~/^\+ Target Hostname:\s+([^ ]*)/);
     print "Hostname Found: $hostname\n";
     push (@nomatch,$_);
  }
  elsif ($_ =~ /^\+ Target Port:\s+\d+/) {
    ($port) = ($_ =~/\+ Target Port:\s+([^ ]*)/);
     print "Port Found:  $port\n";
     push (@nomatch,$_);
  }
  elsif ($_ =~/^\+ SSL Info:\s+/) {
    $ssl = 1;
    print "SSL Info Found\n";
    push (@nomatch,$_);
}
  # make sure we have an ip address, port, and hostname before
  # parsing the URL
  elsif ( $ip && $hostname && $port && $_ =~ /^\+ \//) {
      if ( $foundurl ) { 
          print '.' } else {
          $ip_and_host = "$ip:$port ($hostname:$port)";
          $host_index_url = '<a href="nikframe-' . $count . '.html" \
            target="_top">' . $ip_and_host . '</a>';
      push (@host_indexes, $host_index_url);
          print "Processing URLs."; 
          $foundurl++;
      } 
      $_ =~ (s/^\+ //);
     ($vulnpath, $vuln) = split (/\s+/,$_,2);
     $esc_vulnpath = $vulnpath;
     $esc_vulnpath =~ s/([^A-Za-z0-9])/\\$1/g;
     $uri_esc_vulnpath = uri_escape($vulnpath,"^A-Za-z0-9\-_.!*'~?()=&/");
     $html_esc_vulnpath = encode_entities($vulnpath);
     if ($ssl) { $protocol = "https://"; } else { $protocol = "http://";} 
     if (! $ssl && $port == 80) { $urlport = "" } 
      elsif ($ssl && $port == 443) { $urlport = "" } 
       else { $urlport = ":$port" } 
     $baseurl_ip = $protocol . $ip . $urlport;
     $url = $baseurl_ip . $vulnpath ;
     $esc_url = $baseurl_ip .  $esc_vulnpath ;
     $uri_esc_url = $baseurl_ip . $uri_esc_vulnpath ;
     $html_esc_url = $baseurl_ip . $html_esc_vulnpath ;
     &makeFiles;
     $count++;
     if ($hostname ne $ip) {  
        $baseurl_hn = $protocol . $hostname . $urlport;
        $url = $baseurl_hn . $vulnpath ;
        $esc_url = $baseurl_hn . $esc_vulnpath ;
        $uri_esc_url = $baseurl_hn . $uri_esc_vulnpath ;
        $html_esc_url = $baseurl_hn . $html_esc_vulnpath ;
        &makeFiles;
        $count++;
     }
  }
  else  { push(@nomatch, $_); } 
}

print "\n\nDone parsing file. \
  Results begin here: $ARGV[1]/nikframe-0.html\n\n";
close FH;

$prevcount = $count - 1 ;

open (LASTFRAME, ">$output_dir/nikframe-$count.html");

print LASTFRAME <<EOF;
<html>
<head><title>NiktoRAT</title></head>
<frameset cols="20%,80%">
<frame src="nikframe-nav.html">
<frame src="nikrat-unparsed.html">
</frameset>
</frameset>
<noframes>
You need a browser that supports frames.
</noframes>
</html>
EOF

close LASTFRAME;

open (LASTFILE, ">$output_dir/nikrat-unparsed.html");

print LASTFILE <<EOF;
<html>
<head><title>NiktoRAT</title></head>
<body>
<a href="nikframe-$prevcount.html" target="_top">Previous</a>
<br><br>
<b>The lines below from the Nikto report did not appear to contain \
  vulnerability 
URLs.  They should be reviewed manually.</b>
<br><hr>
<br>

EOF

foreach (@nomatch) { 
    chomp;
    print LASTFILE $_ . "<br><br>\n";
}

print LASTFILE <<EOF;
</body>
</html>
EOF

close LASTFILE;

open (NIKFRAMENAV, ">$output_dir/nikframe-nav.html");

print NIKFRAMENAV <<EOF;
<html>
<head></head>
<body>
<b>NiktoRAT</b>
<br><br>
<b>Report File Analyzed:</b>
<br>
$ARGV[0]
<br><br>
<b>Results Navigation:</b>
<br>
<i><a href="nikframe-0.html" target="_top">All Files ($count)</a></i><br>
<br><i>By HTTP Response Code</i><br>
EOF

foreach $http_code (@http_codes) {
  &makeLastCodeFiles;
  print NIKFRAMENAV "<a href=\"nikframe-$http_code-$first{$http_code}.html\" \
    target=\"_top\">$http_code ($counter{$http_code})</a><br>\n";
}

print NIKFRAMENAV '<br><i>Jump to Results for Target Host</i><br>';

foreach (@host_indexes) { 
  print NIKFRAMENAV "$_" . '<br>' . "\n";
}

print NIKFRAMENAV <<EOF;
<br><i><a href="nikframe-$count.html" target="_top">Unparsed 
Lines</a></i>
<br>
<br>
<br>
<b>Contact:</b> <a href="mailto:niktorat\@gmail.com">niktorat\@gmail.com</a>
<br>
</body>
</html>

EOF

close NIKFRAMENAV;

#####################
# SUBROUTINES
#####################


sub makeFiles {

$prevcount = $count - 1 ;
$nextcount = $count + 1;

if ( $count > 0 ) { 
  $prev_url = "<a href=\"nikframe-$prevcount.html\" \
    target=\"_top\">Previous</a>" ; 
   } else  { 
  $prev_url="";
}


open (MAIN, ">$output_dir/nikframe-$count.html") || die "File open error.\n";
open (TOPFRAME, ">$output_dir/nikframe-top-$count.html") || die \
  "File open error\n";

print MAIN <<EOF;
<html>
<head><title>NiktoRAT</title></head>
<frameset cols="20%,80%">
<frame src="nikframe-nav.html">
<frameset rows="*,*,2*">
<frame src="nikframe-top-$count.html">
<frame src="nikframe-headers-$count.txt">
<frame src="nikframe-bottom-$count.html">
</frameset>
</frameset>
<noframes>
You need a browser that supports frames.
</noframes>
</html>
EOF

close MAIN;

print TOPFRAME <<EOF;
<html>
<head><title>NiktoRAT</title></head>
<body>
<b>Browsing:  All Files</b>
<br><br>
<b>URL:</b> <a href="$uri_esc_url" target="_top">$html_esc_url</a>
<br>
<b>Vulnerability Summary:</b> $vuln
<br>
$prev_url <a href="nikframe-$nextcount.html" target="_top">Next</a>
<br>
</body>
</html>
EOF

close TOPFRAME;

($curl_output) = `$CURL_BIN $CURL_ARGS -s -D \
  $output_dir/nikframe-headers-$count.txt -o \
  $output_dir/nikframe-bottom-$count.html -w "%{http_code} \
  %{url_effective}" $esc_url`;

($http_code, $curl_get) = split (/\s+/,$curl_output,2);

tie @headers_file , "Tie::File", \
  "$output_dir/nikframe-headers-$count.txt" || die \
  "ERROR:  Cannot tie file \
  $output_dir/nikframe-headers-$count.txt\nExitting.\n\n";

splice @headers_file, 0, 0, "HTTP REQUEST:", "$curl_get", "", "HTTP RESPONSE:";

if ( $counter{$http_code} > 1 ) {
  $prev_code_url = \
    "<a href=\"nikframe-$http_code-$old_prev_page{$http_code}.html\" \
    target=\"_top\">Previous</a>" ;
   } else  {
  $prev_code_url="";
}

if ( $counter{$http_code} > 0 )  { 
open (PREVCODETOP, \
  ">$output_dir/nikframe-top-$http_code-$prev_page{$http_code}.html") \
  || die "File open error.\n";

print PREVCODETOP <<EOF;
<html>
<head><title>NiktoRAT</title></head>
<body>
<b>Browsing:  HTTP Response Code $http_code</b>
<br><br>
<b>URL:</b> <a href="$prev_uri_esc_url{$http_code}" \
  target="_top">$prev_html_esc_url{$http_code}</a>
<br>
<b>Vulnerability Summary:</b> $prev_vuln{$http_code}
<br>
$prev_code_url <a href="nikframe-$http_code-$count.html" \
  target="_top">Next</a>
<br>
</body>
</html>
EOF

close PREVCODETOP;

open (CODEMAIN, ">$output_dir/nikframe-$http_code-$prev_page{$http_code}.html") \
  || die "File open error.\n";

print CODEMAIN <<EOF;
<html>
<head><title>NiktoRAT</title></head>
<frameset cols="20%,80%">
<frame src="nikframe-nav.html">
<frameset rows="*,*,2*">
<frame src="nikframe-top-$http_code-$prev_page{$http_code}.html">
<frame src="nikframe-headers-$prev_page{$http_code}.txt">
<frame src="nikframe-bottom-$prev_page{$http_code}.html">
</frameset>
</frameset>
<noframes>
You need a browser that supports frames.
</noframes>
</html>
EOF

close CODEMAIN;

}

if (! $counter{$http_code} ) {
   push (@http_codes, $http_code);
   $first{$http_code} = $count;
}
$old_prev_page{$http_code} = $prev_page{$http_code};
$prev_vuln{$http_code} = $vuln;
$prev_uri_esc_url{$http_code} = $uri_esc_url;
$prev_html_esc_url{$http_code} = $html_esc_url;
$prev_page{$http_code} = $count;
$counter{$http_code}++;

}



sub makeLastCodeFiles { 

open (PREVCODETOP, \
  ">$output_dir/nikframe-top-$http_code-$prev_page{$http_code}.html") \
  || die "File open error.\n";

print PREVCODETOP <<EOF;
<html>
<head><title>NiktoRAT</title></head>
<body>
<b>Browsing:  HTTP Response Code $http_code</b>
<br><br>
<b>URL:</b> <a href="$prev_uri_esc_url{$http_code}" \
  target="_top">$prev_html_esc_url{$http_code}</a>
<br>
<b>Vulnerability Summary:</b> $prev_vuln{$http_code}
<br>
<a href="nikframe-$http_code-$old_prev_page{$http_code}.html" \
  target="_top">Previous</a>
<br>
</body>
</html>
EOF

close PREVCODETOP;

open (CODEMAIN, \
  ">$output_dir/nikframe-$http_code-$prev_page{$http_code}.html") \
  || die "File open error.\n";

print CODEMAIN <<EOF;
<html>
<head><title>NiktoRAT</title></head>
<frameset cols="20%,80%">
<frame src="nikframe-nav.html">
<frameset rows="*,*,2*">
<frame src="nikframe-top-$http_code-$prev_page{$http_code}.html">
<frame src="nikframe-headers-$prev_page{$http_code}.txt">
<frame src="nikframe-bottom-$prev_page{$http_code}.html">
</frameset>
</frameset>
<noframes>
You need a browser that supports frames.
</noframes>
</html>
EOF

close CODEMAIN;

}