##
# 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
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
def initialize
super(
'Name' => 'Wordpress Scanner',
'Description' => 'Detects Wordpress Versions, Themes, Plugins, and Users',
'Author' => [
'Christian Mehlmauer', # original module
'h00die', # plugins and themes
'shoxxdj' # users
],
'License' => MSF_LICENSE
)
register_options [
OptBool.new('EXPLOITABLE', [false, 'Only scan plugins and themes which a MSF module exists for', true]),
OptPath.new('EXPLOITABLE_THEMES', [
true, 'File containing exploitable by MSF themes',
File.join(Msf::Config.data_directory, 'wordlists', 'wp-exploitable-themes.txt')
]),
OptPath.new('EXPLOITABLE_PLUGINS', [
true, 'File containing exploitable by MSF plugins',
File.join(Msf::Config.data_directory, 'wordlists', 'wp-exploitable-plugins.txt')
]),
OptBool.new('THEMES', [false, 'Detect themes', true]),
OptBool.new('PLUGINS', [false, 'Detect plugins', true]),
OptPath.new('THEMES_FILE', [
true, 'File containing themes to enumerate',
File.join(Msf::Config.data_directory, 'wordlists', 'wp-themes.txt')
]),
OptPath.new('PLUGINS_FILE', [
true, 'File containing plugins to enumerate',
File.join(Msf::Config.data_directory, 'wordlists', 'wp-plugins.txt')
]),
OptInt.new('PROGRESS', [true, 'how often to print progress', 1000]),
OptBool.new('USERS', [false, 'Detect users with API', true])
]
end
def print_progress(host, i, total)
print_status("#{host} - Progress #{i.to_s.rjust(Math.log10(total).ceil + 1)}/#{total} (#{((i.to_f / total) * 100).truncate(2)}%)")
end
def run_host(target_host)
print_status("Trying #{target_host}")
if wordpress_and_online?
version = wordpress_version
version_string = version || '(no version detected)'
print_good("#{target_host} - Detected Wordpress #{version_string}")
report_note(
{
host: target_host,
proto: 'tcp',
sname: (ssl ? 'https' : 'http'),
port: rport,
type: "Wordpress #{version_string}",
data: target_uri.to_s
}
)
if datastore['THEMES']
print_status("#{target_host} - Enumerating Themes")
if datastore['EXPLOITABLE']
f = File.open(datastore['EXPLOITABLE_THEMES'], 'rb')
else
f = File.open(datastore['THEMES_FILE'], 'rb')
end
total = f.readlines.size
f.rewind
f = f.readlines
f.each_with_index do |theme, i|
theme = theme.strip
print_progress(target_host, i, total) if i % datastore['PROGRESS'] == 0
vprint_status("#{target_host} - Checking theme: #{theme}")
version = check_theme_version_from_readme(theme)
next if version == Msf::Exploit::CheckCode::Unknown # aka not found
print_good("#{target_host} - Detected theme: #{theme} version #{version.details[:version]}")
report_note(
{
host: target_host,
proto: 'tcp',
sname: (ssl ? 'https' : 'http'),
port: rport,
type: "Wordpress Theme: #{theme} version #{version.details[:version]}"
# data: target_uri
}
)
end
print_status("#{target_host} - Finished scanning themes")
end
if datastore['PLUGINS']
print_status("#{target_host} - Enumerating plugins")
if datastore['EXPLOITABLE']
f = File.open(datastore['EXPLOITABLE_PLUGINS'], 'rb')
else
f = File.open(datastore['PLUGINS_FILE'], 'rb')
end
total = f.readlines.size
f.rewind
f = f.readlines
f.each_with_index do |plugin, i|
plugin = plugin.strip
print_progress(target_host, i, total) if i % datastore['PROGRESS'] == 0
vprint_status("#{target_host} - Checking plugin: #{plugin}")
version = check_plugin_version_from_readme(plugin)
next if version == Msf::Exploit::CheckCode::Unknown # aka not found
print_good("#{target_host} - Detected plugin: #{plugin} version #{version.details[:version]}")
report_note(
{
host: target_host,
proto: 'tcp',
sname: (ssl ? 'https' : 'http'),
port: rport,
type: "Wordpress Plugin: #{plugin} version #{version.details[:version]}"
# data: target_uri
}
)
end
print_status("#{target_host} - Finished scanning plugins")
end
if datastore['USERS']
print_status("#{target_host} - Searching Users")
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(wordpress_url_rest_api, 'users')
})
if res.nil?
print_error('Error getting response.')
elsif res.code == 200
parsed = res.get_json_document
if parsed.empty?
print_error('Response received, but no JSON content was provided.')
else
parsed.map do |child|
name = child['name']
wp_username = child['slug']
print_good("#{target_host} - Detected user: #{name} with username: #{wp_username}")
service_data = {
address: rhost,
port: rport,
service_name: (ssl ? 'https' : 'http'),
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: wp_username,
private_data: '',
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: nil
}.merge(service_data)
create_credential_login(login_data)
end
print_status("#{target_host} - Finished scanning users")
end
else
print_status("#{target_host} - Was not able to identify users on site using #{wordpress_url_rest_api}/users")
end
print_status("#{target_host} - Finished all scans")
end
end
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