source: trunk/plugins/nikto_auth.plugin @ 505

Revision 505, 7.2 KB checked in by deity, 3 years ago (diff)

Fix for broken -id parameter and clean up of unused %REALMS hash

  • 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    if (defined $CLI{'hostauth'}) {
59        my @x = split(/:/, $CLI{'hostauth'});
60
61        my $HOSTAUTH = {
62            nikto_id    => "700500",
63            realm       => (defined $x[2]) ? $x[2] : '@ANY',
64            password    => $x[1],
65            id          => $x[0],
66            message     => "Credentials provided by CLI.",
67        };
68        unshift(@{$REALMS}, $HOSTAUTH);
69    }
70}
71
72sub nikto_auth_pre {
73    my ($mark, $parameters, $request, $result) = @_;
74
75    # If we know the realm then don't bother guessing it
76    # See whether we've already guessed it
77
78    my ($uridir) = $request->{'whisker'}->{'uri'};
79    $uridir =~ s#/[^/]*$#/#g;
80
81    if (exists $REALMSMATCHED{ $mark->{'hostname'} }{$uridir}) {
82
83        # Just set up the auth and return the valid result
84        LW2::auth_set($REALMSMATCHED{ $mark->{'hostname'} }{$uridir}{'authtype'},
85                      $request,
86                      $REALMSMATCHED{ $mark->{'hostname'} }{$uridir}{'id'},
87                      $REALMSMATCHED{ $mark->{'hostname'} }{$uridir}{'password'}
88                      );
89
90        # Patch to fix short reads
91        $request->{'whisker'}->{'allow_short_reads'} = 1;
92        LW2::http_fixup_request($request);
93    }
94    return $request, $result;
95}
96
97sub nikto_auth {
98    my ($mark, $parameters, $request, $result) = @_;
99    my ($authtype) = 'basic';
100    my ($body)     = $result->{'whisker'}->{'data'};
101    my ($uri)      = $result->{'whisker'}->{'uri'};
102    my ($method)   = $result->{'whisker'}->{'method'} || "GET";
103    my ($realm, $save_auth);
104
105    unless (defined $result->{'www-authenticate'}) {
106        nprint("+ ERROR: No authentication header defined: $uri");
107        return $request, $result;
108    }
109
110    # Save to revert
111    $save_auth = $result{'www-authenticate'};
112
113    # Split up www-authenticate to realm and method
114    my @authenticate = split(/ /, $result->{'www-authenticate'});
115    if ($#authenticate == 0) {    # Only one parameter: realm
116        $realm = $authenticate[0];
117        if ($realm =~ /^ntlm/i) {
118            $realm    = "";
119            $authtype = $authenticate[0];
120        }
121    }
122    else {
123        $authtype = $authenticate[0];
124        $realm    = $authenticate[1];
125        $realm =~ s/^realm=//;
126    }
127
128    nprint("+ $uri - Requires Authentication for realm '$realm'") if $OUTPUT{'show_auth'};
129
130    # Now we have this we can try guessing the password
131    foreach my $entry (@{$REALMS}) {
132        unless ($realm =~ /$entry->{'realm'}/i || $entry->{realm} eq '@ANY') { next; }
133
134        if ($result->{'www-authenticate'} =~ /^ntlm/i) {
135            $authtype = 'ntlm';
136        }
137
138        # Set up LW hash
139        LW2::auth_set($authtype, $request, $entry->{'id'}, $entry->{'password'});
140
141        # Patch to fix short reads
142        $request->{'whisker'}->{'allow_short_reads'} = 1;
143        LW2::http_fixup_request($request);
144
145        # pause if needed
146        if ($CLI{'pause'} > 0) { sleep $CLI{'pause'}; }
147
148        LW2::http_do_request_timeout($request, $result);    # test auth
149        $NIKTO{'totalrequests'}++;
150        dump_var("Auth Request",  $request);
151        dump_var("Auth Response", $result);
152
153        if ($result{'www-authenticate'} =~ /^ntlm/i) {
154
155            # Deal with ntlm
156            my @ntlm_x = split(/ /, $result{'www-authenticate'});
157            if ($#ntlm_x == 1) {
158                LW2::http_do_request_timeout(\%request, \%result);
159                $NIKTO{'totalrequests'}++;
160            }
161        }
162        my $uridir = $request->{'whisker'}->{'uri'};
163        $uridir =~ s#/[^/]*$#/#g;
164
165        if ($result->{'www-authenticate'} eq ''
166            && !defined $result->{'whisker'}->{'error'}) {
167            my $message =
168              "Default account found for '$realm' at $uridir ($request->{'whisker'}->{'uri'}) (ID '$entry->{'id'}', PW '$entry->{'password'}'). $entry->{message}";
169            if ($entry->{'id'} eq '' && $entry->{'password'} eq '') {
170                $message =
171                  "Blank credentials found at $uridir ($request{whisker}->{uri}), $entry->{'realm'}: $entry->{'msg'}";
172            }
173            unless ($entry->{'checked'} == 1) {
174                add_vulnerability($mark, $message, $entry->{tid}, 0, "GET", $uridir, $result);
175                $entry->{checked} = 1;
176            }
177
178            # Finally repeat the check
179            LW2::http_do_request_timeout($request, $result);    # test auth
180            $NIKTO{'totalrequests'}++;
181
182            # Set up so we don't have to repeat in future
183            # / isn't a valid entry in a hash  - more stupid perl
184
185            $REALMSMATCHED{ $mark->{hostname} }{$uridir}{'id'}       = $entry->{'id'};
186            $REALMSMATCHED{ $mark->{hostname} }{$uridir}{'password'} = $entry->{'password'};
187            $REALMSMATCHED{ $mark->{hostname} }{$uridir}{'authtype'} = $authtype;
188
189            # and leave
190            last;
191        }
192        else {
193            $result->{'www-authenticate'} = $save_auth;
194        }
195    }
196    LW2::auth_unset(\%request);
197
198    return $request, $result;
199}
200
2011;
Note: See TracBrowser for help on using the repository browser.