88from impacket .dcerpc .v5 import transport , scmr
99from impacket .dcerpc .v5 .rpcrt import DCERPCException
1010from impacket .smbconnection import SessionError
11+ from gevent .coros import BoundedSemaphore
12+
13+ sem = BoundedSemaphore (1 )
14+ global_failed_logins = 0
1115
1216class Connection :
1317
@@ -24,9 +28,21 @@ def __init__(self, args, db, target, server_name, domain, conn, logger, cmeserve
2428 self .username = None
2529 self .hash = None
2630 self .admin_privs = False
31+ self .failed_logins = 0
32+
33+ if self .args .local_auth :
34+ self .domain = self .hostname
2735
2836 self .login ()
2937
38+ def over_fail_limit (self ):
39+ global global_failed_logins
40+
41+ if global_failed_logins == self .args .gfail_limit : return True
42+ if self .failed_logins == self .args .fail_limit : return True
43+
44+ return False
45+
3046 def check_if_admin (self ):
3147 if self .args .mssql :
3248 try :
@@ -79,26 +95,27 @@ def check_if_admin(self):
7995 except DCERPCException :
8096 pass
8197
82- def plaintext_login (self , username , password ):
98+ def plaintext_login (self , domain , username , password ):
8399 try :
84100 if self .args .mssql :
85- res = self .conn .login (None , username , password , self . domain , None , True )
101+ res = self .conn .login (None , username , password , domain , None , True )
86102 if res is not True :
87103 self .conn .printReplies ()
88104 return False
89105
90106 elif not self .args .mssql :
91- self .conn .login (username , password , self . domain )
107+ self .conn .login (username , password , domain )
92108
93109 self .password = password
94110 self .username = username
111+ self .domain = domain
95112 self .check_if_admin ()
96- self .db .add_credential ('plaintext' , self . domain , username , password )
113+ self .db .add_credential ('plaintext' , domain , username , password )
97114
98115 if self .admin_privs :
99- self .db .link_cred_to_host ('plaintext' , self . domain , username , password , self .host )
116+ self .db .link_cred_to_host ('plaintext' , domain , username , password , self .host )
100117
101- out = u'{}\\ {}:{} {}' .format (self . domain .decode ('utf-8' ),
118+ out = u'{}\\ {}:{} {}' .format (domain .decode ('utf-8' ),
102119 username .decode ('utf-8' ),
103120 password .decode ('utf-8' ),
104121 highlight ('(Pwn3d!)' ) if self .admin_privs else '' )
@@ -107,14 +124,18 @@ def plaintext_login(self, username, password):
107124 return True
108125 except SessionError as e :
109126 error , desc = e .getErrorString ()
110- self .logger .error (u'{}\\ {}:{} {} {}' .format (self .domain .decode ('utf-8' ),
127+ if error == 'STATUS_LOGON_FAILURE' :
128+ global global_failed_logins ; global_failed_logins += 1
129+ self .failed_logins += 1
130+
131+ self .logger .error (u'{}\\ {}:{} {} {}' .format (domain .decode ('utf-8' ),
111132 username .decode ('utf-8' ),
112133 password .decode ('utf-8' ),
113134 error ,
114135 '({})' .format (desc ) if self .args .verbose else '' ))
115136 return False
116137
117- def hash_login (self , username , ntlm_hash ):
138+ def hash_login (self , domain , username , ntlm_hash ):
118139 lmhash = ''
119140 nthash = ''
120141
@@ -126,23 +147,24 @@ def hash_login(self, username, ntlm_hash):
126147
127148 try :
128149 if self .args .mssql :
129- res = self .conn .login (None , username , '' , self . domain , ntlm_hash , True )
150+ res = self .conn .login (None , username , '' , domain , ntlm_hash , True )
130151 if res is not True :
131152 self .conn .printReplies ()
132153 return False
133154
134155 elif not self .args .mssql :
135- self .conn .login (username , '' , self . domain , lmhash , nthash )
156+ self .conn .login (username , '' , domain , lmhash , nthash )
136157
137158 self .hash = ntlm_hash
138159 self .username = username
160+ self .domain = domain
139161 self .check_if_admin ()
140- self .db .add_credential ('hash' , self . domain , username , ntlm_hash )
162+ self .db .add_credential ('hash' , domain , username , ntlm_hash )
141163
142164 if self .admin_privs :
143- self .db .link_cred_to_host ('hash' , self . domain , username , ntlm_hash , self .host )
165+ self .db .link_cred_to_host ('hash' , domain , username , ntlm_hash , self .host )
144166
145- out = u'{}\\ {} {} {}' .format (self . domain .decode ('utf-8' ),
167+ out = u'{}\\ {} {} {}' .format (domain .decode ('utf-8' ),
146168 username .decode ('utf-8' ),
147169 ntlm_hash ,
148170 highlight ('(Pwn3d!)' ) if self .admin_privs else '' )
@@ -151,64 +173,90 @@ def hash_login(self, username, ntlm_hash):
151173 return True
152174 except SessionError as e :
153175 error , desc = e .getErrorString ()
154- self .logger .error (u'{}\\ {} {} {} {}' .format (self .domain .decode ('utf-8' ),
176+ if error == 'STATUS_LOGON_FAILURE' :
177+ global global_failed_logins ; global_failed_logins += 1
178+ self .failed_logins += 1
179+
180+ self .logger .error (u'{}\\ {} {} {} {}' .format (domain .decode ('utf-8' ),
155181 username .decode ('utf-8' ),
156182 ntlm_hash ,
157183 error ,
158184 '({})' .format (desc ) if self .args .verbose else '' ))
159185 return False
160186
161187 def login (self ):
162- if self .args .local_auth :
163- self .domain = self .hostname
188+ for cred_id in self .args .cred_id :
189+ with sem :
190+ try :
191+ c_id , credtype , domain , username , password = self .db .get_credentials (filterTerm = cred_id )[0 ]
164192
165- for user in self .args .username :
193+ if not domain : domain = self .domain
194+ if self .args .domain : domain = self .args .domain
166195
167- if type (user ) is file :
196+ if credtype == 'hash' and not self .over_fail_limit ():
197+ self .hash_login (domain , username , password )
168198
169- for usr in user :
199+ elif credtype == 'plaintext' and not self .over_fail_limit ():
200+ self .plaintext_login (domain , username , password )
201+
202+ except IndexError :
203+ self .logger .error ("Invalid database credential ID!" )
170204
205+ for user in self .args .username :
206+ if type (user ) is file :
207+ for usr in user :
171208 if self .args .hash :
172- for ntlm_hash in self .args .hash :
173- if type (ntlm_hash ) is not file :
174- if self .hash_login (usr .strip (), ntlm_hash ): return
209+ with sem :
210+ for ntlm_hash in self .args .hash :
211+ if type (ntlm_hash ) is not file :
212+ if not self .over_fail_limit ():
213+ if self .hash_login (self .domain , usr .strip (), ntlm_hash ): return
175214
176- elif type (ntlm_hash ) is file :
177- for f_hash in ntlm_hash :
178- if self .hash_login (usr .strip (), f_hash .strip ()): return
179- ntlm_hash .seek (0 )
215+ elif type (ntlm_hash ) is file :
216+ for f_hash in ntlm_hash :
217+ if not self .over_fail_limit ():
218+ if self .hash_login (self .domain , usr .strip (), f_hash .strip ()): return
219+ ntlm_hash .seek (0 )
180220
181221 elif self .args .password :
182- for password in self .args .password :
183- if type (password ) is not file :
184- if self .plaintext_login (usr .strip (), password ): return
185-
186- elif type (password ) is file :
187- for f_pass in password :
188- if self .plaintext_login (usr .strip (), f_pass .strip ()): return
189- password .seek (0 )
222+ with sem :
223+ for password in self .args .password :
224+ if type (password ) is not file :
225+ if not self .over_fail_limit ():
226+ if self .plaintext_login (self .domain , usr .strip (), password ): return
227+
228+ elif type (password ) is file :
229+ for f_pass in password :
230+ if not self .over_fail_limit ():
231+ if self .plaintext_login (self .domain , usr .strip (), f_pass .strip ()): return
232+ password .seek (0 )
190233
191234 elif type (user ) is not file :
192-
193235 if self .args .hash :
194- for ntlm_hash in self .args .hash :
195- if type (ntlm_hash ) is not file :
196- if self .hash_login (user , ntlm_hash ): return
197-
198- elif type (ntlm_hash ) is file :
199- for f_hash in ntlm_hash :
200- if self .hash_login (user , f_hash .strip ()): return
201- ntlm_hash .seek (0 )
236+ with sem :
237+ for ntlm_hash in self .args .hash :
238+ if type (ntlm_hash ) is not file :
239+ if not self .over_fail_limit ():
240+ if self .hash_login (self .domain , user , ntlm_hash ): return
241+
242+ elif type (ntlm_hash ) is file :
243+ for f_hash in ntlm_hash :
244+ if not self .over_fail_limit ():
245+ if self .hash_login (self .domain , user , f_hash .strip ()): return
246+ ntlm_hash .seek (0 )
202247
203248 elif self .args .password :
204- for password in self .args .password :
205- if type (password ) is not file :
206- if self .plaintext_login (user , password ): return
207-
208- elif type (password ) is file :
209- for f_pass in password :
210- if self .plaintext_login (user , f_pass .strip ()): return
211- password .seek (0 )
249+ with sem :
250+ for password in self .args .password :
251+ if type (password ) is not file :
252+ if not self .over_fail_limit ():
253+ if self .plaintext_login (self .domain , user , password ): return
254+
255+ elif type (password ) is file :
256+ for f_pass in password :
257+ if not self .over_fail_limit ():
258+ if self .plaintext_login (self .domain , user , f_pass .strip ()): return
259+ password .seek (0 )
212260
213261 def execute (self , payload , get_output = False , methods = None ):
214262
0 commit comments