1#VERSION,2.00 2############################################################################### 3# Copyright (C) 2013 CIRT, Inc. 4# 5# This program is free software; you can redistribute it and/or 6# modify it under the terms of the GNU General Public License 7# as published by the Free Software Foundation; version 2 8# of the License only. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program; if not, write to 17# Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18############################################################################### 19# PURPOSE: 20# SQL Reporting 21# Sample table create (mysql): 22# create table nikto_table (testid varchar(6) not null, ip varchar(15), 23# hostname text, port int(5), usessl tinyint(1), osvdb int, httpmethod text, 24# uri text, message text, request blob, response blob); 25############################################################################### 26sub nikto_report_sqlg_init { 27 my $id = { name => "report_sqlg", 28 full_name => "Generic SQL reports", 29 author => "Sullo", 30 description => "Produces SQL inserts into a generic database.", 31 report_head => \&sqlg_open, 32 report_host_start => \&sqlg_host_start, 33 report_item => \&sqlg_item, 34 report_format => 'sql', 35 copyright => "2013 CIRT Inc." 36 }; 37 return $id; 38} 39 40############################################################################### 41# open output file 42sub sqlg_open { 43 my ($file) = @_; 44 45 # Open file and produce header 46 open(OUT, ">>$file") || die print STDERR "+ ERROR: Unable to open '$file' for write: $@\n"; 47 48 # Write header 49 my $opt = $CLI{'all_options'}; 50 $opt =~ s/'/\\'/g; 51 print OUT "# $VARIABLES{'name'} - v$VARIABLES{'version'}/$VARIABLES{'core_version'}\n"; 52 print OUT "# Options: $opt\n"; 53 print OUT "# Start Time: " . localtime($COUNTERS{'scan_start'}) . "\n"; 54 print OUT "# End Time: " . localtime($COUNTERS{'scan_end'}) . "\n"; 55 print OUT "\n"; 56 57 return OUT; 58} 59 60############################################################################### 61# start output 62sub sqlg_host_start { 63 my ($handle, $mark) = @_; 64 my $banner = $mark->{'banner'}; 65 $banner =~ s/"/\\'/g; 66 my $ssl=0; 67 if (defined $mark->{'ssl_cipher'}) { $ssl=1; } 68 my $hostname = $mark->{'hostname'}; 69 if ($mark->{'vhost'} ne '') { $hostname=$mark->{'hostname'}; } 70 my $sql="insert into nikto_table (testid, ip, hostname, port, usessl, osvdb, httpmethod, uri, message) values("; 71 $sql .= "'999958','$mark->{'ip'}','$hostname','$mark->{'port'}','$ssl','0','GET','/','$banner');\n"; 72 print $handle $sql; 73 74 if (defined $mark->{'ssl_cipher'}) { 75 my $ciphers = $mark->{'ssl_cipher'}; 76 my $issuer = $mark->{'ssl_cert_issuer'}; 77 my $subj = $mark->{'ssl_cert_subject'}; 78 my $alt = $mark->{'ssl_cert_altnames'}; 79 $ciphers =~ s/'/\\'/g; 80 $issuer =~ s/'/\\'/g; 81 $subj =~ s/'/\\'/g; 82 $alt =~ s/'/\\'/g; 83 print OUT "# SSL Ciphers: $ciphers\n"; 84 print OUT "# SSL Altnames: $alt\n"; 85 print OUT "# SSL Issuer: $issuer\n"; 86 print OUT "# SSL Info: $subj\n"; 87 } 88 89 return; 90} 91 92############################################################################### 93# print an item 94sub sqlg_item { 95 my ($handle, $mark, $item) = @_; 96 foreach my $uri (split(' ', $item->{'uri'})) { 97 my $hostname = quotemeta($item->{'mark'}->{'hostname'}); 98 my $httpmethod = quotemeta($item->{'method'}); 99 my $msg = quotemeta($item->{'message'}); 100 my $root = quotemeta($mark->{'root'}); 101 my $rootq = quotemeta($mark->{'root'}); # temporary, just for regex 102 $uri = quotemeta($uri); 103 if ($item->{'mark'}->{'vhost'} ne '') { $hostname=$item->{'mark'}->{'vhost'}; } 104 my $ssl = $mark->{'ssl_cipher'} ? 1 : 0; 105 106 my $sql="insert into nikto_table (testid, ip, hostname, port, usessl, osvdb, httpmethod, uri, message, request, response) values("; 107 $sql .= "'$item->{'nikto_id'}','$item->{'mark'}->{'ip'}','$hostname','$item->{'mark'}->{'port'}','$ssl',"; 108 $sql .= "'$item->{'osvdb'}','$httpmethod',"; 109 110 if (($uri ne '') && ($root ne '') && ($uri !~ /^$rootq/)) { 111 $sql .= "'" . $root . $uri . "',"; } 112 else { 113 $sql .= "'$uri',"; 114 } 115 116 $msg =~ s/^$uri:\s//; 117 $msg =~ s/^$rootq$uri:\s//; 118 $sql .= "'$msg',"; 119 120 # Rebuild the request from the hash -- no need to escape as it's base64 encoded 121 my $req = $$item{'request'}; 122 if ($req->{'whisker'}{'method'} eq '') { 123 $sql .= "'',"; 124 } 125 else { 126 my $rstring = $req->{'whisker'}{'method'} . " " 127 . $req->{'whisker'}{'uri'} . " " 128 . $req->{'whisker'}{'protocol'} . "/" 129 . $req->{'whisker'}{'version'} . "\n"; 130 131 foreach my $header (keys %{$req}) { 132 next if $header eq 'whisker'; 133 $rstring .= $header . ": " . $req->{$header} . "\n"; 134 } 135 $sql .= "'" . LW2::encode_base64($rstring,'') . "',"; 136 } 137 138 # response content 139 my $response = $$item{'response'}; 140 $rstring=''; 141 if ($response->{'whisker'}{'protocol'} ne '') { 142 $rstring = $response->{'whisker'}{'protocol'} . "/" 143 . $response->{'whisker'}{'version'} . " " 144 . $response->{'whisker'}{'code'} . " " 145 . $response->{'whisker'}{'message'} . "\n"; 146 foreach my $header (@{ $response->{'whisker'}{'header_order'} }) { 147 $rstring .= $header . ": " . $response->{$header} . "\n"; 148 } 149 $rstring .= "\n" . $response->{'whisker'}{'data'} . "\n"; 150 } 151 152 $sql .= "'" . LW2::encode_base64($rstring,'') . "');"; 153 print $handle "$sql\n"; 154 } 155} 156 1571; 158