1212
1313sem = BoundedSemaphore (1 )
1414global_failed_logins = 0
15+ user_failed_logins = {}
1516
1617class Connection :
1718
@@ -35,11 +36,14 @@ def __init__(self, args, db, target, server_name, domain, conn, logger, cmeserve
3536
3637 self .login ()
3738
38- def over_fail_limit (self ):
39+ def over_fail_limit (self , username ):
3940 global global_failed_logins
41+ global user_failed_logins
4042
4143 if global_failed_logins == self .args .gfail_limit : return True
4244 if self .failed_logins == self .args .fail_limit : return True
45+ if username in user_failed_logins .keys ():
46+ if self .args .ufail_limit == user_failed_logins [username ]: return True
4347
4448 return False
4549
@@ -124,15 +128,22 @@ def plaintext_login(self, domain, username, password):
124128 return True
125129 except SessionError as e :
126130 error , desc = e .getErrorString ()
127- if error == 'STATUS_LOGON_FAILURE' :
128- global global_failed_logins ; global_failed_logins += 1
129- self .failed_logins += 1
130-
131131 self .logger .error (u'{}\\ {}:{} {} {}' .format (domain .decode ('utf-8' ),
132132 username .decode ('utf-8' ),
133133 password .decode ('utf-8' ),
134134 error ,
135135 '({})' .format (desc ) if self .args .verbose else '' ))
136+ if error == 'STATUS_LOGON_FAILURE' :
137+ global global_failed_logins
138+ global user_failed_logins
139+
140+ if username not in user_failed_logins .keys ():
141+ user_failed_logins [username ] = 0
142+
143+ user_failed_logins [username ] += 1
144+ global_failed_logins += 1
145+ self .failed_logins += 1
146+
136147 return False
137148
138149 def hash_login (self , domain , username , ntlm_hash ):
@@ -173,15 +184,22 @@ def hash_login(self, domain, username, ntlm_hash):
173184 return True
174185 except SessionError as e :
175186 error , desc = e .getErrorString ()
176- if error == 'STATUS_LOGON_FAILURE' :
177- global global_failed_logins ; global_failed_logins += 1
178- self .failed_logins += 1
179-
180187 self .logger .error (u'{}\\ {} {} {} {}' .format (domain .decode ('utf-8' ),
181188 username .decode ('utf-8' ),
182189 ntlm_hash ,
183190 error ,
184191 '({})' .format (desc ) if self .args .verbose else '' ))
192+ if error == 'STATUS_LOGON_FAILURE' :
193+ global global_failed_logins
194+ global user_failed_logins
195+
196+ if username not in user_failed_logins .keys ():
197+ user_failed_logins [username ] = 0
198+
199+ user_failed_logins [username ] += 1
200+ global_failed_logins += 1
201+ self .failed_logins += 1
202+
185203 return False
186204
187205 def login (self ):
@@ -209,25 +227,25 @@ def login(self):
209227 with sem :
210228 for ntlm_hash in self .args .hash :
211229 if type (ntlm_hash ) is not file :
212- if not self .over_fail_limit ():
230+ if not self .over_fail_limit (usr . strip () ):
213231 if self .hash_login (self .domain , usr .strip (), ntlm_hash ): return
214232
215233 elif type (ntlm_hash ) is file :
216234 for f_hash in ntlm_hash :
217- if not self .over_fail_limit ():
235+ if not self .over_fail_limit (usr . strip () ):
218236 if self .hash_login (self .domain , usr .strip (), f_hash .strip ()): return
219237 ntlm_hash .seek (0 )
220238
221239 elif self .args .password :
222240 with sem :
223241 for password in self .args .password :
224242 if type (password ) is not file :
225- if not self .over_fail_limit ():
243+ if not self .over_fail_limit (usr . strip () ):
226244 if self .plaintext_login (self .domain , usr .strip (), password ): return
227245
228246 elif type (password ) is file :
229247 for f_pass in password :
230- if not self .over_fail_limit ():
248+ if not self .over_fail_limit (usr . strip () ):
231249 if self .plaintext_login (self .domain , usr .strip (), f_pass .strip ()): return
232250 password .seek (0 )
233251
@@ -236,25 +254,25 @@ def login(self):
236254 with sem :
237255 for ntlm_hash in self .args .hash :
238256 if type (ntlm_hash ) is not file :
239- if not self .over_fail_limit ():
257+ if not self .over_fail_limit (user ):
240258 if self .hash_login (self .domain , user , ntlm_hash ): return
241259
242260 elif type (ntlm_hash ) is file :
243261 for f_hash in ntlm_hash :
244- if not self .over_fail_limit ():
262+ if not self .over_fail_limit (user ):
245263 if self .hash_login (self .domain , user , f_hash .strip ()): return
246264 ntlm_hash .seek (0 )
247265
248266 elif self .args .password :
249267 with sem :
250268 for password in self .args .password :
251269 if type (password ) is not file :
252- if not self .over_fail_limit ():
270+ if not self .over_fail_limit (user ):
253271 if self .plaintext_login (self .domain , user , password ): return
254272
255273 elif type (password ) is file :
256274 for f_pass in password :
257- if not self .over_fail_limit ():
275+ if not self .over_fail_limit (user ):
258276 if self .plaintext_login (self .domain , user , f_pass .strip ()): return
259277 password .seek (0 )
260278
0 commit comments