source: trunk/plugins/nikto_auth.plugin @ 483

Revision 483, 6.8 KB checked in by sullo, 3 years ago (diff)

Update version numbers... lost sync!

  • Property svn:executable set to *
  • Property svn:keywords set to Id
Line 
1#VERSION,2.01
2# $Id$
3###############################################################################
4#  Copyright (C) 2004 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# Search content for known bad strings
22###############################################################################
23use vars qw/$REALMS %REALMSMATCHED/;
24
25sub nikto_auth_init {
26    my $id = { name             => 'auth',
27               full_name        => 'Guess authentication',
28               author           => 'Sullo/Deity',
29               description      => 'Attempt to guess authentication realms',
30               hooks            => {
31                                    start => {
32                                       method => \&nikto_auth_load,
33                                       weight => 1,
34                                    },
35                                    postfetch => {
36                                       method => \&nikto_auth,
37                                       weight => 19,
38                                       cond   => '$result->{whisker}->{code} eq 401',
39                                    },
40                                    prefetch => {
41                                       method => \&nikto_auth_pre,
42                                       weight => 19,
43                                    },
44                                   },                   
45               copyright        => "2010 CIRT Inc"
46               };
47
48    return $id;
49}
50
51sub nikto_auth_load {
52
53    # Load up the database as soon as we can
54
55    $REALMS        = init_db("db_realms");
56    %REALMSMATCHED = ();
57}
58
59sub nikto_auth_pre {
60    my ($mark, $parameters, $request, $result) = @_;
61
62    # If we know the realm then don't bother guessing it
63    # See whether we've already guessed it
64
65    my ($uridir) = $request->{'whisker'}->{'uri'};
66    $uridir =~ s#/[^/]*$#/#g;
67
68    if (exists $REALMSMATCHED{ $mark->{'hostname'} }{$uridir}) {
69
70        # Just set up the auth and return the valid result
71        LW2::auth_set($REALMSMATCHED{ $mark->{'hostname'} }{$uridir}{'authtype'},
72                      $request,
73                      $REALMSMATCHED{ $mark->{'hostname'} }{$uridir}{'id'},
74                      $REALMSMATCHED{ $mark->{'hostname'} }{$uridir}{'password'}
75                      );
76
77        # Patch to fix short reads
78        $request->{'whisker'}->{'allow_short_reads'} = 1;
79        LW2::http_fixup_request($request);
80    }
81    return $request, $result;
82}
83
84sub nikto_auth {
85    my ($mark, $parameters, $request, $result) = @_;
86    my ($authtype) = 'basic';
87    my ($body)     = $result->{'whisker'}->{'data'};
88    my ($uri)      = $result->{'whisker'}->{'uri'};
89    my ($method)   = $result->{'whisker'}->{'method'} || "GET";
90    my ($realm, $save_auth);
91
92    unless (defined $result->{'www-authenticate'}) {
93        nprint("+ ERROR: No authentication header defined: $uri");
94        return $request, $result;
95    }
96
97    # Save to revert
98    $save_auth = $result{'www-authenticate'};
99
100    # Split up www-authenticate to realm and method
101    my @authenticate = split(/ /, $result->{'www-authenticate'});
102    if ($#authenticate == 0) {    # Only one parameter: realm
103        $realm = $authenticate[0];
104        if ($realm =~ /^ntlm/i) {
105            $realm    = "";
106            $authtype = $authenticate[0];
107        }
108    }
109    else {
110        $authtype = $authenticate[0];
111        $realm    = $authenticate[1];
112        $realm =~ s/^realm=//;
113    }
114
115    nprint("+ $uri - Requires Authentication for realm '$realm'") if $OUTPUT{'show_auth'};
116
117    # Now we have this we can try guessing the password
118    foreach my $entry (@{$REALMS}) {
119        unless ($realm =~ /$entry->{'realm'}/i || $entry->{realm} eq '@ANY') { next; }
120
121        if ($result->{'www-authenticate'} =~ /^ntlm/i) {
122            $authtype = 'ntlm';
123        }
124
125        # Set up LW hash
126        LW2::auth_set($authtype, $request, $entry->{'id'}, $entry->{'password'});
127
128        # Patch to fix short reads
129        $request->{'whisker'}->{'allow_short_reads'} = 1;
130        LW2::http_fixup_request($request);
131
132        # pause if needed
133        if ($CLI{'pause'} > 0) { sleep $CLI{'pause'}; }
134
135        LW2::http_do_request_timeout($request, $result);    # test auth
136        $NIKTO{'totalrequests'}++;
137        dump_var("Auth Request",  $request);
138        dump_var("Auth Response", $result);
139
140        if ($result{'www-authenticate'} =~ /^ntlm/i) {
141
142            # Deal with ntlm
143            my @ntlm_x = split(/ /, $result{'www-authenticate'});
144            if ($#ntlm_x == 1) {
145                LW2::http_do_request_timeout(\%request, \%result);
146                $NIKTO{'totalrequests'}++;
147            }
148        }
149        my $uridir = $request->{'whisker'}->{'uri'};
150        $uridir =~ s#/[^/]*$#/#g;
151
152        if ($result->{'www-authenticate'} eq ''
153            && !defined $result->{'whisker'}->{'error'}) {
154
155            my $message =
156              "Default account found for '$realm' at $uridir ($request->{'whisker'}->{'uri'}) (ID '$entry->{'id'}', PW '$entry->{'password'}'). $entry->{message}";
157            if ($entry->{'id'} eq '' && $entry->{'password'} eq '') {
158                $message =
159                  "Blank credentials found at $uridir ($request{whisker}->{uri}), $entry->{'realm'}: $entry->{'msg'}";
160            }
161            unless ($entry->{'checked'} == 1) {
162                add_vulnerability($mark, $message, $entry->{tid}, 0, "GET", $uridir, $result);
163                $entry->{checked} = 1;
164            }
165
166            # Finally repeat the check
167            LW2::http_do_request_timeout($request, $result);    # test auth
168            $NIKTO{'totalrequests'}++;
169
170            # Set up so we don't have to repeat in future
171            # / isn't a valid entry in a hash  - more stupid perl
172
173            $REALMSMATCHED{ $mark->{hostname} }{$uridir}{'id'}       = $entry->{'id'};
174            $REALMSMATCHED{ $mark->{hostname} }{$uridir}{'password'} = $entry->{'password'};
175            $REALMSMATCHED{ $mark->{hostname} }{$uridir}{'authtype'} = $authtype;
176
177            # and leave
178            last;
179        }
180        else {
181            $result->{'www-authenticate'} = $save_auth;
182        }
183    }
184    LW2::auth_unset(\%request);
185
186    return $request, $result;
187}
188
1891;
Note: See TracBrowser for help on using the repository browser.