source: trunk/plugins/nikto_headers.plugin @ 294

Revision 294, 8.5 KB checked in by sullo, 3 years ago (diff)

Fix a ton of potential perl warnins (future reserved word). But not all of them :(

  • Property svn:keywords set to Id
Line 
1#VERSION,2.05
2# $Id$
3###############################################################################
4#  Copyright (C) 2007 CIRT, Inc.
5#
6#  This program is free software; you can redistribute it and/or
7#  modify it under the terms of the GNU General Public License
8#  as published by the Free Software Foundation; version 2
9#  of the License only.
10#
11#  This program is distributed in the hope that it will be useful,
12#  but WITHOUT ANY WARRANTY; without even the implied warranty of
13#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14#  GNU General Public License for more details.
15#
16#  You should have received a copy of the GNU General Public License
17#  along with this program; if not, write to the Free Software
18#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19###############################################################################
20# PURPOSE:
21# General HTTP headers checks
22###############################################################################
23sub nikto_headers_init
24{
25   my $id =
26   {
27      name         => "headers",
28      full_name    => "HTTP Headers",
29      author       => "Sullo",
30      description  => "Performs various checks against the headers returned from a HTTP request.",
31      scan_method  => \&nikto_headers,
32      copyright    => "2008 CIRT Inc."
33   };
34   return $id;
35}
36
37sub nikto_headers
38{
39   my ($mark)=@_;
40   my $dbarray = init_db("db_headers");
41   my @interesting_headers = qw /microsoftofficewebserver ms-author-via dasl dav daap-server x-aspnet-version/;
42   my %headers;
43   # Standard headers, whisker is added to stop false positives
44   # Host Pragma
45
46   #######################################################################
47   # look for a powered-by header...could require a valid file, maybe not
48   my %xpb;
49   foreach my $f (qw/\/index.php \/junk999.php \/ \/index.php3 \/ \/junk999.php3 \/index.cfm \/junk999.cfm \/index.asp \/junk999.asp \/index.aspx \/junk988.aspx/ )
50   {
51      (my $res, $content) = nfetch($mark, $f, "GET", "", \%headers, "", "headers: powered-by");
52      if (defined $headers{'x-powered-by'}) { $xpb{ $headers{'x-powered-by'} } = 1; }
53   }
54
55   foreach my $x (sort keys %xpb)
56   {
57      my $message;
58
59      # push version to BUILDITEMS so it can be evaluated later
60      push(@BUILDITEMS, $x);
61
62      $message .= " $x";
63      add_vulnerability($mark,"Retrieved X-Powered-By header:$message", 999992, 0);
64   }
65   
66   #######################################################################
67   # look for to see whether its vulnerable to the Translate: f
68   my %transheaders;
69   foreach my $f (qw/\/index.asp \/junk999.asp \/index.aspx \/junk988.aspx \/login.asp \/login.aspx/ )
70   {
71      (my $res, $content) = nfetch($mark, $f , "GET", "", \%transheaders, "", "headers: Translate-f #1");
72      if ($res eq "200")
73      {
74         $transheaders{'Translate'}="f";
75         ($res, $content) = nfetch($mark, $f . "\\", "GET", "", \%transheaders, "", "headers: Translate-f #2");
76         if ($res eq "200")
77         {
78            if ($content =~ /<asp:/ || $content =~ /<\/asp:/)
79            {
80               add_vulnerability($mark, "Host may be vulnerable to a source disclosure using the Translate: header", 999983, 390, "GET", $f, $content);
81               last;
82            }
83         }
84      }
85   }
86
87   #######################################################################
88   # Servlet-Engine info
89   if (defined $headers{'servlet-engine'})
90   {
91      my $x = $headers{'servlet-engine'};
92      $x = ~s/\(.*$//;
93      $x =~ s/\s+//g;
94      push(@BUILDITEMS, $x);
95
96      add_vulnerability($mark, "Retrieved servlet-engine headers: $x",999991,0);
97
98      my @bits = split(/;/, $x);
99      foreach my $bit (@bits)
100      {
101         push(@BUILDITEMS, $bit);
102      }
103   }
104
105   #######################################################################
106   # Content-Location header in IIS
107   LW2::http_close(\%request);    # force-close any old connections
108   LW2::http_fixup_request(\%request);
109   LW2::http_reset();
110   my $wh = $request{'whisker'}{'Host'};
111   my $h  = $request{'Host'};
112   delete $request{'whisker'}{'Host'};
113   delete $request{'Host'};
114   $request{'whisker'}->{'uri'}    = "/";
115   $request{'whisker'}->{'method'} = "GET";
116   $request{'whisker'}{'version'}  = "1.0";
117   
118   LW2::http_do_request_timeout(\%request, \%result);
119   $NIKTO{'totalrequests'}++;
120   if (   ($result{'content-location'} ne "")
121      && ($result{'content-location'} =~ /[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)
122      && ($result{'content-location'} !~ /$mark->{'ip'}/))
123   {
124      add_vulnerability($mark,"IIS may reveal its internal IP in the Content-Location header via a request to the root file. The value is \"$result{'content-location'}\".", 999989, 630);
125   }
126   
127   LW2::http_close(\%request);    # force-close any old connections
128   LW2::http_fixup_request(\%request);
129   LW2::http_reset();
130   $request{'whisker'}->{'uri'}    = "/images";
131   $request{'whisker'}->{'method'} = "GET";
132   $request{'whisker'}{'version'}  = "1.0";
133   delete $request{'whisker'}{'Host'};
134   delete $request{'Host'};
135   if ($CLI{'pause'} > 0) { sleep $CLI{'pause'}; }
136   LW2::http_do_request_timeout(\%request, \%result);
137   $NIKTO{'totalrequests'}++;
138
139   if (($result{'location'} ne "")
140      && ($result{'location'} =~ /[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)
141      && ($result{'location'} !~ /$mark->{'ip'}/))
142   {
143      add_vulnerability($mark,"IIS may reveal its internal IP in the Location header via a request to the /images directory. The value is \"$result{'location'}\".",999988,630,"GET","/images");
144   }
145
146   $request{'whisker'}{'Host'} = $wh;
147   $request{'Host'} = $h;
148
149   #######################################################################
150   # Location header in WebLogic
151   LW2::http_close(\%request);    # force-close any old connections
152   LW2::http_fixup_request(\%request);
153   LW2::http_reset();
154   $request{'whisker'}->{'uri'}    = ".";
155   $request{'whisker'}->{'method'} = "GET";
156   $request{'whisker'}{'version'}  = "1.0";
157   if ($CLI{'pause'} > 0) { sleep $CLI{'pause'}; }
158   LW2::http_do_request_timeout(\%request, \%result);
159   $NIKTO{'totalrequests'}++;
160
161   if (($result{'location'} ne "") && ($result{'location'} =~ /http:\/\//))
162   {
163      add_vulnerability($mark,"WebLogic may reveal its internal IP or hostname in the Location header. The value is \"$result{'location'}\".",999987,5737,"GET",".");
164   }
165
166   #######################################################################
167   # All other interesting headers
168   
169   # First let's hit something we know should return something
170   my ($res, $content)=nfetch($mark, "/", "GET" ,"" ,\%headers, "", "headers: base");
171
172   foreach my $header (@interesting_headers)
173   {
174      if ($headers{$header} ne '')
175      {
176         my $x = $headers{$header};
177         $x =~ s/\s+.*$//;
178         push(@BUILDITEMS, $x);
179         add_vulnerability($mark,"Retrieved $header header: $headers{$header}",999986,0);
180      }
181   }
182
183   #######################################################################
184   # Look for any uncommon headers
185   foreach my $header (sort keys %headers)
186   {
187      my $found = 0;
188      my $reportnum = 999100;
189      foreach my $st_header (@$dbarray)
190      {
191         if ($header eq $st_header->{'header'})
192         {
193            $found=1;
194         }
195      }
196      if ($found == 0)
197      {
198         my $x = $headers{$header};
199         $x =~s/\s+.*$//;
200         push(@BUILDITEMS, $x);
201         add_vulnerability($mark,"Uncommon header '$header' found, with contents: $headers{$header}",$reportnum,0);
202         $reportnum++;
203      }
204   }
205
206   #######################################################################
207   # ETag header
208   
209   # Try to grab a standard file
210   foreach my $f (qw/\/index.html \/index.htm \/robots.txt/)
211   {
212      (my $res, $content) = nfetch($mark, $f, "GET", "", \%headers, "", "headers: etag");
213      last if (defined $headers{'etag'});
214   }
215   
216   # Now we have a header, let's check ETag for inode
217   if (defined $headers{'etag'})
218   {
219      my $etag=$headers{'etag'};
220      $etag =~ s/"//g;
221      my @fields = split("-",$etag);
222      my $message = "ETag header found on server";
223      if ($#fields == 2)
224      {
225         my $inode="0x$fields[0]";
226         my $size="0x$fields[1]";
227         my $mtime="0x$fields[2]";
228         # for some reason $mtime is mangled
229         $message .= sprintf(", inode: %d, size: %d, mtime: %s", hex($inode), hex($size),  $mtime);
230      }
231      else
232      {
233         $message .= ", fields: ";
234         foreach my $field (@fields)
235         {
236            $message .= "0x$field ";
237         }
238      }
239      add_vulnerability($mark, $message, 999984, 0);
240   }
241}
242
2431;
Note: See TracBrowser for help on using the repository browser.