@@ -17,6 +17,18 @@ 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
20
32
21
33
module StatusCodes
22
34
CORRECT_CREDENTIAL_STATUS_CODES = [
@@ -94,6 +106,27 @@ module StatusCodes
94
106
allow_nil : true
95
107
96
108
109
+ # If login is successul and {Result#access_level} is not set
110
+ # then arbitrary credentials are accepted. If it is set to
111
+ # Guest, then arbitrary credentials are accepted, but given
112
+ # Guest permissions.
113
+ #
114
+ # @param domain [String] Domain to authenticate against. Use an
115
+ # empty string for local accounts.
116
+ # @return [Result]
117
+ def attempt_bogus_login ( domain )
118
+ if defined? ( @result_for_bogus )
119
+ return @result_for_bogus
120
+ end
121
+ cred = Credential . new (
122
+ public : Rex ::Text . rand_text_alpha ( 8 ) ,
123
+ private : Rex ::Text . rand_text_alpha ( 8 ) ,
124
+ realm : domain
125
+ )
126
+ @result_for_bogus = attempt_login ( cred )
127
+ end
128
+
129
+
97
130
# (see Base#attempt_login)
98
131
def attempt_login ( credential )
99
132
@@ -115,7 +148,7 @@ def attempt_login(credential)
115
148
116
149
begin
117
150
# TODO: OMG
118
- ok = simple . login (
151
+ simple . login (
119
152
smb_name ,
120
153
credential . public ,
121
154
credential . private ,
@@ -134,16 +167,29 @@ def attempt_login(credential)
134
167
}
135
168
)
136
169
137
- simple . connect ( "\\ \\ #{ smb_name } \\ IPC$" )
138
- status = ok ? :success : :failed
170
+ # Windows SMB will return an error code during Session
171
+ # Setup, but nix Samba requires a Tree Connect. Try admin$
172
+ # first, since that will tell us if this user has local
173
+ # admin access. Fall back to IPC$ which should be accessible
174
+ # to any user with valid creds.
175
+ begin
176
+ simple . connect ( "\\ \\ #{ host } \\ admin$" )
177
+ access_level = AccessLevels ::ADMINISTRATOR
178
+ simple . disconnect ( "\\ \\ #{ host } \\ admin$" )
179
+ rescue ::Rex ::Proto ::SMB ::Exceptions ::ErrorCode
180
+ simple . connect ( "\\ \\ #{ host } \\ IPC$" )
181
+ end
182
+
183
+ # If we made it this far without raising, we have a valid
184
+ # login
185
+ status = :success
139
186
rescue ::Rex ::Proto ::SMB ::Exceptions ::ErrorCode => e
140
187
status = case e . get_error ( e . error_code )
141
188
when *StatusCodes ::CORRECT_CREDENTIAL_STATUS_CODES
142
189
:correct
143
190
when 'STATUS_LOGON_FAILURE' , 'STATUS_ACCESS_DENIED'
144
191
:failed
145
192
else
146
- puts e . backtrace . join
147
193
:failed
148
194
end
149
195
@@ -155,7 +201,11 @@ def attempt_login(credential)
155
201
status = :connection_error
156
202
end
157
203
158
- Result . new ( credential : credential , status : status , proof : proof )
204
+ if status == :success && simple . client . auth_user . nil?
205
+ access_level ||= AccessLevels ::GUEST
206
+ end
207
+
208
+ Result . new ( credential : credential , status : status , proof : proof , access_level : access_level )
159
209
end
160
210
161
211
def connect
@@ -200,6 +250,7 @@ def set_sane_defaults
200
250
self . smb_name = self . host if self . smb_name . nil?
201
251
202
252
end
253
+
203
254
end
204
255
end
205
256
end
0 commit comments