📄 nikto_core.plugin
字号:
#VERSION,1.19#LASTMOD,10.27.2003# Nikto "core" functions# This software is distributed under the terms of the GPL, which should have been received# with a copy of this software in the "LICENSE.txt" file.# --------------------------------------------------------------------## Functions ## --------------------------------------------------------------------#sub test_target{ dump_result_hash(); # this is the actual the looped code for all the checks for (my $CHECKID=1;$CHECKID<=$ITEMCOUNT;$CHECKID++) { (my $RES, $CONTENT) = fetch($FILES{$CHECKID},$METHD{$CHECKID},$DATAS{$CHECKID}); nprint("- $RES for $METHD{$CHECKID}:\t$request{whisker}{uri}","v"); # this is a kluge unti the DB is restructured for more conditional tests my @rcodes = split(/\!/,$RESPS{$CHECKID}); $RESPS{$CHECKID} = $rcodes[0]; # this will also have to change once we allow regex's in the DB $RESPS{$CHECKID} =~ s/([^a-zA-Z0-9\s])/\\$1/g; # do auth/redir first, independent of test pass/fail if (($RES eq 401) && !($NIKTO{suppressauth})) { my $R=$result{'www-authenticate'}; $R =~ s/^basic //i; $R =~ s/realm=//i; nprint("+ $FILES{$CHECKID} - Needs Auth: (realm $R)"); } elsif ($RES eq 302) { nprint("+ $FILES{$CHECKID} - Redirects to " . $result{'location'} ." , $INFOS{$CHECKID}") unless !$OKTRAP; $NIKTO{totalmoved}++; } if ($RESPS{$CHECKID} =~ /[^0-9]/) # response has text to match { if ($CONTENT =~ /$RESPS{$CHECKID}/) # test passed { if (($rcodes[1] eq "") || ($CONTENT !~ /$rcodes[1]/)) # conditional passed or is blank { $VULS++; nprint("+ $request{whisker}{uri} - $INFOS{$CHECKID} ($METHD{$CHECKID})"); $NIKTO{totalokay}++; } } } elsif (($RES eq $RESPS{$CHECKID}) || ((($RES eq $TARGETS{$CURRENT_HOST_ID}{ports}{$CURRENT_PORT}{found}) || ($RES eq 200)) && ($RES !~ /$TARGETS{$CURRENT_HOST_ID}{ports}{$CURRENT_PORT}{notfound}/i)) ) { if (($rcodes[1] eq "") || ($CONTENT !~ /$rcodes[1]/)) # conditional passed or is blank { $VULS++; nprint("+ $request{whisker}{uri} - $INFOS{$CHECKID} ($METHD{$CHECKID})"); $NIKTO{totalokay}++; } } # verify we're not getting bogus 200/302 messages bogus_responses(); # end check loop if ($CLI{pause} > 0) { sleep $CLI{pause}; } }# print any cookies foundif ($CLI{cookies}){ foreach my $cookie (@COOKIES) { $cookie =~ s/\n/ /g; my @C=split(/--=--/,$cookie); nprint("+ Got Cookie on file '$C[0]' - value '$C[1]'"); }} # do this again, at the end so it's obvious. reset OKTRAP. $OKTRAP=1; bogus_responses(); nprint("+ $ITEMCOUNT items checked - $VULS item(s) found on remote host(s)"); $TARGETS{$CURRENT_HOST_ID}{ports}{$CURRENT_PORT}{end_time} = time(); my $diff = $TARGETS{$CURRENT_HOST_ID}{ports}{$CURRENT_PORT}{end_time} - $TARGETS{$CURRENT_HOST_ID}{ports}{$CURRENT_PORT}{start_time}; my $end = localtime($TARGETS{$CURRENT_HOST_ID}{ports}{$CURRENT_PORT}{end_time}); nprint("+ End Time: $end ($diff seconds)"); nprint($DIV); return;}#################################################################################sub bogus_responses{ if ($OKTRAP) { if ($NIKTO{totalokay} > $CONFIG{MAX_WARN}) { $OKTRAP=0; nprint("\n+ Over 30 \"OK\" messages, this may be a by-product of the + server answering all requests with a \"200 OK\" message. You should + manually verify your results."); } elsif ($NIKTO{totalmoved} > $CONFIG{MAX_WARN}) { $OKTRAP=0; nprint("\n+ Over 30 \"Moved\" messages, this may be a by-product of the + server answering all requests with a \"302\" Moved message. You should + manually verify your results."); } }}#################################################################################sub dump_target_info{ # print out initial connection junk my $SSLPRINT=""; $TARGETS{$CURRENT_HOST_ID}{ports}{$CURRENT_PORT}{start_time}=time(); my $start=localtime($TARGETS{$CURRENT_HOST_ID}{ports}{$CURRENT_PORT}{start_time}); if ($TARGETS{$CURRENT_HOST_ID}{ports}{$CURRENT_PORT}{ssl}) { my $SSLCIPHERS=$result{whisker}{ssl_cipher} || "Enabled"; my $SSLISSUERS=$result{whisker}{ssl_cert_issuer} || "Unknown"; my $SSLINFO=$result{whisker}{ssl_cert_subject} || "Unknown"; $SSLPRINT="$DIV\n"; $SSLPRINT.="+ SSL Info: Ciphers: $SSLCIPHERS\n Info: $SSLISSUERS\n Subject: $SSLINFO"; } if ($TARGETS{$CURRENT_HOST_ID}{ip} =~ /[a-z]/i) { nprint("+ Target IP: (proxied)"); } else { nprint("+ Target IP: $TARGETS{$CURRENT_HOST_ID}{ip}"); } nprint("+ Target Hostname: $TARGETS{$CURRENT_HOST_ID}{hostname}"); nprint("+ Target Port: $CURRENT_PORT"); if (($CLI{vhost} ne $TARGETS{$CURRENT_HOST_ID}{hostname}) && ($CLI{vhost} ne "")) { nprint("+ Virtual Host: $CLI{vhost}"); } if ($request{'whisker'}->{'proxy_host'} ne "") { nprint("- Proxy: $request{'whisker'}->{'proxy_host'}:$request{'whisker'}->{'proxy_port'}"); } if ($NIKTO{hostid} ne "") { nprint("- Host Auth: ID: $NIKTO{hostid}, PW: $NIKTO{hostpw}, Realm: $NIKTO{hostdomain}","v"); } if ($TARGETS{$CURRENT_HOST_ID}{ports}{$CURRENT_PORT}{ssl}) { nprint($SSLPRINT); } for (my $i=1;$i<=9;$i++) { if ($CLI{evasion} =~ /$i/) { nprint("+ Using IDS Evasion:\t$NIKTO{anti_ids}{$i}"); }} nprint("+ Start Time: $start"); nprint($DIV); if (!($CLI{forcegen})) { nprint("- Scan is dependent on \"Server\" string which can be faked, use -g to override"); } if ($TARGETS{$CURRENT_HOST_ID}{ports}{$CURRENT_PORT}{banner} ne "") { nprint("+ Server: $TARGETS{$CURRENT_HOST_ID}{ports}{$CURRENT_PORT}{banner}"); } else { nprint("+ Server ID string not sent"); } return;}#################################################################################sub general_config{ ## gotta set these first $|=1; $NIKTO{anti_ids}{1}="Random URI encoding (non-UTF8)"; $NIKTO{anti_ids}{2}="Directory self-reference (/./)"; $NIKTO{anti_ids}{3}="Premature URL ending"; $NIKTO{anti_ids}{4}="Prepend long random string"; $NIKTO{anti_ids}{5}="Fake parameter"; $NIKTO{anti_ids}{6}="TAB as request spacer"; $NIKTO{anti_ids}{7}="Random case sensitivity"; $NIKTO{anti_ids}{8}="Use Windows directory separator (\\)"; $NIKTO{anti_ids}{9}="Session splicing"; $NIKTO{mutate_opts}{1}="Test all files with all root directories"; $NIKTO{mutate_opts}{2}="Guess for password file names"; $NIKTO{mutate_opts}{3}="Enumerate user names via Apache (/~user type requests)"; $NIKTO{mutate_opts}{4}="Enumerate user names via cgiwrap (/cgi-bin/cgiwrap/~user type requests)"; $NIKTO{options}=" Options: -Cgidirs Scan these CGI dirs: 'none', 'all', or a value like '/cgi/' -cookies print cookies found -evasion+ ids evasion technique (1-9, see below) -findonly find http(s) ports only, don't perform a full scan -Format save file (-o) Format: htm, csv or txt (assumed) -generic force full (generic) scan -host+ target host -id+ host authentication to use, format is userid:password -mutate+ mutate checks (see below) -nolookup skip name lookup -output+ write output to this file -port+ port to use (default 80) -root+ prepend root value to all requests, format is /directory -ssl force ssl mode on port -timeout timeout (default 10 seconds) -useproxy use the proxy defined in config.txt -Version print plugin and database versions -vhost+ virtual host (for Host header) + requires a value These options cannot be abbreviated: -debug debug mode -dbcheck syntax check scan_database.db and user_scan_database.db -update update databases and plugins from cirt.net -verbose verbose mode IDS Evasion Techniques: "; for (my $i=0;$i<=9;$i++) { if ($NIKTO{anti_ids}{$i} eq "") { next; } $NIKTO{options} .= "\t$i\t$NIKTO{anti_ids}{$i}\n"; } $NIKTO{options} .= "\n Mutation Techniques:\n"; for (my $i=0;$i<=9;$i++) { if ($NIKTO{mutate_opts}{$i} eq "") { next; } $NIKTO{options} .= "\t$i\t$NIKTO{mutate_opts}{$i}\n"; } ### CLI STUFF $CLI{pause}=$NIKTO{suppressauth}=$CLI{html}=$OUTPUT{verbose}=$CLI{skiplookup}=$NIKTO{totalmoved}=$NIKTO{totalokay}=$NIKTO{totalrequests}=$ITEMCOUNT=0; @OPTS=@ARGV; # preprocess CLI options which cannot be abbreviated for (my $i=0;$i<=$#ARGV;$i++) { if ($ARGV[$i] =~ /\-dbcheck/) { dbcheck(); } elsif ($ARGV[$i] =~ /\-verbose/) { $OUTPUT{verbose}=1; $ARGV[$i]=""; } elsif ($ARGV[$i] =~ /\-debug/) { $OUTPUT{debug}=1; $ARGV[$i]=""; } elsif ($ARGV[$i] =~ /\-update/) { check_updates(); } } GetOptions( "nolookup" => \$CLI{skiplookup}, "generic" => \$CLI{forcegen}, "Cgidirs=s"=> \$CLI{forcecgi}, "mutate=s" => \$CLI{mutate}, "id=s" => \$CLI{hostauth}, "evasion=s"=> \$CLI{evasion}, "port=s" => \$CLI{ports}, "findonly" => \$CLI{findonly}, "root=s" => \$CLI{root}, "timeout=s"=> \$CLI{timeout}, "x=s" => \$CLI{pause}, "ssl" => \$CLI{ssl}, "useproxy" => \$CLI{useproxy}, "vhost=s" => \$CLI{vhost}, "host=s" => \$CLI{host}, "cookies" => \$CLI{cookies}, "output=s" => \$CLI{file}, "Format=s" => \$CLI{format}, "Verbose" => \$CLI{verbose} ); if ($CLI{verbose}) { version(); } if (($CLI{format} eq "") || ($CLI{format} eq "text")) { $CLI{format}="txt"; } if ($CLI{format} eq "html") { $CLI{format}="htm"; } $CLI{format}=lc($CLI{format}); # port(s) $CLI{ports}=~s/^\s+//; $CLI{ports}=~s/\s+$//; if ($CLI{ports} eq "") { $CLI{ports}=80; } if ($CLI{ports} =~ /[^0-9\-\, ]/) { nprint("+ ERROR: Invalid port option '$CLI{ports}'"); exit; } ### VARIABLES (STUFF) if (length($CONFIG{"\@CGIDIRS"}) < 1) { $CONFIG{"\@CGIDIRS"}="/cgi-bin/"; } # populate %VARIABLES foreach my $key (keys %CONFIG) { if ($key =~ /^\@/) { $VARIABLES{$key}=$CONFIG{"$key"}; } } $OKTRAP=1; if ($CLI{hostauth} ne "") { my @x=split(/:/,$CLI{hostauth}); if (($#x ne 1) || ($x[0] eq "")) { nprint("+ ERROR: '$CLI{hostauth}' (-i option) syntax is 'user:password' or 'user:password:domain' for host authentication.") } $NIKTO{hostid} = $x[0]; $NIKTO{hostpw} = $x[1]; $NIKTO{hostdomain} = $x[2]; } $CLI{evasion}=~s/[^0-9]//g; $NIKTO{useragent}="Mozilla/4.75 ($NIKTO{name}/$NIKTO{version} $request{'User-Agent'})"; # here's the fingerprint -- this should always be something which will NOT be found on the server! $NIKTO{fingerprint}="$NIKTO{name}-$NIKTO{version}-" . LW::utils_randstr() . ".htm"; if ($CLI{evasion} ne "") # remove all refs to Nikto/LW { $NIKTO{useragent}="Mozilla/4.75"; $NIKTO{fingerprint}=LW::utils_randstr() . ".htm"; }# SSL Testif (!$LW::LW_HAS_SSL) { nprint("-***** SSL support not available (see docs for SSL install instructions) *****"); }# get core versionopen(FI,"<$NIKTO{plugindir}/nikto_core.plugin");my @F=<FI>;close(FI);my @VERS=grep(/^#VERSION/,@F);$NIKTO{core_version}=$VERS[0];$NIKTO{core_version}=~s/\#VERSION,//;chomp($NIKTO{core_version});$COUNTERS{hosts_total}=$COUNTERS{hosts_completed}=0;return;}#################################################################################sub resolve{ my $ident=$_[0] || return; my ($name, $ip, $dn)=""; # ident is name, lookup IP if ($ident =~ /[^0-9\.]/) # not an IP, assume name { if ($CLI{skiplookup}) { nprint("+ ERROR: -skiplookup set, but given name\n"); exit; } $ip=gethostbyname($ident); if (($ip eq "") && ($request{'whisker'}->{'proxy_host'} ne "")) # can't resolve name to IP, but using proxy { $name=$ident; $ip=$name; } elsif (($ip eq "") && ($request{'whisker'}->{'proxy_host'} eq "")) # can't resolve name to IP, no proxy set { nprint("+ ERROR: Cannot resolve hostname '$ident'\n"); delete $TARGETS{$CURRENT_HOST_ID}; return; } else { use IO::Socket; $ip=inet_ntoa($ip); if (($ip !~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) && ($ip ne "")) # trap for proxy... { nprint("+ ERROR: Invalid IP '$ip'\n\n"); delete $TARGETS{$CURRENT_HOST_ID}; return; } $name=$ident; } } else # ident is IP, lookup name { if (($ident !~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) && ($ident ne "")) # trap for proxy... { nprint("+ ERROR: Invalid IP '$ident'\n\n"); delete $TARGETS{$CURRENT_HOST_ID}; return; } $ip=$ident; if (!$CLI{skiplookup}) { use IO::Socket; my $temp_ip=inet_aton($ip); $name=gethostbyaddr($temp_ip,AF_INET); } if ($name eq "") { $name=$ip; } } # set displayname -- name takes precedence
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -