3333import base64
3434import binascii
3535import gc
36+ import math
3637import os
3738import re
3839import tempfile
@@ -481,14 +482,20 @@ def vbulletin_passwd(password, salt, **kwargs):
481482
482483 return "%s:%s" % (md5 (binascii .hexlify (md5 (getBytes (password )).digest ()) + getBytes (salt )).hexdigest (), salt )
483484
484- def wordpress_passwd (password , salt , count , prefix , ** kwargs ):
485+ def phpass_passwd (password , salt , count , prefix , ** kwargs ):
485486 """
486487 Reference(s):
487488 https://web.archive.org/web/20120219120128/packetstormsecurity.org/files/74448/phpassbrute.py.txt
488489 http://scriptserver.mainframe8.com/wordpress_password_hasher.php
490+ https://www.openwall.com/phpass/
491+ https://github.com/jedie/django-phpBB3/blob/master/django_phpBB3/hashers.py
489492
490- >>> wordpress_passwd (password='testpass', salt='aD9ZLmkp', count=2048, prefix='$P$9aD9ZLmkp ')
493+ >>> phpass_passwd (password='testpass', salt='aD9ZLmkp', count=2048, prefix='$P$')
491494 '$P$9aD9ZLmkpsN4A83G8MefaaP888gVKX0'
495+ >>> phpass_passwd(password='testpass', salt='Pb1j9gSb', count=2048, prefix='$H$')
496+ '$H$9Pb1j9gSb/u3EVQ.4JDZ3LqtN44oIx/'
497+ >>> phpass_passwd(password='testpass', salt='iwtD/g.K', count=128, prefix='$S$')
498+ '$S$5iwtD/g.KZT2rwC9DASy/mGYAThkSd3lBFdkONi1Ig1IEpBpqG8W'
492499 """
493500
494501 def _encode64 (input_ , count ):
@@ -523,18 +530,24 @@ def _encode64(input_, count):
523530 return output
524531
525532 password = getBytes (password )
526- salt = getBytes ( salt )
533+ f = { "$P$" : md5 , "$H$" : md5 , "$Q$" : sha1 , "$S$" : sha512 }[ prefix ]
527534
528- cipher = md5 ( salt )
535+ cipher = f ( getBytes ( salt ) )
529536 cipher .update (password )
530537 hash_ = cipher .digest ()
531538
532539 for i in xrange (count ):
533- _ = md5 (hash_ )
540+ _ = f (hash_ )
534541 _ .update (password )
535542 hash_ = _ .digest ()
536543
537- return "%s%s" % (prefix , _encode64 (hash_ , 16 ))
544+ retVal = "%s%s%s%s" % (prefix , ITOA64 [int (math .log (count , 2 ))], salt , _encode64 (hash_ , len (hash_ )))
545+
546+ if prefix == "$S$" :
547+ # Reference: https://api.drupal.org/api/drupal/includes%21password.inc/constant/DRUPAL_HASH_LENGTH/7.x
548+ retVal = retVal [:55 ]
549+
550+ return retVal
538551
539552__functions__ = {
540553 HASH .MYSQL : mysql_passwd ,
@@ -555,7 +568,7 @@ def _encode64(input_, count):
555568 HASH .JOOMLA : joomla_passwd ,
556569 HASH .DJANGO_MD5 : django_md5_passwd ,
557570 HASH .DJANGO_SHA1 : django_sha1_passwd ,
558- HASH .WORDPRESS : wordpress_passwd ,
571+ HASH .PHPASS : phpass_passwd ,
559572 HASH .APACHE_MD5_CRYPT : unix_md5_passwd ,
560573 HASH .UNIX_MD5_CRYPT : unix_md5_passwd ,
561574 HASH .APACHE_SHA1 : apache_sha1_passwd ,
@@ -965,7 +978,7 @@ def dictionaryAttack(attack_dict):
965978 try :
966979 item = None
967980
968- if hash_regex not in (HASH .CRYPT_GENERIC , HASH .JOOMLA , HASH .WORDPRESS , HASH .UNIX_MD5_CRYPT , HASH .APACHE_MD5_CRYPT , HASH .APACHE_SHA1 , HASH .VBULLETIN , HASH .VBULLETIN_OLD , HASH .SSHA , HASH .SSHA256 , HASH .SSHA512 , HASH .DJANGO_MD5 , HASH .DJANGO_SHA1 , HASH .MD5_BASE64 , HASH .SHA1_BASE64 , HASH .SHA256_BASE64 , HASH .SHA512_BASE64 ):
981+ if hash_regex not in (HASH .CRYPT_GENERIC , HASH .JOOMLA , HASH .PHPASS , HASH .UNIX_MD5_CRYPT , HASH .APACHE_MD5_CRYPT , HASH .APACHE_SHA1 , HASH .VBULLETIN , HASH .VBULLETIN_OLD , HASH .SSHA , HASH .SSHA256 , HASH .SSHA512 , HASH .DJANGO_MD5 , HASH .DJANGO_SHA1 , HASH .MD5_BASE64 , HASH .SHA1_BASE64 , HASH .SHA256_BASE64 , HASH .SHA512_BASE64 ):
969982 hash_ = hash_ .lower ()
970983
971984 if hash_regex in (HASH .MD5_BASE64 , HASH .SHA1_BASE64 , HASH .SHA256_BASE64 , HASH .SHA512_BASE64 ):
@@ -994,9 +1007,9 @@ def dictionaryAttack(attack_dict):
9941007 item = [(user , hash_ ), {"salt" : hash_ .split (':' )[- 1 ]}]
9951008 elif hash_regex in (HASH .DJANGO_MD5 , HASH .DJANGO_SHA1 ):
9961009 item = [(user , hash_ ), {"salt" : hash_ .split ('$' )[1 ]}]
997- elif hash_regex in (HASH .WORDPRESS ,):
1010+ elif hash_regex in (HASH .PHPASS ,):
9981011 if ITOA64 .index (hash_ [3 ]) < 32 :
999- item = [(user , hash_ ), {"salt" : hash_ [4 :12 ], "count" : 1 << ITOA64 .index (hash_ [3 ]), "prefix" : hash_ [:12 ]}]
1012+ item = [(user , hash_ ), {"salt" : hash_ [4 :12 ], "count" : 1 << ITOA64 .index (hash_ [3 ]), "prefix" : hash_ [:3 ]}]
10001013 else :
10011014 warnMsg = "invalid hash '%s'" % hash_
10021015 logger .warn (warnMsg )
0 commit comments