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;
}
|