5858from lib .core .exception import sqlmapFilePathException
5959from lib .core .exception import sqlmapUserQuitException
6060from lib .core .settings import COMMON_PASSWORD_SUFFIXES
61+ from lib .core .settings import COMMON_USER_COLUMNS
6162from lib .core .settings import DUMMY_USER_PREFIX
6263from lib .core .settings import GENERAL_IP_ADDRESS_REGEX
6364from lib .core .settings import HASH_MOD_ITEM_DISPLAY
6465from lib .core .settings import IS_WIN
66+ from lib .core .settings import ITOA64
6567from lib .core .settings import PYVERSION
6668from lib .core .settings import ML
6769from lib .core .settings import UNICODE_ENCODING
@@ -214,6 +216,7 @@ def sha1_generic_passwd(password, uppercase=False):
214216
215217 return retVal .upper () if uppercase else retVal .lower ()
216218
219+
217220def crypt_generic_passwd (password , salt , uppercase = False ):
218221 """
219222 Reference(s):
@@ -230,6 +233,60 @@ def crypt_generic_passwd(password, salt, uppercase=False):
230233
231234 return retVal .upper () if uppercase else retVal
232235
236+ def wordpress_passwd (password , salt , count , prefix , uppercase = False ):
237+ """
238+ Reference(s):
239+ http://packetstormsecurity.org/files/74448/phpassbrute.py.txt
240+ http://scriptserver.mainframe8.com/wordpress_password_hasher.php
241+
242+ >>> wordpress_passwd(password='testpass', salt='dYPSjeF4', count=2048)
243+ ''
244+ """
245+
246+ def _encode64 (input_ , count ):
247+ output = ''
248+ i = 0
249+
250+ while i < count :
251+ value = ord (input_ [i ])
252+ i += 1
253+ output = output + ITOA64 [value & 0x3f ]
254+
255+ if i < count :
256+ value = value | (ord (input_ [i ]) << 8 )
257+
258+ output = output + ITOA64 [(value >> 6 ) & 0x3f ]
259+
260+ i += 1
261+ if i >= count :
262+ break
263+
264+ if i < count :
265+ value = value | (ord (input_ [i ]) << 16 )
266+
267+ output = output + ITOA64 [(value >> 12 ) & 0x3f ]
268+
269+ i += 1
270+ if i >= count :
271+ break
272+
273+ output = output + ITOA64 [(value >> 18 ) & 0x3f ]
274+
275+ return output
276+
277+ cipher = md5 (salt )
278+ cipher .update (password )
279+ hash_ = cipher .digest ()
280+
281+ for i in xrange (count ):
282+ _ = md5 (hash_ )
283+ _ .update (password )
284+ hash_ = _ .digest ()
285+
286+ retVal = prefix + _encode64 (hash_ , 16 )
287+
288+ return retVal .upper () if uppercase else retVal
289+
233290__functions__ = {
234291 HASH .MYSQL : mysql_passwd ,
235292 HASH .MYSQL_OLD : mysql_old_passwd ,
@@ -240,7 +297,8 @@ def crypt_generic_passwd(password, salt, uppercase=False):
240297 HASH .ORACLE_OLD : oracle_old_passwd ,
241298 HASH .MD5_GENERIC : md5_generic_passwd ,
242299 HASH .SHA1_GENERIC : sha1_generic_passwd ,
243- HASH .CRYPT_GENERIC : crypt_generic_passwd
300+ HASH .CRYPT_GENERIC : crypt_generic_passwd ,
301+ HASH .WORDPRESS : wordpress_passwd
244302 }
245303
246304def attackCachedUsersPasswords ():
@@ -268,7 +326,7 @@ def attackDumpedTable():
268326 attack_dict = {}
269327
270328 for column in columns :
271- if column and column .lower () in ( 'user' , 'username' , 'user_name' ) :
329+ if column and column .lower () in COMMON_USER_COLUMNS :
272330 colUser = column
273331 break
274332
@@ -385,7 +443,7 @@ def __bruteProcessVariantA(attack_info, hash_regex, wordlist, suffix, retVal, pr
385443
386444 attack_info .remove (item )
387445
388- elif proc_id == 0 and count % HASH_MOD_ITEM_DISPLAY == 0 or hash_regex == HASH .ORACLE_OLD or hash_regex == HASH .CRYPT_GENERIC and IS_WIN :
446+ elif ( proc_id == 0 or getattr ( proc_count , 'value' , 0 ) == 1 ) and count % HASH_MOD_ITEM_DISPLAY == 0 or hash_regex == HASH .ORACLE_OLD or hash_regex == HASH .CRYPT_GENERIC and IS_WIN :
389447 rotator += 1
390448 if rotator >= len (ROTATING_CHARS ):
391449 rotator = 0
@@ -404,6 +462,10 @@ def __bruteProcessVariantA(attack_info, hash_regex, wordlist, suffix, retVal, pr
404462 except KeyboardInterrupt :
405463 pass
406464
465+ finally :
466+ if hasattr (proc_count , 'value' ):
467+ proc_count .value -= 1
468+
407469def __bruteProcessVariantB (user , hash_ , kwargs , hash_regex , wordlist , suffix , retVal , found , proc_id , proc_count ):
408470 count = 0
409471 rotator = 0
@@ -441,7 +503,8 @@ def __bruteProcessVariantB(user, hash_, kwargs, hash_regex, wordlist, suffix, re
441503 dataToStdout (infoMsg , True )
442504
443505 found .value = True
444- elif proc_id == 0 and count % HASH_MOD_ITEM_DISPLAY == 0 or hash_regex == HASH .ORACLE_OLD or hash_regex == HASH .CRYPT_GENERIC and IS_WIN :
506+
507+ elif (proc_id == 0 or getattr (proc_count , 'value' , 0 ) == 1 ) and count % HASH_MOD_ITEM_DISPLAY == 0 or hash_regex == HASH .ORACLE_OLD or hash_regex == HASH .CRYPT_GENERIC and IS_WIN :
445508 rotator += 1
446509 if rotator >= len (ROTATING_CHARS ):
447510 rotator = 0
@@ -461,6 +524,9 @@ def __bruteProcessVariantB(user, hash_, kwargs, hash_regex, wordlist, suffix, re
461524 except KeyboardInterrupt :
462525 pass
463526
527+ finally :
528+ if hasattr (proc_count , 'value' ):
529+ proc_count .value -= 1
464530
465531def dictionaryAttack (attack_dict ):
466532 suffix_list = ["" ]
@@ -491,11 +557,14 @@ def dictionaryAttack(attack_dict):
491557 if not hash_ :
492558 continue
493559
494- hash_ = hash_ .split ()[0 ]. lower ()
560+ hash_ = hash_ .split ()[0 ]
495561
496562 if getCompiledRegex (hash_regex ).match (hash_ ):
497563 item = None
498564
565+ if hash_regex not in (HASH .CRYPT_GENERIC , HASH .WORDPRESS ):
566+ hash_ = hash_ .lower ()
567+
499568 if hash_regex in (HASH .MYSQL , HASH .MYSQL_OLD , HASH .MD5_GENERIC , HASH .SHA1_GENERIC ):
500569 item = [(user , hash_ ), {}]
501570 elif hash_regex in (HASH .ORACLE_OLD , HASH .POSTGRES ):
@@ -506,6 +575,8 @@ def dictionaryAttack(attack_dict):
506575 item = [(user , hash_ ), {'salt' : hash_ [6 :14 ]}]
507576 elif hash_regex in (HASH .CRYPT_GENERIC ):
508577 item = [(user , hash_ ), {'salt' : hash_ [0 :2 ]}]
578+ elif hash_regex in (HASH .WORDPRESS ):
579+ item = [(user , hash_ ), {'salt' : hash_ [4 :12 ], 'count' : 1 << ITOA64 .index (hash_ [3 ]), 'prefix' : hash_ [:12 ]}]
509580
510581 if item and hash_ not in keys :
511582 resumed = conf .hashDB .retrieve (hash_ )
@@ -545,7 +616,7 @@ def dictionaryAttack(attack_dict):
545616 logger .info ("using custom list of dictionaries" )
546617 else :
547618 # It is the slowest of all methods hence smaller default dict
548- if hash_regex == HASH .ORACLE_OLD :
619+ if hash_regex in ( HASH .ORACLE_OLD , HASH . WORDPRESS ) :
549620 dictPaths = [paths .SMALL_DICT ]
550621 else :
551622 dictPaths = [paths .WORDLIST ]
@@ -602,8 +673,10 @@ def dictionaryAttack(attack_dict):
602673 singleTimeLogMessage (infoMsg )
603674
604675 retVal = _multiprocessing .Queue ()
676+ count = _multiprocessing .Value ('i' , _multiprocessing .cpu_count ())
677+
605678 for i in xrange (_multiprocessing .cpu_count ()):
606- p = _multiprocessing .Process (target = __bruteProcessVariantA , args = (attack_info , hash_regex , kb .wordlist , suffix , retVal , i , _multiprocessing . cpu_count () ))
679+ p = _multiprocessing .Process (target = __bruteProcessVariantA , args = (attack_info , hash_regex , kb .wordlist , suffix , retVal , i , count ))
607680 processes .append (p )
608681
609682 for p in processes :
@@ -671,9 +744,10 @@ def dictionaryAttack(attack_dict):
671744
672745 retVal = _multiprocessing .Queue ()
673746 found_ = _multiprocessing .Value ('i' , False )
747+ count = _multiprocessing .Value ('i' , _multiprocessing .cpu_count ())
674748
675749 for i in xrange (_multiprocessing .cpu_count ()):
676- p = _multiprocessing .Process (target = __bruteProcessVariantB , args = (user , hash_ , kwargs , hash_regex , kb .wordlist , suffix , retVal , found_ , i , _multiprocessing . cpu_count () ))
750+ p = _multiprocessing .Process (target = __bruteProcessVariantB , args = (user , hash_ , kwargs , hash_regex , kb .wordlist , suffix , retVal , found_ , i , count ))
677751 processes .append (p )
678752
679753 for p in processes :
0 commit comments