Adding support for generic phpass (Wordpress, Drupal, PHPBB3, etc.) (Issue #4252)

This commit is contained in:
Miroslav Stampar 2020-07-01 12:46:26 +02:00
parent 459130196a
commit 0094f02fb0
3 changed files with 25 additions and 12 deletions

View File

@ -177,7 +177,7 @@ class HASH(object):
SHA512_GENERIC = r'(?i)\A(0x)?[0-9a-f]{128}\Z' SHA512_GENERIC = r'(?i)\A(0x)?[0-9a-f]{128}\Z'
CRYPT_GENERIC = r'\A(?!\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\Z)(?![0-9]+\Z)[./0-9A-Za-z]{13}\Z' CRYPT_GENERIC = r'\A(?!\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\Z)(?![0-9]+\Z)[./0-9A-Za-z]{13}\Z'
JOOMLA = r'\A[0-9a-f]{32}:\w{32}\Z' JOOMLA = r'\A[0-9a-f]{32}:\w{32}\Z'
WORDPRESS = r'\A\$P\$[./0-9a-zA-Z]{31}\Z' PHPASS = r'\A\$[PHQS]\$[./0-9a-zA-Z]{31}\Z'
APACHE_MD5_CRYPT = r'\A\$apr1\$.{1,8}\$[./a-zA-Z0-9]+\Z' APACHE_MD5_CRYPT = r'\A\$apr1\$.{1,8}\$[./a-zA-Z0-9]+\Z'
UNIX_MD5_CRYPT = r'\A\$1\$.{1,8}\$[./a-zA-Z0-9]+\Z' UNIX_MD5_CRYPT = r'\A\$1\$.{1,8}\$[./a-zA-Z0-9]+\Z'
APACHE_SHA1 = r'\A\{SHA\}[a-zA-Z0-9+/]+={0,2}\Z' APACHE_SHA1 = r'\A\{SHA\}[a-zA-Z0-9+/]+={0,2}\Z'

View File

@ -18,7 +18,7 @@ from lib.core.enums import OS
from thirdparty.six import unichr as _unichr from thirdparty.six import unichr as _unichr
# sqlmap version (<major>.<minor>.<month>.<monthly commit>) # sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.4.7.0" VERSION = "1.4.7.1"
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable" TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34} TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE) VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)

View File

@ -33,6 +33,7 @@ else:
import base64 import base64
import binascii import binascii
import gc import gc
import math
import os import os
import re import re
import tempfile import tempfile
@ -481,14 +482,20 @@ def vbulletin_passwd(password, salt, **kwargs):
return "%s:%s" % (md5(binascii.hexlify(md5(getBytes(password)).digest()) + getBytes(salt)).hexdigest(), salt) return "%s:%s" % (md5(binascii.hexlify(md5(getBytes(password)).digest()) + getBytes(salt)).hexdigest(), salt)
def wordpress_passwd(password, salt, count, prefix, **kwargs): def phpass_passwd(password, salt, count, prefix, **kwargs):
""" """
Reference(s): Reference(s):
https://web.archive.org/web/20120219120128/packetstormsecurity.org/files/74448/phpassbrute.py.txt https://web.archive.org/web/20120219120128/packetstormsecurity.org/files/74448/phpassbrute.py.txt
http://scriptserver.mainframe8.com/wordpress_password_hasher.php http://scriptserver.mainframe8.com/wordpress_password_hasher.php
https://www.openwall.com/phpass/
https://github.com/jedie/django-phpBB3/blob/master/django_phpBB3/hashers.py
>>> wordpress_passwd(password='testpass', salt='aD9ZLmkp', count=2048, prefix='$P$9aD9ZLmkp') >>> phpass_passwd(password='testpass', salt='aD9ZLmkp', count=2048, prefix='$P$')
'$P$9aD9ZLmkpsN4A83G8MefaaP888gVKX0' '$P$9aD9ZLmkpsN4A83G8MefaaP888gVKX0'
>>> phpass_passwd(password='testpass', salt='Pb1j9gSb', count=2048, prefix='$H$')
'$H$9Pb1j9gSb/u3EVQ.4JDZ3LqtN44oIx/'
>>> phpass_passwd(password='testpass', salt='iwtD/g.K', count=128, prefix='$S$')
'$S$5iwtD/g.KZT2rwC9DASy/mGYAThkSd3lBFdkONi1Ig1IEpBpqG8W'
""" """
def _encode64(input_, count): def _encode64(input_, count):
@ -523,18 +530,24 @@ def wordpress_passwd(password, salt, count, prefix, **kwargs):
return output return output
password = getBytes(password) password = getBytes(password)
salt = getBytes(salt) f = {"$P$": md5, "$H$": md5, "$Q$": sha1, "$S$": sha512}[prefix]
cipher = md5(salt) cipher = f(getBytes(salt))
cipher.update(password) cipher.update(password)
hash_ = cipher.digest() hash_ = cipher.digest()
for i in xrange(count): for i in xrange(count):
_ = md5(hash_) _ = f(hash_)
_.update(password) _.update(password)
hash_ = _.digest() hash_ = _.digest()
return "%s%s" % (prefix, _encode64(hash_, 16)) retVal = "%s%s%s%s" % (prefix, ITOA64[int(math.log(count, 2))], salt, _encode64(hash_, len(hash_)))
if prefix == "$S$":
# Reference: https://api.drupal.org/api/drupal/includes%21password.inc/constant/DRUPAL_HASH_LENGTH/7.x
retVal = retVal[:55]
return retVal
__functions__ = { __functions__ = {
HASH.MYSQL: mysql_passwd, HASH.MYSQL: mysql_passwd,
@ -555,7 +568,7 @@ __functions__ = {
HASH.JOOMLA: joomla_passwd, HASH.JOOMLA: joomla_passwd,
HASH.DJANGO_MD5: django_md5_passwd, HASH.DJANGO_MD5: django_md5_passwd,
HASH.DJANGO_SHA1: django_sha1_passwd, HASH.DJANGO_SHA1: django_sha1_passwd,
HASH.WORDPRESS: wordpress_passwd, HASH.PHPASS: phpass_passwd,
HASH.APACHE_MD5_CRYPT: unix_md5_passwd, HASH.APACHE_MD5_CRYPT: unix_md5_passwd,
HASH.UNIX_MD5_CRYPT: unix_md5_passwd, HASH.UNIX_MD5_CRYPT: unix_md5_passwd,
HASH.APACHE_SHA1: apache_sha1_passwd, HASH.APACHE_SHA1: apache_sha1_passwd,
@ -965,7 +978,7 @@ def dictionaryAttack(attack_dict):
try: try:
item = None item = None
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): 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):
hash_ = hash_.lower() hash_ = hash_.lower()
if hash_regex in (HASH.MD5_BASE64, HASH.SHA1_BASE64, HASH.SHA256_BASE64, HASH.SHA512_BASE64): if hash_regex in (HASH.MD5_BASE64, HASH.SHA1_BASE64, HASH.SHA256_BASE64, HASH.SHA512_BASE64):
@ -994,9 +1007,9 @@ def dictionaryAttack(attack_dict):
item = [(user, hash_), {"salt": hash_.split(':')[-1]}] item = [(user, hash_), {"salt": hash_.split(':')[-1]}]
elif hash_regex in (HASH.DJANGO_MD5, HASH.DJANGO_SHA1): elif hash_regex in (HASH.DJANGO_MD5, HASH.DJANGO_SHA1):
item = [(user, hash_), {"salt": hash_.split('$')[1]}] item = [(user, hash_), {"salt": hash_.split('$')[1]}]
elif hash_regex in (HASH.WORDPRESS,): elif hash_regex in (HASH.PHPASS,):
if ITOA64.index(hash_[3]) < 32: if ITOA64.index(hash_[3]) < 32:
item = [(user, hash_), {"salt": hash_[4:12], "count": 1 << ITOA64.index(hash_[3]), "prefix": hash_[:12]}] item = [(user, hash_), {"salt": hash_[4:12], "count": 1 << ITOA64.index(hash_[3]), "prefix": hash_[:3]}]
else: else:
warnMsg = "invalid hash '%s'" % hash_ warnMsg = "invalid hash '%s'" % hash_
logger.warn(warnMsg) logger.warn(warnMsg)