77See the file 'doc/COPYING' for copying permission
88"""
99
10+ import re
11+ import time
12+
1013from hashlib import md5
1114from hashlib import sha1
15+ from zipfile import ZipFile
1216
1317from extra .pydes .pyDes import des
1418from extra .pydes .pyDes import CBC
19+ from lib .core .common import conf
20+ from lib .core .common import dataToStdout
21+ from lib .core .common import getFileItems
22+ from lib .core .common import paths
23+ from lib .core .common import readInput
1524from lib .core .convert import hexdecode
1625from lib .core .convert import hexencode
26+ from lib .core .data import kb
27+ from lib .core .data import logger
28+ from lib .core .enums import DBMS
29+ from lib .core .enums import HASH
1730
1831def mysql_passwd (password , uppercase = True ):
1932 """
@@ -126,8 +139,8 @@ def oracle_old_passwd(password, username, uppercase=True): # prior to version '1
126139 >>> oracle_old_passwd(password='tiger', username='scott', uppercase=True)
127140 'F894844C34402B67'
128141 """
129-
130142 IV , pad = "\0 " * 8 , "\0 "
143+ username = unicode .encode (username , conf .dataEncoding ) #pyDes has issues with unicode strings
131144 unistr = "" .join ("\0 %s" % c for c in (username + password ).upper ())
132145
133146 cipher = des (hexdecode ("0123456789ABCDEF" ), CBC , IV , pad )
@@ -138,3 +151,115 @@ def oracle_old_passwd(password, username, uppercase=True): # prior to version '1
138151 retVal = hexencode (encrypted [- 8 :])
139152
140153 return retVal .upper () if uppercase else retVal .lower ()
154+
155+ def md5_generic_passwd (password , uppercase = False ):
156+ """
157+ >>> md5_generic_passwd(password='testpass', uppercase=False)
158+ '179ad45c6ce2cb97cf1029e212046e81'
159+ """
160+
161+ retVal = md5 (password ).hexdigest ()
162+
163+ return retVal .upper () if uppercase else retVal .lower ()
164+
165+ def sha1_generic_passwd (password , uppercase = False ):
166+ """
167+ >>> sha1_generic_passwd(password='testpass', uppercase=False)
168+ '206c80413b9a96c1312cc346b7d2517b84463edd'
169+ """
170+
171+ retVal = sha1 (password ).hexdigest ()
172+
173+ return retVal .upper () if uppercase else retVal .lower ()
174+
175+ __functions__ = {
176+ HASH .MYSQL : mysql_passwd , HASH .MYSQL_OLD : mysql_old_passwd , HASH .POSTGRES : postgres_passwd ,
177+ HASH .MSSQL : mssql_passwd , HASH .MSSQL_OLD : mssql_old_passwd , HASH .ORACLE : oracle_passwd ,
178+ HASH .ORACLE_OLD : oracle_old_passwd , HASH .MD5_GENERIC : md5_generic_passwd , HASH .SHA1_GENERIC : sha1_generic_passwd
179+ }
180+
181+ def dictionaryAttack ():
182+ rehash = None
183+ attack_info = []
184+ results = []
185+
186+ for (_ , hashes ) in kb .data .cachedUsersPasswords .items ():
187+ for hash_ in hashes :
188+ if not hash_ :
189+ continue
190+
191+ hash_ = hash_ .split ()[0 ]
192+
193+ for regex in HASH .__all__ :
194+ if re .match (regex , hash_ ):
195+ rehash = regex
196+ break
197+
198+ if rehash :
199+ for (user , hashes ) in kb .data .cachedUsersPasswords .items ():
200+ for hash_ in hashes :
201+ if not hash_ :
202+ continue
203+
204+ hash_ = hash_ .split ()[0 ]
205+
206+ if re .match (rehash , hash_ ):
207+ hash_ = hash_ .lower ()
208+
209+ if rehash in (HASH .MYSQL , HASH .MYSQL_OLD , HASH .MD5_GENERIC , HASH .SHA1_GENERIC ) and kb .dbms != DBMS .ORACLE :
210+ attack_info .append ([(user , hash_ ), {}])
211+ elif rehash in (HASH .ORACLE_OLD , HASH .POSTGRES ):
212+ attack_info .append ([(user , hash_ ), {'username' : user }])
213+ elif rehash in (HASH .ORACLE ):
214+ attack_info .append ([(user , hash_ ), {'salt' : hash_ [- 20 :]}])
215+ elif rehash in (HASH .MSSQL , HASH .MSSQL_OLD ):
216+ attack_info .append ([(user , hash_ ), {'salt' : hash_ [6 :14 ]}])
217+
218+ infoMsg = "loading dictionary from: '%s'" % paths .WORDLIST_TXT
219+ logger .info (infoMsg )
220+ wordlist = getFileItems (paths .WORDLIST_TXT , None , False )
221+
222+ infoMsg = "running dictionary attack"
223+ logger .info (infoMsg )
224+
225+ length = len (wordlist )
226+
227+ if rehash in (HASH .MYSQL , HASH .MYSQL_OLD , HASH .MD5_GENERIC , HASH .SHA1_GENERIC ) and kb .dbms != DBMS .ORACLE :
228+ count = 0
229+ for word in wordlist :
230+ count += 1
231+ current = __functions__ [rehash ](password = word , uppercase = False )
232+ for item in attack_info :
233+ ((user , hash_ ), _ ) = item
234+
235+ if count % 1117 == 0 or count == length :
236+ status = '%d/%d words (%d%s)' % (count , length , round (100.0 * count / length ), '%' )
237+ dataToStdout ("\r [%s] [INFO] %s" % (time .strftime ("%X" ), status ), True )
238+
239+ if hash_ == current :
240+ results .append ((user , hash_ , word ))
241+ #dataToStdout("\r[%s] [INFO] found: %s:%s\n" % (time.strftime("%X"), user, word), True)
242+ attack_info .remove (item )
243+
244+ else :
245+ for ((user , hash_ ), kwargs ) in attack_info :
246+ count = 0
247+ for word in wordlist :
248+ current = __functions__ [rehash ](password = word , uppercase = False , ** kwargs )
249+
250+ count += 1
251+ if count % 1117 == 0 or count == length :
252+ status = '%d/%d words (%d%s)' % (count , length , round (100.0 * count / length ), '%' )
253+ dataToStdout ("\r [%s] [INFO] %s" % (time .strftime ("%X" ), status ), True )
254+
255+ if hash_ == current :
256+ results .append ((user , hash_ , word ))
257+ #dataToStdout("\r[%s] [INFO] found: %s:%s\n" % (time.strftime("%X"), user, word), True)
258+ break
259+
260+ dataToStdout ("\n " , True )
261+ blank = " "
262+ for (user , hash_ , password ) in results :
263+ for i in xrange (len (kb .data .cachedUsersPasswords [user ])):
264+ if kb .data .cachedUsersPasswords [user ][i ] and hash_ .lower () in kb .data .cachedUsersPasswords [user ][i ].lower ():
265+ kb .data .cachedUsersPasswords [user ][i ] += "%s%spassword: %s" % ('\n ' if kb .data .cachedUsersPasswords [user ][i ][- 1 ] != '\n ' else '' , blank , password )
0 commit comments