source: trunk/plugins/nikto_user_enum_apache.plugin @ 239

Revision 186, 5.8 KB checked in by sullo, 4 years ago (diff)
  • Standardization of ERROR print prefix, as well as matching in nprint to make sure we don't send things to STDERR we don't mean to.
  • If outputfile is - don't send any output to STDOUT, regardless of -F type.
  • Property svn:keywords set to Id
Line 
1#VERSION,2.1
2# $Id$
3
4###############################################################################
5#  Copyright (C) 2004 CIRT, Inc.
6#
7#  This program is free software; you can redistribute it and/or
8#  modify it under the terms of the GNU General Public License
9#  as published by the Free Software Foundation; version 2
10#  of the License only.
11#
12#  This program is distributed in the hope that it will be useful,
13#  but WITHOUT ANY WARRANTY; without even the implied warranty of
14#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15#  GNU General Public License for more details.
16#
17#  You should have received a copy of the GNU General Public License
18#  along with this program; if not, write to the Free Software
19#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20###############################################################################
21
22###############################################################################
23# PURPOSE
24# Enumeration of users and directories in system (as Apache's ~username)
25###############################################################################
26# NOTES
27# This plugin tries to enumerate all the users and directories
28# in the system (of course the bruteforce attack is limited to a given range).
29# In some Apache/UNIX systems this might give out many local users
30# (which could later on be used for a ssh brute-force attack).
31# This plugin was originally written by Javier Fernandez-Sanguino Pe–a
32###############################################################################
33sub nikto_user_enum_apache_init
34{
35   my $id =
36   {
37      name         => "user_enum_apache",
38      full_name    => "Apache User Enumeration",
39      author       => "Javier Fernandez-Sanguinoi Pena",
40      description  => "Attempts to enumerate usernames by guessing usernames.",
41      scan_method  => \&nikto_user_enum_apache,
42      scan_cond    => '$CLI{mutate} =~ /3/ || $CLI{mutate} =~ /4/',
43      copyright    => "2008 CIRT Inc."
44   };
45   return $id;
46}
47
48sub nikto_user_enum_apache
49{
50   my ($mark) = @_;
51   my $url;
52   my @cgiwraps, @cfgcgi=split(/ /, $VARIABLES{"\@CGIDIRS"});
53   
54   # Set the URL according to the mutate version
55   my @mutates=split(//,$CLI{mutate});
56   foreach my $option (@mutates)
57   {
58      if ($option eq "3")
59      {
60         $url="/~";
61         # First check whether we use a dictionary attack of brute force it
62         if (defined $CLI{mutate-options})
63         {
64            # We have options - assume it is a dictionary attack
65            nikto_user_enum_apache_dictionary($url);
66         }
67         else
68         {
69            nikto_user_enum_apache_brute($url);
70         }
71      }
72      if ($option eq "4")
73      {
74         # Check for existence of cgiwrap
75         foreach my $cgidir (@CFGCGI)
76         {
77            my $curl = "$cgidir" . "cgiwrap";
78            (my $result, $content) = nfetch($mark,"$curl", "GET");
79            if ($content =~ /check your URL/i)
80            {
81               push(@cgiwraps, "$curl");
82               $valid++;
83            }
84         }
85         
86         foreach my $cgiwrap (@cgiwraps)
87         {
88            $url="$cgiwrap/~";
89            # First check whether we use a dictionary attack of brute force it
90            if (defined $CLI{mutate-options})
91            {
92               # We have options - assume it is a dictionary attack
93               nikto_user_enum_apache_dictionary($url);
94            }
95            else
96            {
97               nikto_user_enum_apache_brute($url);
98            }
99         }
100      }
101   }
102}
103
104sub nikto_user_enum_apache_brute
105{
106   nprint("- Enumerating Apache users (1 to 5 characters).", "v");
107
108   # Note1: This script only generates names with letters A-Z (no numbers)
109   #
110   # Note2: this script will generate SUM(26^n)(n=$min to $max)
111   # it's probably faster to write this to a file than to generate it
112   # on the fly BTW.
113   #
114   # Of course, it could be optimized to skip some "strange"
115   # combinations of usernames, but hey, then it wouldn't
116   # be 'brute force' would it? (jfs)
117
118   my $text = "a";
119   my $ctr  = 0;
120   my $message="Valid users found via Apache enumeration: ";
121   my $result, $content;
122   my @foundusers=();
123   while (length($text) <= 5)
124   {
125      if (($ctr % 500) eq 0) { nprint("- User enumeration guess $ctr ($text)", "v"); }
126      (my $result, $content) = nfetch($mark,"/~" . $text, "HEAD");
127      my $user = nikto_user_enum_apache_check($result, $text);
128      if (defined $user)
129      {
130         push(@foundusers,$user);
131      }
132      $text++;
133      $ctr++;
134   }
135   if ($found)
136   {
137      add_vulnerability($mark, $message . join(' ',@foundusers), 999997, "637", "HEAD", "/");
138   }
139   
140}
141
142sub nikto_user_enum_apache_dictionary
143{
144   my $filename=$CLI{mutate-options};
145   my $message="Valid users found via Apache enumeration: ";
146   my @foundusers=();
147   my $result, $content;
148   my $ctr=0;
149   
150   nprint("- Enumerating Apache users (using dictionary $filename).", "v");
151   unless (open(IN, "<$filename"))
152   {
153      nprint("+ ERROR: Unable to open dictionary file $filename: $!.");
154   }
155
156   # Now attempt on each entry
157   while (<IN>)
158   {
159      chomp;
160      s/\#.*$//;
161      # remove preceding ~ just in case
162      s/^~//;
163      if ($_ eq "" ) { next };
164      if (($ctr % 500) == 0) { nprint("- User enumeration guess $ctr ($_)", "v"); }
165      (my $result, $content) = nfetch($mark,"/~" . $_, "HEAD");
166      my $user = nikto_user_enum_apache_check($result, $_);
167      if ($user)
168      {
169         push(@foundusers,$user);
170      }
171      $ctr++;
172   }
173   close(IN);
174   if (scalar(@foundusers))
175   {
176      add_vulnerability($mark, $message . join(' ',@foundusers), 999997, "637", "HEAD", "/");
177   }
178}
179
180sub nikto_user_enum_apache_check
181{
182   (my $code, $user) = @_;
183   my $result="";
184   
185   foreach my $found (split(/ /, $VARIABLES{"\@HTTPFOUND"}))
186   {
187      if ($code eq $found)
188      {
189         $result=$user;
190         last;
191      }
192   }
193   
194   return $result;
195}     
196
1971;
Note: See TracBrowser for help on using the repository browser.