#VERSION,2.04
# $Id: nikto_httpoptions.plugin 155 2009-08-13 21:43:24Z deity $

###############################################################################
#  Copyright (C) 2006 CIRT, Inc.
#
#  This program 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; version 2
#  of the License only.
#
#  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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
###############################################################################

###############################################################################
# PURPOSE
# HTTP options check
###############################################################################
sub nikto_httpoptions_init
{
   my $id =
   {
      name         => "httpoptions",
      full_name    => "HTTP Options",
      author       => "Sullo",
      description  => "Performs a variety of checks against the HTTP options returned from the server.",
      scan_method  => \&nikto_httpoptions,
      copyright    => "2008 CIRT Inc."
   };
   return $id;
}
# This just gets the HTTP options & checks 'em out.
# See RFC 2626 for more info...

sub nikto_httpoptions
{
   my ($mark) = @_;
   my %headers;
   # test for both OPTIONS / and OPTIONS * as they may give different results
   (my $res, $content) = nfetch($mark,"*", "OPTIONS", "", \%headers);
   my $aoptions = "$headers{allow}, ";
   my $poptions = "$headers{public}, ";
   my ($allow_methods, $public_methods, $txt);
   my $dbarray;

   $dbarray=initialise_db("db_httpoptions");

   ($res, $content) = nfetch($mark,"/", "OPTIONS", "", \%headers);
   $aoptions .= $headers{allow};
   $poptions .= $headers{public};

   foreach my $o (split(/,[ ]?/, $aoptions)) { $allow_methods .= ", $o" unless ($allow_methods =~ /\b$o\b/ || $o eq ''); }
   $allow_methods =~ s/^[ ]?, //;
   foreach my $o (split(/,[ ]?/, $poptions)) { $public_methods .= ", $o" unless ($public_methods =~ /\b$o\b/ || $o eq ''); }
   $public_methods =~ s/^[ ]?, //;

   # proxy can impose it's methods... should actually check this not just warn
   if ($CLI{useproxy} ne "") { $txt = "(May be proxy's methods, not server's)"; }

   if ($allow_methods ne "")
   {
      add_vulnerability($mark,"Allowed HTTP Methods: $allow_methods $txt",999990,0);
      foreach my $m (split /,? /, $allow_methods) { eval_methods($m, "Allow", $dbarray,$mark); }
   }

   if ($public_methods ne "")
   {
      add_vulnerability($mark,"Public HTTP Methods: $public_methods $txt",999985,0);
      foreach my $m (split /,? /, $public_methods) { eval_methods($m, "Public", $dbarray,$mark); }
   }

   # Check for other weirdness
   # IIS Debug

   ($res, $content) = nfetch($mark,"/","DEBUG",);
   if ($res == 200) 
   {
      add_vulnerability($mark,"DEBUG HTTP verb may show server debugging information",999972,0,"DEBUG");
   }
   # IIS PROPFIND HEADER
   my %headers=(
      "Host" => "",
      "Content-Length" => "0",
   );
   ($res, $content) = nfetch($mark,"/","PROPFIND","",\%headers,1);
   if ($res == 207)
   {
      if ($content =~ "<a:href>http://")
      {
         my $ipfound=$content;
         $ipfound =~ s/^.*<a:href>//g;
         $ipfound =~ s/<\/a:href>.*$//g;
         add_vulnerability($mark,"PROPFIND HTTP verb may show the server's internal IP address: $ipfound",999973,13431);
      }
   } 

   # Special checks for TRACE/TRACK to see whether its vulnerable
   my %headers=(
      "Host" => "Nikto",
   );
   foreach my $method (split(/ /,"TRACE TRACK"))
   {
      # Check for all flavours of HTTP
      foreach my $version (split(/ /,"1.0 1.1"))
      {
         $request{whisker}{version} = $version; 
         ($res, $content) = nfetch($mark,"/","$method","",\%headers);
         if ($res == 200)
         {
            if ($content =~ "Nikto")
            {
               add_vulnerability($mark,"HTTP $method method is active, suggesting the host is vulnerable to XST",999971,877);
               # now we know its vulnerable stop testing
               last;
            }
         }
      }
   } 
   # Now release memory for the dbarray
   undef @$dbarray;
   return;
}

sub eval_methods
{
   my $method = $_[0] || return;
   my $type = $_[1];
   my $dbarray = $_[2];
   my $mark = $_[3];
   my $message;
   $method = uc($method);

   # Now search database for the method.
   foreach my $item (@$dbarray)
   {
      if ($item->{method} eq $method)
      {
         $message = $item->{message};
         $message =~ s/\@TYPE\@/$type/;
         add_vulnerability($mark,"$message",$item->{nikto_id},$item->{osvdb});
      }
   }
}

1;
