@@ -17,6 +17,19 @@ class SMB
17
17
include Metasploit ::Framework ::LoginScanner ::RexSocket
18
18
include Metasploit ::Framework ::LoginScanner ::NTLM
19
19
20
+ # Constants to be used in {Result#access_level}
21
+ module AccessLevels
22
+ # Administrative access. For SMB, this is defined as being
23
+ # able to successfully Tree Connect to the `ADMIN$` share.
24
+ # This definition is not without its problems, but suffices to
25
+ # conclude that such a user will most likely be able to use
26
+ # psexec.
27
+ ADMINISTRATOR = "Administrator"
28
+ # Guest access means our creds were accepted but the logon
29
+ # session is not associated with a real user account.
30
+ GUEST = "Guest"
31
+ end
32
+
20
33
CAN_GET_SESSION = true
21
34
DEFAULT_REALM = 'WORKSTATION'
22
35
LIKELY_PORTS = [ 139 , 445 ]
@@ -100,6 +113,27 @@ module StatusCodes
100
113
allow_nil : true
101
114
102
115
116
+ # If login is successul and {Result#access_level} is not set
117
+ # then arbitrary credentials are accepted. If it is set to
118
+ # Guest, then arbitrary credentials are accepted, but given
119
+ # Guest permissions.
120
+ #
121
+ # @param domain [String] Domain to authenticate against. Use an
122
+ # empty string for local accounts.
123
+ # @return [Result]
124
+ def attempt_bogus_login ( domain )
125
+ if defined? ( @result_for_bogus )
126
+ return @result_for_bogus
127
+ end
128
+ cred = Credential . new (
129
+ public : Rex ::Text . rand_text_alpha ( 8 ) ,
130
+ private : Rex ::Text . rand_text_alpha ( 8 ) ,
131
+ realm : domain
132
+ )
133
+ @result_for_bogus = attempt_login ( cred )
134
+ end
135
+
136
+
103
137
# (see Base#attempt_login)
104
138
def attempt_login ( credential )
105
139
@@ -121,7 +155,7 @@ def attempt_login(credential)
121
155
122
156
begin
123
157
# TODO: OMG
124
- ok = simple . login (
158
+ simple . login (
125
159
smb_name ,
126
160
credential . public ,
127
161
credential . private ,
@@ -140,16 +174,29 @@ def attempt_login(credential)
140
174
}
141
175
)
142
176
143
- simple . connect ( "\\ \\ #{ smb_name } \\ IPC$" )
144
- status = ok ? :success : :failed
145
- rescue ::Rex ::Proto ::SMB ::Exceptions ::ErrorCode => e
177
+ # Windows SMB will return an error code during Session
178
+ # Setup, but nix Samba requires a Tree Connect. Try admin$
179
+ # first, since that will tell us if this user has local
180
+ # admin access. Fall back to IPC$ which should be accessible
181
+ # to any user with valid creds.
182
+ begin
183
+ simple . connect ( "\\ \\ #{ host } \\ admin$" )
184
+ access_level = AccessLevels ::ADMINISTRATOR
185
+ simple . disconnect ( "\\ \\ #{ host } \\ admin$" )
186
+ rescue ::Rex ::Proto ::SMB ::Exceptions ::ErrorCode
187
+ simple . connect ( "\\ \\ #{ host } \\ IPC$" )
188
+ end
189
+
190
+ # If we made it this far without raising, we have a valid
191
+ # login
192
+ status = :success
193
+ rescue ::Rex ::Proto ::SMB ::Exceptions ::LoginError => e
146
194
status = case e . get_error ( e . error_code )
147
195
when *StatusCodes ::CORRECT_CREDENTIAL_STATUS_CODES
148
196
:correct
149
197
when 'STATUS_LOGON_FAILURE' , 'STATUS_ACCESS_DENIED'
150
198
:failed
151
199
else
152
- puts e . backtrace . join
153
200
:failed
154
201
end
155
202
@@ -161,7 +208,11 @@ def attempt_login(credential)
161
208
status = :connection_error
162
209
end
163
210
164
- Result . new ( credential : credential , status : status , proof : proof )
211
+ if status == :success && simple . client . auth_user . nil?
212
+ access_level ||= AccessLevels ::GUEST
213
+ end
214
+
215
+ Result . new ( credential : credential , status : status , proof : proof , access_level : access_level )
165
216
end
166
217
167
218
def connect
@@ -206,6 +257,7 @@ def set_sane_defaults
206
257
self . smb_name = self . host if self . smb_name . nil?
207
258
208
259
end
260
+
209
261
end
210
262
end
211
263
end
0 commit comments