mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-07-03 06:51:08 +00:00
Adding more supported hash algorithms
This commit is contained in:
parent
a7c9b721fd
commit
d6299fc4f5
7 changed files with 394 additions and 17 deletions
|
|
@ -84,7 +84,7 @@ c8d467837c8567b61a11e2dfd75a2d8305a8b317041ee81eda6d0e47609dabb7 data/xml/paylo
|
|||
0648264166455010921df1ec431e4c973809f37ef12cbfea75f95029222eb689 data/xml/payloads/stacked_queries.xml
|
||||
379fc92f2dadd948f401e17490d8a8f03a1988d817323cbe1feff5fe87726079 data/xml/payloads/time_blind.xml
|
||||
40a4878669f318568097719d07dc906a19b8520bc742be3583321fc1e8176089 data/xml/payloads/union_query.xml
|
||||
45aa5280edc0412a217498bd229651ff9c55afab44d555507ee5bdc27531de82 data/xml/queries.xml
|
||||
ff99497d2f04a872e16e799183e6c8f2e16f3e69cddb336e29162f1e92ae45c7 data/xml/queries.xml
|
||||
127799739f9aeabca367027197f3c0240f141303bd7499928ccfa1443bf148c7 doc/ARCHITECTURE.md
|
||||
0f5a9c84cb57809be8759f483c7d05f54847115e715521ac0ecf390c0aa68465 doc/AUTHORS
|
||||
ce20a4b452f24a97fde7ec9ed816feee12ac148e1fde5f1722772cc866b12740 doc/CHANGELOG.md
|
||||
|
|
@ -177,19 +177,19 @@ f8de57606325456928e46ae2896f5f8bbec9ad18b1c644b492a566fa992216f6 lib/core/decor
|
|||
147823c37596bd6a56d677697781f34b8d1d1671d5a2518fbc9468d623c6d07d lib/core/defaults.py
|
||||
8e4f4b5ea37a49d445bb0df83bf04b34f61035ec33fd8acf598ebcf371cb19a7 lib/core/dicts.py
|
||||
b14628a6c9327d110afe50b01f3171f64f61823343b8de89596e854b00b74928 lib/core/dump.py
|
||||
6dd47f52082e98dc0cda6969b277b7d81c6f7c68dac4688821f873a1c65c6edf lib/core/enums.py
|
||||
c2db614a3ce7dda889152bea8bd6d709e5d8c2b556741fdbfe44469f27ce266b lib/core/enums.py
|
||||
5387168e5dfedd94ae22af7bb255f27d6baaca50b24179c6b98f4f325f5cc7b4 lib/core/exception.py
|
||||
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/core/__init__.py
|
||||
914a13ee21fd610a6153a37cbe50830fcbd1324c7ebc1e7fc206d5e598b0f7ad lib/core/log.py
|
||||
4fe3ac4c0d354d1ac42ad3f5dc1b308993588f8a249ff880d273f5031d6b52b0 lib/core/optiondict.py
|
||||
0235aa27d0c8cfe54180f2a003f749065d11bf167923a8189844efd45469c612 lib/core/option.py
|
||||
ca3d9185aa5418cdfc79f43beb4ad6f6503496763f349ecef57fff278bcfc8c8 lib/core/option.py
|
||||
21b2b1745107c211fc7593923a3da7a808d40763c00091c28de5f7c129bcf3bc lib/core/patch.py
|
||||
49c0fa7e3814dfda610d665ee02b12df299b28bc0b6773815b4395514ddf8dec lib/core/profiling.py
|
||||
0c36a65b6237732eb001d333f80f0c58c088ff01ae80cf07e4dcc6da2a806364 lib/core/readlineng.py
|
||||
9bf174058f15d14e24e94f9aaf42df045119d3617c6c54bd2f3af79b462f331d lib/core/replication.py
|
||||
0b8c38a01bb01f843d94a6c5f2075ee47520d0c4aa799cecea9c3e2c5a4a23a6 lib/core/revision.py
|
||||
888daba83fd4a34e9503fe21f01fef4cc730e5cde871b1d40e15d4cbc847d56c lib/core/session.py
|
||||
0b0a122d3ae6f64c2af2aab91b72ecf6573e9cc1fd250f41ba441be60d8dd464 lib/core/settings.py
|
||||
5fa3141353791446463a215a5481048346aa0f1dde08f1fe8fa6834a22aa23c1 lib/core/settings.py
|
||||
c7804223319e18eb0b8e2cbf0a8b6896d1cefb7b0b1a2e9f1cf826a8a3b56750 lib/core/shell.py
|
||||
a2e98a94b231432736d6b304fc75525c8b5fdb4768c418387c5b4c1a610dad64 lib/core/subprocessng.py
|
||||
15d36cdac9389d0a54a6c33fbb89f32bb65e303f50de573773dcb6d4618bca64 lib/core/target.py
|
||||
|
|
@ -211,7 +211,7 @@ c2f34e27578742e729c2fa9c1d4f0a0d8f8f7f4cf0fc14c62ec817a260c71dec lib/parse/site
|
|||
1be3da334411657461421b8a26a0f2ff28e1af1e28f1e963c6c92768f9b0847c lib/request/basicauthhandler.py
|
||||
a988c659e0c642e4f3dc4034118b5a6e138a522394ff2eda5bdc3c8495ea2207 lib/request/basic.py
|
||||
bc61bc944b81a7670884f82231033a6ac703324b34b071c9834886a92e249d0e lib/request/chunkedhandler.py
|
||||
9c0dccc1cee66d38478aaf75a7c513d0d136d50a90b15fed146faa1653899fe1 lib/request/comparison.py
|
||||
4fd1957e31b14e7670b09d85a634fa6772a1cd90babe149f39a1c945fe306f0a lib/request/comparison.py
|
||||
4a3b997a83b1724e8bd025be95ec5d84c6bf41d533ba097fcab1eab763352111 lib/request/connect.py
|
||||
8e06682280fce062eef6174351bfebcb6040e19976acff9dc7b3699779783498 lib/request/direct.py
|
||||
a6b37b436838caeb197fea858d0a39fadbff4736256e741b5fcec1f28fcf1ce0 lib/request/dns.py
|
||||
|
|
@ -263,7 +263,7 @@ bd9267d94390ba87d6c5a35c90f2406d6a4135a7c8ea01db76dd9e6519eee2ed lib/utils/dial
|
|||
3c4ad819589fe4fca303706dc87969273a07a04dee85e23f064b39caf1fb80e9 lib/utils/gui.py
|
||||
972c5db9c9e30ac0f91c0f8d4df4531d0304e151dac99f1399c37c952ba9f935 lib/utils/har.py
|
||||
0cd3860c03e39bacd1d0fe4cf1a0c605de48ff82f70441319f21d47e38e7e3a9 lib/utils/hashdb.py
|
||||
71a66ff766a2921106770b26acff380de469222dc893816a7b970b384c927666 lib/utils/hash.py
|
||||
f1f29dee813d08be77023543c45a4f3621ed26b1bbc133c020b618256663baaf lib/utils/hash.py
|
||||
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/utils/__init__.py
|
||||
1bbf57e43f921d4132e6e5a336ff39454a9506b36de94ebcc45879d0abcac56a lib/utils/keysetdump.py
|
||||
b57aa20b7a6fd8afd07bae773fd03f8acb05655ee605362b220e65a0664dc38d lib/utils/library.py
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@
|
|||
<!-- https://github.com/dev-sec/mysql-baseline/issues/35 -->
|
||||
<!-- https://stackoverflow.com/a/31122246 -->
|
||||
<passwords>
|
||||
<inband query="SELECT user,authentication_string FROM mysql.user" condition="user"/>
|
||||
<blind query="SELECT DISTINCT(authentication_string) FROM mysql.user WHERE user='%s' LIMIT %d,1" count="SELECT COUNT(DISTINCT(authentication_string)) FROM mysql.user WHERE user='%s'"/>
|
||||
<inband query="SELECT user,IF(LEFT(authentication_string,3)=0x244124,CONCAT(0x246d7973716c,LEFT(authentication_string,6),0x2a,INSERT(HEX(SUBSTR(authentication_string,8)),41,0,0x2a)),authentication_string) FROM mysql.user" condition="user"/>
|
||||
<blind query="SELECT DISTINCT(IF(LEFT(authentication_string,3)=0x244124,CONCAT(0x246d7973716c,LEFT(authentication_string,6),0x2a,INSERT(HEX(SUBSTR(authentication_string,8)),41,0,0x2a)),authentication_string)) FROM mysql.user WHERE user='%s' LIMIT %d,1" count="SELECT COUNT(DISTINCT(authentication_string)) FROM mysql.user WHERE user='%s'"/>
|
||||
</passwords>
|
||||
<privileges>
|
||||
<inband query="SELECT grantee,privilege_type FROM INFORMATION_SCHEMA.USER_PRIVILEGES" condition="grantee" query2="SELECT user,select_priv,insert_priv,update_priv,delete_priv,create_priv,drop_priv,reload_priv,shutdown_priv,process_priv,file_priv,grant_priv,references_priv,index_priv,alter_priv,show_db_priv,super_priv,create_tmp_table_priv,lock_tables_priv,execute_priv,repl_slave_priv,repl_client_priv,create_view_priv,show_view_priv,create_routine_priv,alter_routine_priv,create_user_priv FROM mysql.user" condition2="user"/>
|
||||
|
|
|
|||
|
|
@ -180,6 +180,8 @@ class HASH(object):
|
|||
MYSQL = r'(?i)\A\*[0-9a-f]{40}\Z'
|
||||
MYSQL_OLD = r'(?i)\A(?![0-9]+\Z)[0-9a-f]{16}\Z'
|
||||
POSTGRES = r'(?i)\Amd5[0-9a-f]{32}\Z'
|
||||
POSTGRES_SCRAM = r'\ASCRAM-SHA-256\$\d+:[A-Za-z0-9+/]+={0,2}\$[A-Za-z0-9+/]+={0,2}:[A-Za-z0-9+/]+={0,2}\Z'
|
||||
MYSQL_SHA2 = r'\A\$mysql\$A\$[0-9A-Fa-f]{3}\*[0-9A-Fa-f]{40}\*[0-9A-Fa-f]{86}\Z'
|
||||
MSSQL = r'(?i)\A0x0100[0-9a-f]{8}[0-9a-f]{40}\Z'
|
||||
MSSQL_OLD = r'(?i)\A0x0100[0-9a-f]{8}[0-9a-f]{80}\Z'
|
||||
MSSQL_NEW = r'(?i)\A0x0200[0-9a-f]{8}[0-9a-f]{128}\Z'
|
||||
|
|
@ -192,6 +194,8 @@ class HASH(object):
|
|||
SHA384_GENERIC = r'(?i)\A[0-9a-f]{96}\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'
|
||||
SHA256_UNIX_CRYPT = r'\A\$5\$(?:rounds=\d+\$)?[./0-9A-Za-z]{1,16}\$[./0-9A-Za-z]{43}\Z'
|
||||
SHA512_UNIX_CRYPT = r'\A\$6\$(?:rounds=\d+\$)?[./0-9A-Za-z]{1,16}\$[./0-9A-Za-z]{86}\Z'
|
||||
JOOMLA = r'\A[0-9a-f]{32}:\w{32}\Z'
|
||||
PHPASS = r'\A\$[PHQS]\$[./0-9a-zA-Z]{31}\Z'
|
||||
APACHE_MD5_CRYPT = r'\A\$apr1\$.{1,8}\$[./a-zA-Z0-9]+\Z'
|
||||
|
|
@ -205,6 +209,13 @@ class HASH(object):
|
|||
SSHA512 = r'\A\{SSHA512\}[a-zA-Z0-9+/]+={0,2}\Z'
|
||||
DJANGO_MD5 = r'\Amd5\$[^$]*\$[0-9a-f]{32}\Z'
|
||||
DJANGO_SHA1 = r'\Asha1\$[^$]*\$[0-9a-f]{40}\Z'
|
||||
DJANGO_PBKDF2_SHA256 = r'\Apbkdf2_sha256\$\d+\$[^$]+\$[A-Za-z0-9+/]+={0,2}\Z'
|
||||
WERKZEUG_PBKDF2 = r'\Apbkdf2:(?:sha1|sha256|sha512):\d+\$[^$]+\$[0-9a-f]+\Z'
|
||||
WERKZEUG_SCRYPT = r'\Ascrypt:\d+:\d+:\d+\$[^$]+\$[0-9a-f]+\Z'
|
||||
BCRYPT = r'\A\$2[abxy]\$\d{2}\$[./A-Za-z0-9]{53}\Z'
|
||||
WORDPRESS_BCRYPT = r'\A\$wp\$2[abxy]\$\d{2}\$[./A-Za-z0-9]{53}\Z'
|
||||
ARGON2 = r'\A\$argon2(?:id|i|d)\$v=\d+\$m=\d+,t=\d+,p=\d+\$[A-Za-z0-9+/]+={0,2}\$[A-Za-z0-9+/]+={0,2}\Z'
|
||||
ASPNET_IDENTITY = r'\AAQAAAA[A-Za-z0-9+/]{76}==\Z'
|
||||
MD5_BASE64 = r'\A[a-zA-Z0-9+/]{22}==\Z'
|
||||
SHA1_BASE64 = r'\A[a-zA-Z0-9+/]{27}=\Z'
|
||||
SHA256_BASE64 = r'\A[a-zA-Z0-9+/]{43}=\Z'
|
||||
|
|
|
|||
|
|
@ -870,6 +870,15 @@ def _setTamperingFunctions():
|
|||
warnMsg += "a good idea"
|
||||
logger.warning(warnMsg)
|
||||
|
||||
# tamper scripts rewrite SQL injection payloads; the self-contained non-SQL engines
|
||||
# (--graphql/--nosql/--ldap/--xpath/--ssti) do not run payloads through the tampering hook, so
|
||||
# warn instead of silently ignoring the user's '--tamper'
|
||||
if kb.tamperFunctions and any((conf.graphql, conf.nosql, conf.ldap, conf.xpath, conf.ssti)):
|
||||
engine = next(_ for _ in ("graphql", "nosql", "ldap", "xpath", "ssti") if conf.get(_))
|
||||
warnMsg = "tamper scripts are applied to SQL injection payloads only and "
|
||||
warnMsg += "will be ignored by the '--%s' engine" % engine
|
||||
logger.warning(warnMsg)
|
||||
|
||||
if resolve_priorities and priorities:
|
||||
priorities.sort(key=functools.cmp_to_key(lambda a, b: cmp(a[0], b[0])), reverse=True)
|
||||
kb.tamperFunctions = []
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ from lib.core.enums import OS
|
|||
from thirdparty import six
|
||||
|
||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||
VERSION = "1.10.7.15"
|
||||
VERSION = "1.10.7.16"
|
||||
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -39,15 +39,18 @@ from thirdparty import six
|
|||
|
||||
def _isJsonResponse(headers):
|
||||
"""
|
||||
Returns True if the response Content-Type indicates a JSON document (e.g. 'application/json'
|
||||
or a structured suffix like 'application/vnd.api+json')
|
||||
Returns True if the response Content-Type plausibly indicates a JSON document - i.e. the canonical
|
||||
'application/json', the common misservings ('text/json', 'application/javascript', ...), or a
|
||||
structured suffix like 'application/vnd.api+json'. Being liberal here is safe: jsonMinimize() returns
|
||||
None for anything that is not actually parseable JSON, so a mislabelled body simply falls back to the
|
||||
normal text comparison.
|
||||
"""
|
||||
|
||||
retVal = False
|
||||
|
||||
if headers:
|
||||
contentType = (headers.get(HTTP_HEADER.CONTENT_TYPE) or "").split(';')[0].strip().lower()
|
||||
retVal = contentType == "application/json" or contentType.endswith("+json")
|
||||
retVal = contentType in ("application/json", "text/json", "application/javascript", "text/javascript", "application/x-javascript") or contentType.endswith("+json")
|
||||
|
||||
return retVal
|
||||
|
||||
|
|
|
|||
|
|
@ -19,19 +19,27 @@ except:
|
|||
from thirdparty.pydes.pyDes import CBC
|
||||
from thirdparty.pydes.pyDes import des
|
||||
|
||||
try:
|
||||
from hashlib import scrypt as _scrypt # not available on Python 2 (added in 3.6)
|
||||
except ImportError:
|
||||
_scrypt = None
|
||||
|
||||
_multiprocessing = None
|
||||
|
||||
import base64
|
||||
import binascii
|
||||
import gc
|
||||
import hmac
|
||||
import math
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import tempfile
|
||||
import time
|
||||
import zipfile
|
||||
|
||||
from hashlib import md5
|
||||
from hashlib import pbkdf2_hmac
|
||||
from hashlib import sha1
|
||||
from hashlib import sha224
|
||||
from hashlib import sha256
|
||||
|
|
@ -146,6 +154,21 @@ def postgres_passwd(password, username, uppercase=False):
|
|||
|
||||
return retVal.upper() if uppercase else retVal.lower()
|
||||
|
||||
def postgres_scram_passwd(password, salt, iterations, **kwargs): # since version '10'
|
||||
"""
|
||||
Reference(s):
|
||||
https://www.rfc-editor.org/rfc/rfc5803
|
||||
|
||||
>>> postgres_scram_passwd(password='testpass', salt='c2FsdHNhbHRzYWx0', iterations=4096)
|
||||
'SCRAM-SHA-256$4096:c2FsdHNhbHRzYWx0$AzDKnszrCJPfdiFrFLbdoiqdocK4KWksHHcs3Jx7R5w=:lmWF1kOl/PbOyhpnGuBGzKyuP3XYMK6whWukBxHiHLc='
|
||||
"""
|
||||
|
||||
salted = pbkdf2_hmac("sha256", getBytes(password), decodeBase64(salt, binary=True), iterations)
|
||||
stored_key = sha256(hmac.new(salted, b"Client Key", sha256).digest()).digest()
|
||||
server_key = hmac.new(salted, b"Server Key", sha256).digest()
|
||||
|
||||
return "SCRAM-SHA-256$%d:%s$%s:%s" % (iterations, salt, getText(base64.b64encode(stored_key)), getText(base64.b64encode(server_key)))
|
||||
|
||||
def mssql_new_passwd(password, salt, uppercase=False): # since version '2012'
|
||||
"""
|
||||
Reference(s):
|
||||
|
|
@ -439,6 +462,243 @@ def unix_md5_passwd(password, salt, magic="$1$", **kwargs):
|
|||
|
||||
return getText(magic + salt + b'$' + getBytes(hash_))
|
||||
|
||||
# SHA-crypt (Drepper) final-permutation byte orders for the 32/64-byte digests
|
||||
_SHA256_CRYPT_ORDER = ((0, 10, 20), (21, 1, 11), (12, 22, 2), (3, 13, 23), (24, 4, 14), (15, 25, 5), (6, 16, 26), (27, 7, 17), (18, 28, 8), (9, 19, 29), (31, 30))
|
||||
_SHA512_CRYPT_ORDER = ((0, 21, 42), (22, 43, 1), (44, 2, 23), (3, 24, 45), (25, 46, 4), (47, 5, 26), (6, 27, 48), (28, 49, 7), (50, 8, 29), (9, 30, 51), (31, 52, 10), (53, 11, 32), (12, 33, 54), (34, 55, 13), (56, 14, 35), (15, 36, 57), (37, 58, 16), (59, 17, 38), (18, 39, 60), (40, 61, 19), (62, 20, 41), (63,))
|
||||
|
||||
def _shaCryptDigest(password, salt, rounds, digestmod, order):
|
||||
dsize = digestmod().digest_size
|
||||
|
||||
B = digestmod(password + salt + password).digest()
|
||||
|
||||
ctx = digestmod(password + salt)
|
||||
cnt = len(password)
|
||||
while cnt > dsize:
|
||||
ctx.update(B)
|
||||
cnt -= dsize
|
||||
ctx.update(B[:cnt])
|
||||
|
||||
i = len(password)
|
||||
while i:
|
||||
ctx.update(B if i & 1 else password)
|
||||
i >>= 1
|
||||
A = ctx.digest()
|
||||
|
||||
dp = digestmod()
|
||||
for _ in xrange(len(password)):
|
||||
dp.update(password)
|
||||
DP = dp.digest()
|
||||
P = DP * (len(password) // dsize) + DP[:len(password) % dsize]
|
||||
|
||||
ds = digestmod()
|
||||
for _ in xrange(16 + (A[0] if isinstance(A[0], int) else ord(A[0]))):
|
||||
ds.update(salt)
|
||||
DS = ds.digest()
|
||||
S = DS * (len(salt) // dsize) + DS[:len(salt) % dsize]
|
||||
|
||||
C = A
|
||||
for i in xrange(rounds):
|
||||
c = digestmod()
|
||||
c.update(P if i & 1 else C)
|
||||
if i % 3:
|
||||
c.update(S)
|
||||
if i % 7:
|
||||
c.update(P)
|
||||
c.update(C if i & 1 else P)
|
||||
C = c.digest()
|
||||
|
||||
retVal = ""
|
||||
for group in order:
|
||||
value = 0
|
||||
for idx in group:
|
||||
value = (value << 8) | (C[idx] if isinstance(C[idx], int) else ord(C[idx]))
|
||||
for _ in xrange((len(group) * 8 + 5) // 6):
|
||||
retVal += ITOA64[value & 0x3f]
|
||||
value >>= 6
|
||||
|
||||
return retVal
|
||||
|
||||
def sha2_crypt_passwd(password, salt, magic="$5$", **kwargs):
|
||||
"""
|
||||
Reference(s):
|
||||
https://www.akkadia.org/drepper/SHA-crypt.txt
|
||||
|
||||
>>> sha2_crypt_passwd(password='testpass', salt='saltstring', magic='$5$')
|
||||
'$5$saltstring$rn/td51LeVLXb2RR8WT672g4QhAuobh1gQQFGFiRCT.'
|
||||
>>> sha2_crypt_passwd(password='testpass', salt='saltstring', magic='$6$')
|
||||
'$6$saltstring$Oxduy3vBZ8CEBR5mER96ach5GlbbBT1Oz5g1UNdPqomx5bB1.IwS1ZFoW8fpb0xvz/BCS7.LzpkW7GAFOW9yC.'
|
||||
"""
|
||||
|
||||
rounds, saltstr = 5000, salt
|
||||
if salt.startswith("rounds="):
|
||||
prefix, saltstr = salt.split('$', 1)
|
||||
rounds = int(prefix[len("rounds="):])
|
||||
|
||||
order, digestmod = (_SHA256_CRYPT_ORDER, sha256) if magic == "$5$" else (_SHA512_CRYPT_ORDER, sha512)
|
||||
digest = _shaCryptDigest(getBytes(password), getBytes(saltstr)[:16], rounds, digestmod, order)
|
||||
|
||||
return "%s%s$%s" % (magic, salt, digest)
|
||||
|
||||
def mysql_sha2_passwd(password, salt, rounds, prefix, **kwargs): # MySQL 8 'caching_sha2_password' (sha256crypt, 20-byte salt)
|
||||
"""
|
||||
Reference(s):
|
||||
https://hashcat.net/wiki/doku.php?id=example_hashes
|
||||
|
||||
>>> mysql_sha2_passwd(password='hashcat', salt=decodeHex('F9CC98CE08892924F50A213B6BC571A2C11778C5'), rounds=5000, prefix='$mysql$A$005*F9CC98CE08892924F50A213B6BC571A2C11778C5*')
|
||||
'$mysql$A$005*F9CC98CE08892924F50A213B6BC571A2C11778C5*625479393559393965414D45316477456B484F41316E64484742577A2E3162785353526B7554584647562F'
|
||||
"""
|
||||
|
||||
digest = _shaCryptDigest(getBytes(password), bytes(salt), rounds, sha256, _SHA256_CRYPT_ORDER)
|
||||
|
||||
return "%s%s" % (prefix, getText(encodeHex(getBytes(digest), binary=False)).upper())
|
||||
|
||||
# bcrypt (Provos-Mazieres EksBlowfish); the Blowfish P/S init constants are the fractional hex digits of pi
|
||||
BCRYPT_ITOA64 = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
|
||||
_bcryptState = None
|
||||
|
||||
def _bcryptInitState():
|
||||
global _bcryptState
|
||||
|
||||
if _bcryptState is None:
|
||||
count = 18 + 4 * 256
|
||||
ndigits = count * 8
|
||||
prec = ndigits + 16
|
||||
one = 1 << (4 * prec)
|
||||
|
||||
def _arctan(inv):
|
||||
total = term = one // inv
|
||||
square = inv * inv
|
||||
i = 1
|
||||
while term:
|
||||
term //= square
|
||||
total += (term // (2 * i + 1)) * (-1 if i % 2 else 1)
|
||||
i += 1
|
||||
return total
|
||||
|
||||
frac = (16 * _arctan(5) - 4 * _arctan(239) - 3 * one) >> (4 * (prec - ndigits))
|
||||
hexstr = "%0*x" % (ndigits, frac)
|
||||
words = [int(hexstr[i * 8:(i + 1) * 8], 16) for i in xrange(count)]
|
||||
_bcryptState = (words[:18], [words[18 + i * 256:18 + (i + 1) * 256] for i in xrange(4)])
|
||||
|
||||
return _bcryptState
|
||||
|
||||
def _bcryptEncipher(P, S, L, R):
|
||||
for i in xrange(16):
|
||||
L ^= P[i]
|
||||
R ^= (((S[0][(L >> 24) & 0xff] + S[1][(L >> 16) & 0xff]) & 0xffffffff) ^ S[2][(L >> 8) & 0xff]) + S[3][L & 0xff] & 0xffffffff
|
||||
L, R = R, L
|
||||
L, R = R, L
|
||||
return (L ^ P[17]) & 0xffffffff, (R ^ P[16]) & 0xffffffff
|
||||
|
||||
def _bcryptStream(data, offset):
|
||||
word = 0
|
||||
for _ in xrange(4):
|
||||
word = ((word << 8) | data[offset[0]]) & 0xffffffff
|
||||
offset[0] = (offset[0] + 1) % len(data)
|
||||
return word
|
||||
|
||||
def _bcryptExpand(P, S, data, key):
|
||||
koffset = [0]
|
||||
for i in xrange(18):
|
||||
P[i] ^= _bcryptStream(key, koffset)
|
||||
|
||||
doffset = [0]
|
||||
L = R = 0
|
||||
for i in xrange(0, 18, 2):
|
||||
if data:
|
||||
L ^= _bcryptStream(data, doffset)
|
||||
R ^= _bcryptStream(data, doffset)
|
||||
L, R = _bcryptEncipher(P, S, L, R)
|
||||
P[i], P[i + 1] = L, R
|
||||
|
||||
for b in xrange(4):
|
||||
for k in xrange(0, 256, 2):
|
||||
if data:
|
||||
L ^= _bcryptStream(data, doffset)
|
||||
R ^= _bcryptStream(data, doffset)
|
||||
L, R = _bcryptEncipher(P, S, L, R)
|
||||
S[b][k], S[b][k + 1] = L, R
|
||||
|
||||
def _bcryptBase64(data):
|
||||
retVal = ""
|
||||
i = 0
|
||||
while i < len(data):
|
||||
c = data[i]; i += 1
|
||||
retVal += BCRYPT_ITOA64[(c >> 2) & 0x3f]
|
||||
c = (c & 3) << 4
|
||||
if i >= len(data):
|
||||
retVal += BCRYPT_ITOA64[c & 0x3f]; break
|
||||
d = data[i]; i += 1
|
||||
retVal += BCRYPT_ITOA64[(c | (d >> 4) & 0x0f) & 0x3f]
|
||||
c = (d & 0x0f) << 2
|
||||
if i >= len(data):
|
||||
retVal += BCRYPT_ITOA64[c & 0x3f]; break
|
||||
e = data[i]; i += 1
|
||||
retVal += BCRYPT_ITOA64[(c | (e >> 6) & 3) & 0x3f]
|
||||
retVal += BCRYPT_ITOA64[e & 0x3f]
|
||||
return retVal
|
||||
|
||||
def _bcryptUnbase64(value, length):
|
||||
retVal = bytearray()
|
||||
positions = [BCRYPT_ITOA64.index(_) for _ in value]
|
||||
i = 0
|
||||
while i < len(positions) and len(retVal) < length:
|
||||
c1 = positions[i]
|
||||
c2 = positions[i + 1] if i + 1 < len(positions) else 0
|
||||
retVal.append(((c1 << 2) | (c2 >> 4)) & 0xff)
|
||||
if len(retVal) >= length:
|
||||
break
|
||||
c3 = positions[i + 2] if i + 2 < len(positions) else 0
|
||||
retVal.append((((c2 & 0x0f) << 4) | (c3 >> 2)) & 0xff)
|
||||
if len(retVal) >= length:
|
||||
break
|
||||
c4 = positions[i + 3] if i + 3 < len(positions) else 0
|
||||
retVal.append((((c3 & 3) << 6) | c4) & 0xff)
|
||||
i += 4
|
||||
return retVal[:length]
|
||||
|
||||
def bcrypt_passwd(password, salt, magic="$2a$", cost=5, **kwargs):
|
||||
"""
|
||||
Reference(s):
|
||||
https://www.openwall.com/crypt/
|
||||
|
||||
>>> bcrypt_passwd(password='U*U', salt='CCCCCCCCCCCCCCCCCCCCC.', magic='$2a$', cost=5)
|
||||
'$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW'
|
||||
"""
|
||||
|
||||
P0, S0 = _bcryptInitState()
|
||||
P, S = list(P0), [list(_) for _ in S0]
|
||||
|
||||
key = bytearray(getBytes(password) + b"\0")
|
||||
saltbytes = _bcryptUnbase64(salt, 16)
|
||||
|
||||
_bcryptExpand(P, S, saltbytes, key)
|
||||
for _ in xrange(1 << cost):
|
||||
_bcryptExpand(P, S, b"", key)
|
||||
_bcryptExpand(P, S, b"", saltbytes)
|
||||
|
||||
ctext = list(struct.unpack(">6I", b"OrpheanBeholderScryDoubt"))
|
||||
for _ in xrange(64):
|
||||
for j in xrange(0, 6, 2):
|
||||
ctext[j], ctext[j + 1] = _bcryptEncipher(P, S, ctext[j], ctext[j + 1])
|
||||
|
||||
digest = bytearray(struct.pack(">6I", *ctext))[:23]
|
||||
|
||||
return "%s%02d$%s%s" % (magic, cost, salt, _bcryptBase64(digest))
|
||||
|
||||
def wordpress_bcrypt_passwd(password, salt, magic="$2y$", cost=10, **kwargs): # WordPress 6.8+ 'bcrypt(base64(hmac-sha384(pass)))'
|
||||
"""
|
||||
Reference: https://make.wordpress.org/core/2025/02/17/wordpress-6-8-will-use-bcrypt-for-password-hashing/
|
||||
|
||||
>>> wordpress_bcrypt_passwd(password='hashcat', salt='lzlQrRRhLSjz486bA9CKHu', magic='$2y$', cost=10)
|
||||
'$wp$2y$10$lzlQrRRhLSjz486bA9CKHuZRPoKz4uviT251Sq/r5OzKUBbrXwnQW'
|
||||
"""
|
||||
|
||||
prehashed = getText(base64.b64encode(hmac.new(b"wp-sha384", getBytes(password.strip()), sha384).digest()))
|
||||
|
||||
return "$wp%s" % bcrypt_passwd(prehashed, salt, magic, cost)
|
||||
|
||||
def joomla_passwd(password, salt, **kwargs):
|
||||
"""
|
||||
Reference: https://stackoverflow.com/a/10428239
|
||||
|
|
@ -469,6 +729,56 @@ def django_sha1_passwd(password, salt, **kwargs):
|
|||
|
||||
return "sha1$%s$%s" % (salt, sha1(getBytes(salt) + getBytes(password)).hexdigest())
|
||||
|
||||
def django_pbkdf2_sha256_passwd(password, salt, iterations, **kwargs):
|
||||
"""
|
||||
Reference: https://github.com/django/django/blob/main/django/contrib/auth/hashers.py
|
||||
|
||||
>>> django_pbkdf2_sha256_passwd(password='testpass', salt='salt', iterations=1000)
|
||||
'pbkdf2_sha256$1000$salt$N3DLJstEJ6mIjp0fq/KRcHmJ/4FtMzHYmW9fBHci/aI='
|
||||
"""
|
||||
|
||||
dk = pbkdf2_hmac("sha256", getBytes(password), getBytes(salt), iterations)
|
||||
|
||||
return "pbkdf2_sha256$%d$%s$%s" % (iterations, salt, getText(base64.b64encode(dk)))
|
||||
|
||||
def werkzeug_pbkdf2_passwd(password, salt, iterations, digestmod="sha256", **kwargs):
|
||||
"""
|
||||
Reference: https://github.com/pallets/werkzeug/blob/main/src/werkzeug/security.py
|
||||
|
||||
>>> werkzeug_pbkdf2_passwd(password='testpass', salt='salt', iterations=1000, digestmod='sha256')
|
||||
'pbkdf2:sha256:1000$salt$3770cb26cb4427a9888e9d1fabf291707989ff816d3331d8996f5f047722fda2'
|
||||
"""
|
||||
|
||||
dk = pbkdf2_hmac(digestmod, getBytes(password), getBytes(salt), iterations)
|
||||
|
||||
return "pbkdf2:%s:%d$%s$%s" % (digestmod, iterations, salt, getText(encodeHex(dk, binary=False)))
|
||||
|
||||
def werkzeug_scrypt_passwd(password, salt, N, r, p, **kwargs):
|
||||
"""
|
||||
Reference: https://github.com/pallets/werkzeug/blob/main/src/werkzeug/security.py
|
||||
|
||||
>>> werkzeug_scrypt_passwd(password='testpass', salt='saltsalt', N=32768, r=8, p=1) if _scrypt else 'scrypt:32768:8:1$saltsalt$1e0f97c3f6609024022fbe698da29c2fe53ef1087a8e396dc6d5d2a041e886dee09ea922781f2c2a1c85e46c77060147e43487f8fe6226bcb635915af9b0518b'
|
||||
'scrypt:32768:8:1$saltsalt$1e0f97c3f6609024022fbe698da29c2fe53ef1087a8e396dc6d5d2a041e886dee09ea922781f2c2a1c85e46c77060147e43487f8fe6226bcb635915af9b0518b'
|
||||
"""
|
||||
|
||||
dk = _scrypt(getBytes(password), salt=getBytes(salt), n=N, r=r, p=p, dklen=64, maxmem=132 * N * r + 1024)
|
||||
|
||||
return "scrypt:%d:%d:%d$%s$%s" % (N, r, p, salt, getText(encodeHex(dk, binary=False)))
|
||||
|
||||
def aspnet_identity_passwd(password, salt, iterations, prf, dklen, **kwargs):
|
||||
"""
|
||||
Reference(s):
|
||||
https://github.com/dotnet/AspNetCore/blob/main/src/Identity/Extensions.Core/src/PasswordHasher.cs
|
||||
|
||||
>>> aspnet_identity_passwd(password='cutecats', salt=decodeBase64('AQAAAAEAACcQAAAAEFWLthQDW2xiWaS3vLgY4ItJdModbW0kzKtb8IVuXBY3fFaIntkbbdqTj8mTXH4mmA==', binary=True)[13:29], iterations=10000, prf=1, dklen=32)
|
||||
'AQAAAAEAACcQAAAAEFWLthQDW2xiWaS3vLgY4ItJdModbW0kzKtb8IVuXBY3fFaIntkbbdqTj8mTXH4mmA=='
|
||||
"""
|
||||
|
||||
subkey = pbkdf2_hmac({0: "sha1", 1: "sha256", 2: "sha512"}[prf], getBytes(password), bytes(salt), iterations, dklen)
|
||||
blob = struct.pack(">BIII", 1, prf, iterations, len(salt)) + bytes(salt) + subkey
|
||||
|
||||
return getText(base64.b64encode(blob))
|
||||
|
||||
def vbulletin_passwd(password, salt, **kwargs):
|
||||
"""
|
||||
Reference: https://stackoverflow.com/a/2202810
|
||||
|
|
@ -560,6 +870,8 @@ __functions__ = {
|
|||
HASH.MYSQL: mysql_passwd,
|
||||
HASH.MYSQL_OLD: mysql_old_passwd,
|
||||
HASH.POSTGRES: postgres_passwd,
|
||||
HASH.POSTGRES_SCRAM: postgres_scram_passwd,
|
||||
HASH.MYSQL_SHA2: mysql_sha2_passwd,
|
||||
HASH.MSSQL: mssql_passwd,
|
||||
HASH.MSSQL_OLD: mssql_old_passwd,
|
||||
HASH.MSSQL_NEW: mssql_new_passwd,
|
||||
|
|
@ -572,9 +884,16 @@ __functions__ = {
|
|||
HASH.SHA384_GENERIC: sha384_generic_passwd,
|
||||
HASH.SHA512_GENERIC: sha512_generic_passwd,
|
||||
HASH.CRYPT_GENERIC: crypt_generic_passwd,
|
||||
HASH.SHA256_UNIX_CRYPT: sha2_crypt_passwd,
|
||||
HASH.SHA512_UNIX_CRYPT: sha2_crypt_passwd,
|
||||
HASH.BCRYPT: bcrypt_passwd,
|
||||
HASH.WORDPRESS_BCRYPT: wordpress_bcrypt_passwd,
|
||||
HASH.JOOMLA: joomla_passwd,
|
||||
HASH.DJANGO_MD5: django_md5_passwd,
|
||||
HASH.DJANGO_SHA1: django_sha1_passwd,
|
||||
HASH.DJANGO_PBKDF2_SHA256: django_pbkdf2_sha256_passwd,
|
||||
HASH.ASPNET_IDENTITY: aspnet_identity_passwd,
|
||||
HASH.WERKZEUG_PBKDF2: werkzeug_pbkdf2_passwd,
|
||||
HASH.PHPASS: phpass_passwd,
|
||||
HASH.APACHE_MD5_CRYPT: unix_md5_passwd,
|
||||
HASH.UNIX_MD5_CRYPT: unix_md5_passwd,
|
||||
|
|
@ -591,6 +910,14 @@ __functions__ = {
|
|||
HASH.SHA512_BASE64: sha512_generic_passwd,
|
||||
}
|
||||
|
||||
if _scrypt is not None:
|
||||
__functions__[HASH.WERKZEUG_SCRYPT] = werkzeug_scrypt_passwd
|
||||
|
||||
# Recognized-only formats with no pure-Python/stdlib crack path; identified and pointed to dedicated tools
|
||||
HASH_TOOL_HINTS = {
|
||||
HASH.ARGON2: "an Argon2 hash (e.g. 'hashcat -m 34000' or 'john --format=argon2')",
|
||||
}
|
||||
|
||||
def _finalize(retVal, results, processes, attack_info=None):
|
||||
if _multiprocessing:
|
||||
gc.enable()
|
||||
|
|
@ -1023,9 +1350,14 @@ def dictionaryAttack(attack_dict):
|
|||
regex = hashRecognition(hash_)
|
||||
|
||||
if regex and regex not in hash_regexes:
|
||||
hash_regexes.append(regex)
|
||||
infoMsg = "using hash method '%s'" % __functions__[regex].__name__
|
||||
logger.info(infoMsg)
|
||||
if regex in __functions__:
|
||||
hash_regexes.append(regex)
|
||||
infoMsg = "using hash method '%s'" % __functions__[regex].__name__
|
||||
logger.info(infoMsg)
|
||||
else:
|
||||
warnMsg = "sqlmap identified %s that cannot be cracked with the " % HASH_TOOL_HINTS.get(regex, "a hash")
|
||||
warnMsg += "built-in dictionary attack"
|
||||
singleTimeWarnMessage(warnMsg)
|
||||
|
||||
for hash_regex in hash_regexes:
|
||||
keys = set()
|
||||
|
|
@ -1043,7 +1375,7 @@ def dictionaryAttack(attack_dict):
|
|||
try:
|
||||
item = None
|
||||
|
||||
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):
|
||||
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.DJANGO_PBKDF2_SHA256, HASH.POSTGRES_SCRAM, HASH.MYSQL_SHA2, HASH.WERKZEUG_PBKDF2, HASH.WERKZEUG_SCRYPT, HASH.SHA256_UNIX_CRYPT, HASH.SHA512_UNIX_CRYPT, HASH.BCRYPT, HASH.WORDPRESS_BCRYPT, HASH.ASPNET_IDENTITY, HASH.MD5_BASE64, HASH.SHA1_BASE64, HASH.SHA256_BASE64, HASH.SHA512_BASE64):
|
||||
hash_ = hash_.lower()
|
||||
|
||||
if hash_regex in (HASH.MD5_BASE64, HASH.SHA1_BASE64, HASH.SHA256_BASE64, HASH.SHA512_BASE64):
|
||||
|
|
@ -1068,10 +1400,32 @@ def dictionaryAttack(attack_dict):
|
|||
item = [(user, hash_), {"salt": hash_[0:2]}]
|
||||
elif hash_regex in (HASH.UNIX_MD5_CRYPT, HASH.APACHE_MD5_CRYPT):
|
||||
item = [(user, hash_), {"salt": hash_.split('$')[2], "magic": "$%s$" % hash_.split('$')[1]}]
|
||||
elif hash_regex in (HASH.SHA256_UNIX_CRYPT, HASH.SHA512_UNIX_CRYPT):
|
||||
item = [(user, hash_), {"salt": '$'.join(hash_.split('$')[2:-1]), "magic": "$%s$" % hash_.split('$')[1]}]
|
||||
elif hash_regex in (HASH.BCRYPT,):
|
||||
item = [(user, hash_), {"salt": hash_[7:29], "magic": hash_[:4], "cost": int(hash_[4:6])}]
|
||||
elif hash_regex in (HASH.WORDPRESS_BCRYPT,):
|
||||
item = [(user, hash_), {"salt": hash_[10:32], "magic": hash_[3:7], "cost": int(hash_[7:9])}]
|
||||
elif hash_regex in (HASH.ASPNET_IDENTITY,):
|
||||
_ = decodeBase64(hash_, binary=True)
|
||||
prf, iterations, saltlen = struct.unpack(">III", _[1:13])
|
||||
item = [(user, hash_), {"salt": _[13:13 + saltlen], "iterations": iterations, "prf": prf, "dklen": len(_) - 13 - saltlen}]
|
||||
elif hash_regex in (HASH.MYSQL_SHA2,):
|
||||
_ = hash_.split('*')
|
||||
item = [(user, hash_), {"salt": decodeHex(_[1]), "rounds": int(_[0].split('$')[-1], 16) * 1000, "prefix": hash_[:hash_.rindex('*') + 1]}]
|
||||
elif hash_regex in (HASH.JOOMLA, HASH.VBULLETIN, HASH.VBULLETIN_OLD, HASH.OSCOMMERCE_OLD):
|
||||
item = [(user, hash_), {"salt": hash_.split(':')[-1]}]
|
||||
elif hash_regex in (HASH.DJANGO_MD5, HASH.DJANGO_SHA1):
|
||||
item = [(user, hash_), {"salt": hash_.split('$')[1]}]
|
||||
elif hash_regex in (HASH.DJANGO_PBKDF2_SHA256,):
|
||||
item = [(user, hash_), {"salt": hash_.split('$')[2], "iterations": int(hash_.split('$')[1])}]
|
||||
elif hash_regex in (HASH.POSTGRES_SCRAM,):
|
||||
item = [(user, hash_), {"salt": hash_.split('$')[1].split(':')[1], "iterations": int(hash_.split('$')[1].split(':')[0])}]
|
||||
elif hash_regex in (HASH.WERKZEUG_PBKDF2,):
|
||||
item = [(user, hash_), {"salt": hash_.split('$')[1], "iterations": int(hash_.split('$')[0].split(':')[2]), "digestmod": hash_.split('$')[0].split(':')[1]}]
|
||||
elif hash_regex in (HASH.WERKZEUG_SCRYPT,):
|
||||
_ = hash_.split('$')[0].split(':')
|
||||
item = [(user, hash_), {"salt": hash_.split('$')[1], "N": int(_[1]), "r": int(_[2]), "p": int(_[3])}]
|
||||
elif hash_regex in (HASH.PHPASS,):
|
||||
if ITOA64.index(hash_[3]) < 32:
|
||||
item = [(user, hash_), {"salt": hash_[4:12], "count": 1 << ITOA64.index(hash_[3]), "prefix": hash_[:3]}]
|
||||
|
|
@ -1102,7 +1456,7 @@ def dictionaryAttack(attack_dict):
|
|||
while not kb.wordlists:
|
||||
|
||||
# the slowest of all methods hence smaller default dict
|
||||
if hash_regex in (HASH.ORACLE_OLD, HASH.PHPASS):
|
||||
if hash_regex in (HASH.ORACLE_OLD, HASH.PHPASS, HASH.SHA256_UNIX_CRYPT, HASH.SHA512_UNIX_CRYPT, HASH.WERKZEUG_SCRYPT, HASH.BCRYPT, HASH.WORDPRESS_BCRYPT, HASH.MYSQL_SHA2):
|
||||
dictPaths = [paths.SMALL_DICT]
|
||||
else:
|
||||
dictPaths = [paths.WORDLIST]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue