#!/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. # # (c) Brian Reilly , 2005-2006 # # NiktoRAT is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # USAGE: # # Written for Nikto 1.35 reports; other versions may not work. # This WILL NOT work for CSV or HTML Nikto reports. # # Requires curl, HTML::Entities, and URI::Escape # # % ./niktorat.pl # # 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 \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 = ; chomp $bool; if ($bool =~ /^y$|^yes$/i) { mkpath ("$output_dir"); } } print "Reading file: $nikto_file\n"; while () { 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 = '' . $ip_and_host . ''; 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 < NiktoRAT You need a browser that supports frames. EOF close LASTFRAME; open (LASTFILE, ">$output_dir/nikrat-unparsed.html"); print LASTFILE < NiktoRAT Previous

The lines below from the Nikto report did not appear to contain vulnerability URLs. They should be reviewed manually.


EOF foreach (@nomatch) { chomp; print LASTFILE $_ . "

\n"; } print LASTFILE < EOF close LASTFILE; open (NIKFRAMENAV, ">$output_dir/nikframe-nav.html"); print NIKFRAMENAV < NiktoRAT

Report File Analyzed:
$ARGV[0]

Results Navigation:
All Files ($count)

By HTTP Response Code
EOF foreach $http_code (@http_codes) { &makeLastCodeFiles; print NIKFRAMENAV "$http_code ($counter{$http_code})
\n"; } print NIKFRAMENAV '
Jump to Results for Target Host
'; foreach (@host_indexes) { print NIKFRAMENAV "$_" . '
' . "\n"; } print NIKFRAMENAV <Unparsed Lines


Contact: niktorat\@gmail.com
EOF close NIKFRAMENAV; ##################### # SUBROUTINES ##################### sub makeFiles { $prevcount = $count - 1 ; $nextcount = $count + 1; if ( $count > 0 ) { $prev_url = "Previous" ; } 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 < NiktoRAT You need a browser that supports frames. EOF close MAIN; print TOPFRAME < NiktoRAT Browsing: All Files

URL: $html_esc_url
Vulnerability Summary: $vuln
$prev_url Next
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 = "Previous" ; } 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 < NiktoRAT Browsing: HTTP Response Code $http_code

URL: $prev_html_esc_url{$http_code}
Vulnerability Summary: $prev_vuln{$http_code}
$prev_code_url Next
EOF close PREVCODETOP; open (CODEMAIN, ">$output_dir/nikframe-$http_code-$prev_page{$http_code}.html") || die "File open error.\n"; print CODEMAIN < NiktoRAT You need a browser that supports frames. 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 < NiktoRAT Browsing: HTTP Response Code $http_code

URL: $prev_html_esc_url{$http_code}
Vulnerability Summary: $prev_vuln{$http_code}
Previous
EOF close PREVCODETOP; open (CODEMAIN, ">$output_dir/nikframe-$http_code-$prev_page{$http_code}.html") || die "File open error.\n"; print CODEMAIN < NiktoRAT You need a browser that supports frames. EOF close CODEMAIN; }