From 7b14cac963ff71d59caf88a9527cbe2fc599ef7d Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Sun, 30 Dec 2018 03:07:15 +0530 Subject: [PATCH] alpha release --- bolt.py | 264 ++++++++++++ core/colors.py | 20 + core/config.py | 14 + core/datanize.py | 39 ++ core/evaluate.py | 30 ++ core/photon.py | 54 +++ core/prompt.py | 19 + core/ranger.py | 10 + core/requester.py | 20 + core/tweaker.py | 38 ++ core/utils.py | 62 +++ core/zetanize.py | 48 +++ db/hashes.json | 999 ++++++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 1617 insertions(+) create mode 100644 bolt.py create mode 100644 core/colors.py create mode 100644 core/config.py create mode 100644 core/datanize.py create mode 100644 core/evaluate.py create mode 100644 core/photon.py create mode 100644 core/prompt.py create mode 100644 core/ranger.py create mode 100644 core/requester.py create mode 100644 core/tweaker.py create mode 100644 core/utils.py create mode 100644 core/zetanize.py create mode 100644 db/hashes.json diff --git a/bolt.py b/bolt.py new file mode 100644 index 0000000..59615a9 --- /dev/null +++ b/bolt.py @@ -0,0 +1,264 @@ +import argparse +import concurrent.futures +import json +import random +import re +import statistics + +from collections import Counter +from fuzzywuzzy import fuzz, process + +import core.config +from core.config import token +from core.datanize import datanize +from core.prompt import prompt +from core.photon import photon +from core.tweaker import tweaker +from core.evaluate import evaluate +from core.ranger import ranger +from core.zetanize import zetanize +from core.requester import requester +from core.utils import extractHeaders, entropy, isProtected +from core.colors import green, yellow, end, run, good, info, bad, white + +parser = argparse.ArgumentParser() +parser.add_argument('-u', help='target url', dest='target') +parser.add_argument('-t', help='number of threads', dest='threads', type=int) +parser.add_argument('-l', help='levels to crawl', dest='level', type=int) +parser.add_argument('--delay', help='delay between requests', dest='delay', type=int) +parser.add_argument('--timeout', help='http request timeout', dest='timeout', type=int) +parser.add_argument('--headers', help='http headers', dest='headers', action='store_true') +args = parser.parse_args() + +def banner(): + print ('''%s + ⚡ %sBOLT%s ⚡ + %s''' % (yellow, white, yellow, end)) + +if not args.target: + banner() + print('\n' + parser.format_help().lower()) + quit() + +if args.headers: + headers = extractHeaders(prompt()) +else: + headers = core.config.headers + +banner() + +target = args.target +delay = args.delay or 0 +level = args.level or 2 +timeout = args.timeout or 20 +threadCount = args.threads or 2 + +allTokens = [] +weakTokens = [] +tokenDatabase = [] +insecureForms = [] + +print ('%s Phase: Crawling %s[%s1/5%s]%s' % (run, green, end, green, end)) +dataset = photon(target, headers, level, threadCount) +allForms = dataset[0] +print ('\r%s Crawled %i URL(s) and found %i form(s).%-10s' % (info, dataset[1], len(allForms), ' ')) +print ('%s Phase: Evaluating %s[%s2/5%s]%s' % (run, green, end, green, end)) + +evaluate(allForms, weakTokens, tokenDatabase, allTokens, insecureForms) + +if weakTokens: + print ('%s Weak token(s) found' % good) + for weakToken in weakTokens: + url = list(weakToken.keys())[0] + token = list(weakToken.values())[0] + print ('%s %s %s' % (info, url, token)) + +if insecureForms: + print ('%s Insecure form(s) found' % good) + for insecureForm in insecureForms: + url = list(insecureForm.keys())[0] + action = list(insecureForm.values())[0]['action'] + form = action.replace(target, '') + if form: + print ('%s %s %s[%s%s%s]%s' % (bad, url, green, end, form, green, end)) + +with open('./db/hashes.json') as f: + hashPatterns = json.load(f) + +aToken = allTokens[0] +matches = [] +for element in hashPatterns: + pattern = element['regex'] + if re.match(pattern, aToken): + for name in element['matches']: + matches.append(name) +if matches: + print ('%s Token matches the pattern of following hash type(s):' % info) + for name in matches: + print (' %s>%s %s' % (yellow, end, name)) + +print ('%s Phase: Comparing %s[%s3/5%s]%s' % (run, green, end, green, end)) +uniqueTokens = set(allTokens) +if len(uniqueTokens) < len(allTokens): + print ('%s Potential Replay Attack condition found' % good) + print ('%s Verifying and looking for the cause' % run) + replay = False + for url, token in tokenDatabase: + for url2, token2 in tokenDatabase: + if token == token2 and url != url2: + print ('%s The same token was used on %s%s%s and %s%s%s' % (good, green, url, end, green, url2, end)) + replay = True + if not replay: + print ('%s Further investigation shows that it was a false positive.') + +def fuzzy(tokens): + averages = [] + for token in tokens: + sameTokenRemoved = False + result = process.extract(token, tokens, scorer=fuzz.partial_ratio) + scores = [] + for each in result: + score = each[1] + if score == 100 and not sameTokenRemoved: + sameTokenRemoved = True + continue + scores.append(score) + average = statistics.mean(scores) + averages.append(average) + return statistics.mean(averages) + +try: + similarity = fuzzy(allTokens) + print ('%s Tokens are %s%i%%%s similar to each other on an average' % (info, green, similarity, end)) +except statistics.StatisticsError: + print ('%s No CSRF protection to test' % bad) + quit() + +simTokens = [] + +print ('%s Phase: Observing %s[%s4/5%s]%s' % (run, green, end, green, end)) +print ('%s 100 simultaneous requests are being made, please wait.' % info) + +def extractForms(url): + response = requester(url, {}, headers, True, 0).text + forms = zetanize(url, response) + for each in forms.values(): + localTokens = set() + inputs = each['inputs'] + for inp in inputs: + value = inp['value'] + if value and match(r'^[\w\-_]+$', value): + if entropy(value) > 10: + simTokens.append(value) + +while True: + sample = random.choice(tokenDatabase) + goodToken = list(sample.values())[0] + if len(goodToken) > 0: + goodCandidate = list(sample.keys())[0] + break + +threadpool = concurrent.futures.ThreadPoolExecutor(max_workers=30) +futures = (threadpool.submit(extractForms, goodCandidate) for goodCandidate in [goodCandidate] * 30) +for i in concurrent.futures.as_completed(futures): + pass + +if simTokens: + if len(set(simTokens)) < len(simTokens): + print ('%s Same tokens were issued for simultaneous requests.' % good) + else: + print (simTokens) +else: + print ('%s Different tokens were issued for simultaneous requests.' % info) + +print ('%s Phase: Testing %s[%s5/5%s]%s' % (good, green, end, green, end)) + +parsed = '' +print ('%s Finding a suitable form for further testing. It may take a while.' % run) +for url, forms in allForms[0].items(): + found = False + parsed = datanize(forms, tolerate=True) + if parsed: + found = True + break + if found: + break + +if not parsed: + candidate = list(random.choice(tokenDatabase).keys())[0] + parsed = datanize(candidate, headers, tolerate=True) + print (parsed) + +origGET = parsed[0] +origUrl = parsed[1] +origData = parsed[2] + +print ('%s Making a request with CSRF token for comparison.' % run) +response = requester(origUrl, origData, headers, origGET, 0) +originalCode = response.status_code +originalLength = len(response.text) +print ('%s Status Code: %s' % (info, originalCode)) +print ('%s Content Length: %i' % (info, originalLength)) +print ('%s Checking if the resonse is dynamic.' % run) +response = requester(origUrl, origData, headers, origGET, 0) +secondLength = len(response.text) +if originalLength != secondLength: + print ('%s Response is dynamic.' % info) + tolerableDifference = abs(originalLength - secondLength) +else: + print ('%s Response isn\'t dynamic.' % info) + tolerableDifference = 0 + +print ('%s Emulating a mobile browser' % run) +print ('%s Making a request with mobile browser' % run) +headers['User-Agent'] = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows CE; PPC; 240x320)' +response = requester(origUrl, {}, headers, True, 0).text +parsed = zetanize(origUrl, response) +if isProtected(parsed): + print ('%s CSRF protection is enabled for mobile browsers as well.' % bad) +else: + print ('%s CSRF protection isn\'t enabled for mobile browsers.' % good) + +print ('%s Making a request without CSRF token parameter.' % run) +data = tweaker(origData, 'remove') +response = requester(origUrl, data, headers, origGET, 0) +if response.status_code == originalCode: + if str(originalCode)[0] in ['4', '5']: + print ('%s It didn\'t work' % bad) + else: + difference = abs(originalLength - len(response.text)) + if difference <= tolerableDifference: + print ('%s It worked!' % good) +else: + print ('%s It didn\'t work' % bad) +print ('%s Making a request without CSRF token parameter value.' % run) +data = tweaker(origData, 'clear') +response = requester(origUrl, data, headers, origGET, 0) +if response.status_code == originalCode: + if str(originalCode)[0] in ['4', '5']: + print ('%s It didn\'t work' % bad) + else: + difference = abs(originalLength - len(response.text)) + if difference <= tolerableDifference: + print ('%s It worked!' % good) +else: + print ('%s It didn\'t work' % bad) +seeds = ranger(allTokens) +print ('%s Generating a fake token.' % run) +data = tweaker(origData, 'generate', seeds=seeds) +print ('%s Making a request with the self generated token.' % run) +response = requester(origUrl, data, headers, origGET, 0) +if response.status_code == originalCode: + if str(originalCode)[0] in ['4', '5']: + print ('%s It didn\'t work' % bad) + else: + difference = abs(originalLength - len(response.text)) + if difference <= tolerableDifference: + print ('%s It worked!' % good) +else: + print ('%s It didn\'t work' % bad) + +print ('%s Making requests with various tweaks to the token. It may take a while.' % run) +# data = datanize(goodCandidate, headers)[1] +# data = tweaker(data, 'remove') +# response = requester(origUrl, data, headers, origGET, 0) \ No newline at end of file diff --git a/core/colors.py b/core/colors.py new file mode 100644 index 0000000..7737031 --- /dev/null +++ b/core/colors.py @@ -0,0 +1,20 @@ +import sys + +colors = True # Output should be colored +machine = sys.platform # Detecting the os of current system +if machine.lower().startswith(('os', 'win', 'darwin', 'ios')): + colors = False # Colors shouldn't be displayed in mac & windows +if not colors: + end = red = white = green = yellow = run = bad = good = info = que = '' +else: + white = '\033[97m' + green = '\033[92m' + red = '\033[91m' + yellow = '\033[93m' + end = '\033[0m' + back = '\033[7;91m' + info = '\033[93m[!]\033[0m' + que = '\033[94m[?]\033[0m' + bad = '\033[91m[-]\033[0m' + good = '\033[92m[+]\033[0m' + run = '\033[97m[~]\033[0m' \ No newline at end of file diff --git a/core/config.py b/core/config.py new file mode 100644 index 0000000..191ffb5 --- /dev/null +++ b/core/config.py @@ -0,0 +1,14 @@ +password = 'xXx!69!xXx' +email = 'testing@gmail.com' +strings = ['red', 'bob', 'admin', 'alex', 'testing', 'test', 'lol', 'yes', 'dragon', 'bad'] +commonNames = ['csrf', 'auth', 'token', 'verify', 'hash'] +token = r'^[\w\-_+=/]{14,256}$' + +headers = { # default headers + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Accept-Language': 'en-US,en;q=0.5', + 'Accept-Encoding': 'gzip,deflate', + 'Connection': 'close', + 'DNT': '1', + 'Upgrade-Insecure-Requests': '1', +} \ No newline at end of file diff --git a/core/datanize.py b/core/datanize.py new file mode 100644 index 0000000..3e92380 --- /dev/null +++ b/core/datanize.py @@ -0,0 +1,39 @@ +import random +import re + +from core.config import password, email, token, strings +from core.requester import requester +from core.zetanize import zetanize + +def datanize(forms, tolerate=False): + parsedForms = list(forms.values()) + for oneForm in parsedForms: + data = {} + login = False + protected = False + action = oneForm['action'] + method = oneForm['method'] + inputs = oneForm['inputs'] + for inp in inputs: + name = inp['name'] + kind = inp['type'] + value = inp['value'] + if re.match(token, value): + protected = True + if kind == 'password': + data[name] = password + login = True + if kind == 'email': + data[name] = email + if kind == 'text': + data[name] = random.choice(strings) + else: + data[name] = value + if method == 'GET': + GET = True + else: + GET = False + if protected: + if not login or tolerate: + return [GET, action, data] + return None \ No newline at end of file diff --git a/core/evaluate.py b/core/evaluate.py new file mode 100644 index 0000000..d35675b --- /dev/null +++ b/core/evaluate.py @@ -0,0 +1,30 @@ +from re import match +from core.utils import entropy +from core.config import commonNames + +def evaluate(dataset, weakTokens, tokenDatabase, allTokens, insecureForms): + done = [] + for i in dataset: + for url, page in i.items(): + localTokens = set() + for each in page.values(): + protected = False + action = each['action'] + method = each['method'] + inputs = each['inputs'] + for inp in inputs: + name = inp['name'] + value = inp['value'] + if value and match(r'^[\w\-_]+$', value): + if entropy(value) > 10: + localTokens.add(value) + protected = True + break + elif name.lower() in commonNames: + weakTokens.append({url : {name : value}}) + if not protected and action not in done: + done.append(done) + insecureForms.append({url : each}) + for token in localTokens: + allTokens.append(token) + tokenDatabase.append({url : localTokens}) \ No newline at end of file diff --git a/core/photon.py b/core/photon.py new file mode 100644 index 0000000..abd75f9 --- /dev/null +++ b/core/photon.py @@ -0,0 +1,54 @@ +# Let's import what we need +import tld +import sys +import json +from re import findall +import concurrent.futures +from urllib.parse import urlparse # for python3 + +from core.colors import run +from core.zetanize import zetanize +from core.requester import requester +from core.utils import getUrl, getParams + +def photon(seedUrl, headers, depth, threadCount): + forms = [] # web forms + processed = set() # urls that have been crawled + storage = set() # urls that belong to the target i.e. in-scope + scheme = urlparse(seedUrl).scheme + host = urlparse(seedUrl).netloc + main_url = scheme + '://' + host + storage.add(seedUrl) + def rec(url): + processed.add(url) + urlPrint = (url + (' ' * 60))[:60] + print ('%s Parsing %-40s' % (run, urlPrint), end='\r') + url = getUrl(url, '', True) + params = getParams(url, '', True) + if '=' in url: + inps = [] + for name, value in params.items(): + inps.append({'name': name, 'value': value}) + forms.append({url : {0: {'action': url, 'method': 'get', 'inputs': inps}}}) + response = requester(url, params, headers, True, 0).text + forms.append({url : zetanize(url, response)}) + matches = findall(r'<[aA].*href=["\']{0,1}(.*?)["\']', response) + for link in matches: # iterate over the matches + link = link.split('#')[0].lstrip(' ') # remove everything after a "#" to deal with in-page anchors + if link[:4] == 'http': + if link.startswith(main_url): + storage.add(link) + elif link[:2] == '//': + if link.split('/')[2].startswith(host): + storage.add(schema + link) + elif link[:1] == '/': + storage.add(main_url + link) + else: + storage.add(main_url + '/' + link) + for x in range(depth): + urls = storage - processed + threadpool = concurrent.futures.ThreadPoolExecutor(max_workers=10) + futures = (threadpool.submit(rec, url) for url in urls) + for i in concurrent.futures.as_completed(futures): + pass + return [forms, len(processed)] \ No newline at end of file diff --git a/core/prompt.py b/core/prompt.py new file mode 100644 index 0000000..24151ed --- /dev/null +++ b/core/prompt.py @@ -0,0 +1,19 @@ +import os +import tempfile + +def prompt(default=None): + editor = 'nano' + with tempfile.NamedTemporaryFile(mode='r+') as tmpfile: + if default: + tmpfile.write(default) + tmpfile.flush() + + child_pid = os.fork() + is_child = child_pid == 0 + + if is_child: + os.execvp(editor, [editor, tmpfile.name]) + else: + os.waitpid(child_pid, 0) + tmpfile.seek(0) + return tmpfile.read().strip() \ No newline at end of file diff --git a/core/ranger.py b/core/ranger.py new file mode 100644 index 0000000..de404d6 --- /dev/null +++ b/core/ranger.py @@ -0,0 +1,10 @@ +def ranger(tokens): + digits = set() + alphabets = set() + for token in tokens: + for char in token: + if char in '0123456789': + digits.add(char) + elif char in 'abcdefghijklmnopqrstuvwxyz': + alphabets.add(char) + return [list(digits), list(alphabets)] \ No newline at end of file diff --git a/core/requester.py b/core/requester.py new file mode 100644 index 0000000..7085e04 --- /dev/null +++ b/core/requester.py @@ -0,0 +1,20 @@ +import time +import random +import warnings +import requests + +warnings.filterwarnings('ignore') # Disable SSL related warnings + +def requester(url, data, headers, GET, delay): + time.sleep(delay) + user_agents = ['Mozilla/5.0 (X11; Linux i686; rv:60.0) Gecko/20100101 Firefox/60.0', +'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36' +'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.991'] + if headers: + if 'User-Agent' not in headers: + headers['User-Agent'] = random.choice(user_agents) + if GET: + response = requests.get(url, params=data, headers=headers, verify=False) + else: + response = requests.post(url, data=data, headers=headers, verify=False) + return response \ No newline at end of file diff --git a/core/tweaker.py b/core/tweaker.py new file mode 100644 index 0000000..93c27f2 --- /dev/null +++ b/core/tweaker.py @@ -0,0 +1,38 @@ +from core.config import token +import random +import re + +def tweaker(data, strategy, index=0, seeds=[None, None]): + newData = {} + if strategy == 'clear': + for name, value in data.items(): + if re.match(token, value): + value = '' + newData[name] = value + return newData + elif strategy == 'remove': + for name, value in data.items(): + if not re.match(token, value): + newData[name] = value + elif strategy == 'break': + for name, value in data.items(): + if re.match(token, value): + value = value[:-index] + newData[name] = value + elif strategy == 'generate': + digits = seeds[0] + alphabets = seeds[1] + for name, value in data.items(): + if re.match(token, value): + newToken = '' + for char in list(value): + if char in digits: + newToken += random.choice(digits) + elif char in alphabets: + newToken += random.choice(alphabets) + else: + newToken += char + newData[name] = newToken + else: + newData[name] = value + return newData \ No newline at end of file diff --git a/core/utils.py b/core/utils.py new file mode 100644 index 0000000..b5c377f --- /dev/null +++ b/core/utils.py @@ -0,0 +1,62 @@ +import re +from core.config import token + +def entropy(string): + digits = re.findall(r'\d', string) + lowerAlphas = re.findall(r'[a-z]', string) + upperAlphas = re.findall(r'[A-Z]', string) + entropy = len(set(digits + lowerAlphas + upperAlphas)) + if not digits: + entropy = entropy/2 + return entropy + +def isProtected(parsed): + protected = False + parsedForms = list(parsed.values()) + for oneForm in parsedForms: + inputs = oneForm['inputs'] + for inp in inputs: + name = inp['name'] + kind = inp['type'] + value = inp['value'] + if re.match(token, value): + protected = True + return protected + +def extractHeaders(headers): + sorted_headers = {} + matches = re.findall(r'(.*):\s(.*)', headers) + for match in matches: + header = match[0] + value = match[1] + try: + if value[-1] == ',': + value = value[:-1] + sorted_headers[header] = value + except IndexError: + pass + return sorted_headers + +def getUrl(url, data, GET): + if GET: + return url.split('?')[0] + else: + return url + +def getParams(url, data, GET): + params = {} + if GET: + if '=' in url: + data = url.split('?')[1] + if data[:1] == '?': + data = data[1:] + else: + data = '' + parts = data.split('&') + for part in parts: + each = part.split('=') + try: + params[each[0]] = each[1] + except IndexError: + params = None + return params \ No newline at end of file diff --git a/core/zetanize.py b/core/zetanize.py new file mode 100644 index 0000000..f0aa1f5 --- /dev/null +++ b/core/zetanize.py @@ -0,0 +1,48 @@ +import re +from urllib.parse import urlparse + +def zetanize(url, response): + parsedUrl = urlparse(url) + mainUrl = parsedUrl.scheme + '://' + parsedUrl.netloc + def e(string): + return string.encode('utf-8') + + def d(string): + return string.decode('utf-8') + + response = re.sub(r'(?s)', '', response) + forms = {} + matches = re.findall(r'(?i)(?s)', response) + num = 0 + for match in matches: + page = re.search(r'(?i)action=[\'"](.*?)[\'"]', match) + method = re.search(r'(?i)method=[\'"](.*?)[\'"]', match) + forms[num] = {} + action = d(e(page.group(1))) + if not action.startswith('http'): + if action.startswith('/'): + action = mainUrl + action + else: + action = mainUrl + '/' + action + forms[num]['action'] = action.replace('&', '&') if page else '' + forms[num]['method'] = d(e(method.group(1)).lower()) if method else 'get' + forms[num]['inputs'] = [] + inputs = re.findall(r'(?i)(?s)', response) + for inp in inputs: + inpName = re.search(r'(?i)name=[\'"](.*?)[\'"]', inp) + if inpName: + inpType = re.search(r'(?i)type=[\'"](.*?)[\'"]', inp) + inpValue = re.search(r'(?i)value=[\'"](.*?)[\'"]', inp) + inpName = d(e(inpName.group(1))) + inpType = d(e(inpType.group(1)) )if inpType else '' + inpValue = d(e(inpValue.group(1))) if inpValue else '' + if inpType.lower() == 'submit' and inpValue == '': + inpValue = 'Submit Query' + inpDict = { + 'name' : inpName, + 'type' : inpType, + 'value' : inpValue + } + forms[num]['inputs'].append(inpDict) + num += 1 + return forms \ No newline at end of file diff --git a/db/hashes.json b/db/hashes.json new file mode 100644 index 0000000..e7985a6 --- /dev/null +++ b/db/hashes.json @@ -0,0 +1,999 @@ +[ + { + "regex": "^[a-f0-9]{4}$", + "matches": [ + "CRC-16", + "CRC-16-CCITT", + "FCS-16" + ] + }, + { + "regex": "^[a-f0-9]{8}$", + "matches": [ + "Adler-32", + "CRC-32B", + "FCS-32", + "GHash-32-3", + "GHash-32-5", + "FNV-132", + "Fletcher-32", + "Joaat", + "ELF-32", + "XOR-32" + ] + }, + { + "regex": "^[a-f0-9]{6}$", + "matches": [ + "CRC-24" + ] + }, + { + "regex": "^(\\$crc32\\$[a-f0-9]{8}.)?[a-f0-9]{8}$", + "matches": [ + "CRC-32" + ] + }, + { + "regex": "^\\+[a-z0-9\\/.]{12}$", + "matches": [ + "Eggdrop IRC Bot" + ] + }, + { + "regex": "^[a-z0-9\\/.]{13}$", + "matches": [ + "DES(Unix)", + "Traditional DES", + "DEScrypt" + ] + }, + { + "regex": "^[a-f0-9]{16}$", + "matches": [ + "MySQL323", + "DES(Oracle)", + "Half MD5", + "Oracle 7-10g", + "FNV-164", + "CRC-64" + ] + }, + { + "regex": "^[a-z0-9\\/.]{16}$", + "matches": [ + "Cisco-PIX(MD5)" + ] + }, + { + "regex": "^\\([a-z0-9\\/+]{20}\\)$", + "matches": [ + "Lotus Notes/Domino 6" + ] + }, + { + "regex": "^_[a-z0-9\\/.]{19}$", + "matches": [ + "BSDi Crypt" + ] + }, + { + "regex": "^[a-f0-9]{24}$", + "matches": [ + "CRC-96(ZIP)" + ] + }, + { + "regex": "^[a-z0-9\\/.]{24}$", + "matches": [ + "Crypt16" + ] + }, + { + "regex": "^(\\$md2\\$)?[a-f0-9]{32}$", + "matches": [ + "MD2" + ] + }, + { + "regex": "^[a-f0-9]{32}(:.+)?$", + "matches": [ + "MD5", + "MD4", + "Double MD5", + "LM", + "RIPEMD-128", + "Haval-128", + "Tiger-128", + "Skein-256(128)", + "Skein-512(128)", + "Lotus Notes/Domino 5", + "Skype", + "ZipMonster", + "PrestaShop", + "md5(md5(md5($pass)))", + "md5(strtoupper(md5($pass)))", + "md5(sha1($pass))", + "md5($pass.$salt)", + "md5($salt.$pass)", + "md5(unicode($pass).$salt)", + "md5($salt.unicode($pass))", + "HMAC-MD5 (key = $pass)", + "HMAC-MD5 (key = $salt)", + "md5(md5($salt).$pass)", + "md5($salt.md5($pass))", + "md5($pass.md5($salt))", + "md5($salt.$pass.$salt)", + "md5(md5($pass).md5($salt))", + "md5($salt.md5($salt.$pass))", + "md5($salt.md5($pass.$salt))", + "md5($username.0.$pass)" + ] + }, + { + "regex": "^(\\$snefru\\$)?[a-f0-9]{32}$", + "matches": [ + "Snefru-128" + ] + }, + { + "regex": "^(\\$NT\\$)?[a-f0-9]{32}$", + "matches": [ + "NTLM" + ] + }, + { + "regex": "^([^\\\\\\/:*?\"<>|]{1,20}:)?[a-f0-9]{32}(:[^\\\\\\/:*?\"<>|]{1,20})?$", + "matches": [ + "Domain Cached Credentials" + ] + }, + { + "regex": "^([^\\\\\\/:*?\"<>|]{1,20}:)?(\\$DCC2\\$10240#[^\\\\\\/:*?\"<>|]{1,20}#)?[a-f0-9]{32}$", + "matches": [ + "Domain Cached Credentials 2" + ] + }, + { + "regex": "^{SHA}[a-z0-9\\/+]{27}=$", + "matches": [ + "SHA-1(Base64)", + "Netscape LDAP SHA" + ] + }, + { + "regex": "^\\$1\\$[a-z0-9\\/.]{0,8}\\$[a-z0-9\\/.]{22}(:.*)?$", + "matches": [ + "MD5 Crypt", + "Cisco-IOS(MD5)", + "FreeBSD MD5" + ] + }, + { + "regex": "^0x[a-f0-9]{32}$", + "matches": [ + "Lineage II C4" + ] + }, + { + "regex": "^\\$H\\$[a-z0-9\\/.]{31}$", + "matches": [ + "phpBB v3.x", + "Wordpress v2.6.0/2.6.1", + "PHPass' Portable Hash" + ] + }, + { + "regex": "^\\$P\\$[a-z0-9\\/.]{31}$", + "matches": [ + "Wordpress \u2265 v2.6.2", + "Joomla \u2265 v2.5.18", + "PHPass' Portable Hash" + ] + }, + { + "regex": "^[a-f0-9]{32}:[a-z0-9]{2}$", + "matches": [ + "osCommerce", + "xt:Commerce" + ] + }, + { + "regex": "^\\$apr1\\$[a-z0-9\\/.]{0,8}\\$[a-z0-9\\/.]{22}$", + "matches": [ + "MD5(APR)", + "Apache MD5", + "md5apr1" + ] + }, + { + "regex": "^{smd5}[a-z0-9$\\/.]{31}$", + "matches": [ + "AIX(smd5)" + ] + }, + { + "regex": "^[a-f0-9]{32}:[a-f0-9]{32}$", + "matches": [ + "WebEdition CMS" + ] + }, + { + "regex": "^[a-f0-9]{32}:.{5}$", + "matches": [ + "IP.Board \u2265 v2+" + ] + }, + { + "regex": "^[a-f0-9]{32}:.{8}$", + "matches": [ + "MyBB \u2265 v1.2+" + ] + }, + { + "regex": "^[a-z0-9]{34}$", + "matches": [ + "CryptoCurrency(Adress)" + ] + }, + { + "regex": "^[a-f0-9]{40}(:.+)?$", + "matches": [ + "SHA-1", + "Double SHA-1", + "RIPEMD-160", + "Haval-160", + "Tiger-160", + "HAS-160", + "LinkedIn", + "Skein-256(160)", + "Skein-512(160)", + "MangosWeb Enhanced CMS", + "sha1(sha1(sha1($pass)))", + "sha1(md5($pass))", + "sha1($pass.$salt)", + "sha1($salt.$pass)", + "sha1(unicode($pass).$salt)", + "sha1($salt.unicode($pass))", + "HMAC-SHA1 (key = $pass)", + "HMAC-SHA1 (key = $salt)", + "sha1($salt.$pass.$salt)" + ] + }, + { + "regex": "^\\*[a-f0-9]{40}$", + "matches": [ + "MySQL5.x", + "MySQL4.1" + ] + }, + { + "regex": "^[a-z0-9]{43}$", + "matches": [ + "Cisco-IOS(SHA-256)" + ] + }, + { + "regex": "^{SSHA}[a-z0-9\\/+]{38}==$", + "matches": [ + "SSHA-1(Base64)", + "Netscape LDAP SSHA", + "nsldaps" + ] + }, + { + "regex": "^[a-z0-9=]{47}$", + "matches": [ + "Fortigate(FortiOS)" + ] + }, + { + "regex": "^[a-f0-9]{48}$", + "matches": [ + "Haval-192", + "Tiger-192", + "SHA-1(Oracle)", + "OSX v10.4", + "OSX v10.5", + "OSX v10.6" + ] + }, + { + "regex": "^[a-f0-9]{51}$", + "matches": [ + "Palshop CMS" + ] + }, + { + "regex": "^[a-z0-9]{51}$", + "matches": [ + "CryptoCurrency(PrivateKey)" + ] + }, + { + "regex": "^{ssha1}[0-9]{2}\\$[a-z0-9$\\/.]{44}$", + "matches": [ + "AIX(ssha1)" + ] + }, + { + "regex": "^0x0100[a-f0-9]{48}$", + "matches": [ + "MSSQL(2005)", + "MSSQL(2008)" + ] + }, + { + "regex": "^(\\$md5,rounds=[0-9]+\\$|\\$md5\\$rounds=[0-9]+\\$|\\$md5\\$)[a-z0-9\\/.]{0,16}(\\$|\\$\\$)[a-z0-9\\/.]{22}$", + "matches": [ + "Sun MD5 Crypt" + ] + }, + { + "regex": "^[a-f0-9]{56}$", + "matches": [ + "SHA-224", + "Haval-224", + "SHA3-224", + "Skein-256(224)", + "Skein-512(224)" + ] + }, + { + "regex": "^(\\$2[axy]|\\$2)\\$[0-9]{2}\\$[a-z0-9\\/.]{53}$", + "matches": [ + "Blowfish(OpenBSD)", + "Woltlab Burning Board 4.x", + "bcrypt" + ] + }, + { + "regex": "^[a-f0-9]{40}:[a-f0-9]{16}$", + "matches": [ + "Android PIN" + ] + }, + { + "regex": "^(S:)?[a-f0-9]{40}(:)?[a-f0-9]{20}$", + "matches": [ + "Oracle 11g/12c" + ] + }, + { + "regex": "^\\$bcrypt-sha256\\$(2[axy]|2)\\,[0-9]+\\$[a-z0-9\\/.]{22}\\$[a-z0-9\\/.]{31}$", + "matches": [ + "bcrypt(SHA-256)" + ] + }, + { + "regex": "^[a-f0-9]{32}:.{3}$", + "matches": [ + "vBulletin < v3.8.5" + ] + }, + { + "regex": "^[a-f0-9]{32}:.{30}$", + "matches": [ + "vBulletin \u2265 v3.8.5" + ] + }, + { + "regex": "^(\\$snefru\\$)?[a-f0-9]{64}$", + "matches": [ + "Snefru-256" + ] + }, + { + "regex": "^[a-f0-9]{64}(:.+)?$", + "matches": [ + "SHA-256", + "RIPEMD-256", + "Haval-256", + "GOST R 34.11-94", + "GOST CryptoPro S-Box", + "SHA3-256", + "Skein-256", + "Skein-512(256)", + "Ventrilo", + "sha256($pass.$salt)", + "sha256($salt.$pass)", + "sha256(unicode($pass).$salt)", + "sha256($salt.unicode($pass))", + "HMAC-SHA256 (key = $pass)", + "HMAC-SHA256 (key = $salt)" + ] + }, + { + "regex": "^[a-f0-9]{32}:[a-z0-9]{32}$", + "matches": [ + "Joomla < v2.5.18" + ] + }, + { + "regex": "^[a-f-0-9]{32}:[a-f-0-9]{32}$", + "matches": [ + "SAM(LM_Hash:NT_Hash)" + ] + }, + { + "regex": "^(\\$chap\\$0\\*)?[a-f0-9]{32}[\\*:][a-f0-9]{32}(:[0-9]{2})?$", + "matches": [ + "MD5(Chap)", + "iSCSI CHAP Authentication" + ] + }, + { + "regex": "^\\$episerver\\$\\*0\\*[a-z0-9\\/=+]+\\*[a-z0-9\\/=+]{27,28}$", + "matches": [ + "EPiServer 6.x < v4" + ] + }, + { + "regex": "^{ssha256}[0-9]{2}\\$[a-z0-9$\\/.]{60}$", + "matches": [ + "AIX(ssha256)" + ] + }, + { + "regex": "^[a-f0-9]{80}$", + "matches": [ + "RIPEMD-320" + ] + }, + { + "regex": "^\\$episerver\\$\\*1\\*[a-z0-9\\/=+]+\\*[a-z0-9\\/=+]{42,43}$", + "matches": [ + "EPiServer 6.x \u2265 v4" + ] + }, + { + "regex": "^0x0100[a-f0-9]{88}$", + "matches": [ + "MSSQL(2000)" + ] + }, + { + "regex": "^[a-f0-9]{96}$", + "matches": [ + "SHA-384", + "SHA3-384", + "Skein-512(384)", + "Skein-1024(384)" + ] + }, + { + "regex": "^{SSHA512}[a-z0-9\\/+]{96}$", + "matches": [ + "SSHA-512(Base64)", + "LDAP(SSHA-512)" + ] + }, + { + "regex": "^{ssha512}[0-9]{2}\\$[a-z0-9\\/.]{16,48}\\$[a-z0-9\\/.]{86}$", + "matches": [ + "AIX(ssha512)" + ] + }, + { + "regex": "^[a-f0-9]{128}(:.+)?$", + "matches": [ + "SHA-512", + "Whirlpool", + "Salsa10", + "Salsa20", + "SHA3-512", + "Skein-512", + "Skein-1024(512)", + "sha512($pass.$salt)", + "sha512($salt.$pass)", + "sha512(unicode($pass).$salt)", + "sha512($salt.unicode($pass))", + "HMAC-SHA512 (key = $pass)", + "HMAC-SHA512 (key = $salt)" + ] + }, + { + "regex": "^[a-f0-9]{136}$", + "matches": [ + "OSX v10.7" + ] + }, + { + "regex": "^0x0200[a-f0-9]{136}$", + "matches": [ + "MSSQL(2012)", + "MSSQL(2014)" + ] + }, + { + "regex": "^\\$ml\\$[0-9]+\\$[a-f0-9]{64}\\$[a-f0-9]{128}$", + "matches": [ + "OSX v10.8", + "OSX v10.9" + ] + }, + { + "regex": "^[a-f0-9]{256}$", + "matches": [ + "Skein-1024" + ] + }, + { + "regex": "^grub\\.pbkdf2\\.sha512\\.[0-9]+\\.([a-f0-9]{128,2048}\\.|[0-9]+\\.)?[a-f0-9]{128}$", + "matches": [ + "GRUB 2" + ] + }, + { + "regex": "^sha1\\$[a-z0-9]+\\$[a-f0-9]{40}$", + "matches": [ + "Django(SHA-1)" + ] + }, + { + "regex": "^[a-f0-9]{49}$", + "matches": [ + "Citrix Netscaler" + ] + }, + { + "regex": "^\\$S\\$[a-z0-9\\/.]{52}$", + "matches": [ + "Drupal > v7.x" + ] + }, + { + "regex": "^\\$5\\$(rounds=[0-9]+\\$)?[a-z0-9\\/.]{0,16}\\$[a-z0-9\\/.]{43}$", + "matches": [ + "SHA-256 Crypt" + ] + }, + { + "regex": "^0x[a-f0-9]{4}[a-f0-9]{16}[a-f0-9]{64}$", + "matches": [ + "Sybase ASE" + ] + }, + { + "regex": "^\\$6\\$(rounds=[0-9]+\\$)?[a-z0-9\\/.]{0,16}\\$[a-z0-9\\/.]{86}$", + "matches": [ + "SHA-512 Crypt" + ] + }, + { + "regex": "^\\$sha\\$[a-z0-9]{1,16}\\$([a-f0-9]{32}|[a-f0-9]{40}|[a-f0-9]{64}|[a-f0-9]{128}|[a-f0-9]{140})$", + "matches": [ + "Minecraft(AuthMe Reloaded)" + ] + }, + { + "regex": "^sha256\\$[a-z0-9]+\\$[a-f0-9]{64}$", + "matches": [ + "Django(SHA-256)" + ] + }, + { + "regex": "^sha384\\$[a-z0-9]+\\$[a-f0-9]{96}$", + "matches": [ + "Django(SHA-384)" + ] + }, + { + "regex": "^crypt1:[a-z0-9+=]{12}:[a-z0-9+=]{12}$", + "matches": [ + "Clavister Secure Gateway" + ] + }, + { + "regex": "^[a-f0-9]{112}$", + "matches": [ + "Cisco VPN Client(PCF-File)" + ] + }, + { + "regex": "^[a-f0-9]{1329}$", + "matches": [ + "Microsoft MSTSC(RDP-File)" + ] + }, + { + "regex": "^[^\\\\\\/:*?\"<>|]{1,20}[:]{2,3}([^\\\\\\/:*?\"<>|]{1,20})?:[a-f0-9]{48}:[a-f0-9]{48}:[a-f0-9]{16}$", + "matches": [ + "NetNTLMv1-VANILLA / NetNTLMv1+ESS" + ] + }, + { + "regex": "^([^\\\\\\/:*?\"<>|]{1,20}\\\\)?[^\\\\\\/:*?\"<>|]{1,20}[:]{2,3}([^\\\\\\/:*?\"<>|]{1,20}:)?[^\\\\\\/:*?\"<>|]{1,20}:[a-f0-9]{32}:[a-f0-9]+$", + "matches": [ + "NetNTLMv2" + ] + }, + { + "regex": "^\\$(krb5pa|mskrb5)\\$([0-9]{2})?\\$.+\\$[a-f0-9]{1,}$", + "matches": [ + "Kerberos 5 AS-REQ Pre-Auth" + ] + }, + { + "regex": "^\\$scram\\$[0-9]+\\$[a-z0-9\\/.]{16}\\$sha-1=[a-z0-9\\/.]{27},sha-256=[a-z0-9\\/.]{43},sha-512=[a-z0-9\\/.]{86}$", + "matches": [ + "SCRAM Hash" + ] + }, + { + "regex": "^[a-f0-9]{40}:[a-f0-9]{0,32}$", + "matches": [ + "Redmine Project Management Web App" + ] + }, + { + "regex": "^(.+)?\\$[a-f0-9]{16}$", + "matches": [ + "SAP CODVN B (BCODE)" + ] + }, + { + "regex": "^(.+)?\\$[a-f0-9]{40}$", + "matches": [ + "SAP CODVN F/G (PASSCODE)" + ] + }, + { + "regex": "^(.+\\$)?[a-z0-9\\/.+]{30}(:.+)?$", + "matches": [ + "Juniper Netscreen/SSG(ScreenOS)" + ] + }, + { + "regex": "^0x[a-f0-9]{60}\\s0x[a-f0-9]{40}$", + "matches": [ + "EPi" + ] + }, + { + "regex": "^[a-f0-9]{40}:[^*]{1,25}$", + "matches": [ + "SMF \u2265 v1.1" + ] + }, + { + "regex": "^(\\$wbb3\\$\\*1\\*)?[a-f0-9]{40}[:*][a-f0-9]{40}$", + "matches": [ + "Woltlab Burning Board 3.x" + ] + }, + { + "regex": "^[a-f0-9]{130}(:[a-f0-9]{40})?$", + "matches": [ + "IPMI2 RAKP HMAC-SHA1" + ] + }, + { + "regex": "^[a-f0-9]{32}:[0-9]+:[a-z0-9_.+-]+@[a-z0-9-]+\\.[a-z0-9-.]+$", + "matches": [ + "Lastpass" + ] + }, + { + "regex": "^[a-z0-9\\/.]{16}([:$].{1,})?$", + "matches": [ + "Cisco-ASA(MD5)" + ] + }, + { + "regex": "^\\$vnc\\$\\*[a-f0-9]{32}\\*[a-f0-9]{32}$", + "matches": [ + "VNC" + ] + }, + { + "regex": "^[a-z0-9]{32}(:([a-z0-9-]+\\.)?[a-z0-9-.]+\\.[a-z]{2,7}:.+:[0-9]+)?$", + "matches": [ + "DNSSEC(NSEC3)" + ] + }, + { + "regex": "^(user-.+:)?\\$racf\\$\\*.+\\*[a-f0-9]{16}$", + "matches": [ + "RACF" + ] + }, + { + "regex": "^\\$3\\$\\$[a-f0-9]{32}$", + "matches": [ + "NTHash(FreeBSD Variant)" + ] + }, + { + "regex": "^\\$sha1\\$[0-9]+\\$[a-z0-9\\/.]{0,64}\\$[a-z0-9\\/.]{28}$", + "matches": [ + "SHA-1 Crypt" + ] + }, + { + "regex": "^[a-f0-9]{70}$", + "matches": [ + "hMailServer" + ] + }, + { + "regex": "^[:\\$][AB][:\\$]([a-f0-9]{1,8}[:\\$])?[a-f0-9]{32}$", + "matches": [ + "MediaWiki" + ] + }, + { + "regex": "^[a-f0-9]{140}$", + "matches": [ + "Minecraft(xAuth)" + ] + }, + { + "regex": "^\\$pbkdf2(-sha1)?\\$[0-9]+\\$[a-z0-9\\/.]+\\$[a-z0-9\\/.]{27}$", + "matches": [ + "PBKDF2-SHA1(Generic)" + ] + }, + { + "regex": "^\\$pbkdf2-sha256\\$[0-9]+\\$[a-z0-9\\/.]+\\$[a-z0-9\\/.]{43}$", + "matches": [ + "PBKDF2-SHA256(Generic)" + ] + }, + { + "regex": "^\\$pbkdf2-sha512\\$[0-9]+\\$[a-z0-9\\/.]+\\$[a-z0-9\\/.]{86}$", + "matches": [ + "PBKDF2-SHA512(Generic)" + ] + }, + { + "regex": "^\\$p5k2\\$[0-9]+\\$[a-z0-9\\/+=-]+\\$[a-z0-9\\/+-]{27}=$", + "matches": [ + "PBKDF2(Cryptacular)" + ] + }, + { + "regex": "^\\$p5k2\\$[0-9]+\\$[a-z0-9\\/.]+\\$[a-z0-9\\/.]{32}$", + "matches": [ + "PBKDF2(Dwayne Litzenberger)" + ] + }, + { + "regex": "^{FSHP[0123]\\|[0-9]+\\|[0-9]+}[a-z0-9\\/+=]+$", + "matches": [ + "Fairly Secure Hashed Password" + ] + }, + { + "regex": "^\\$PHPS\\$.+\\$[a-f0-9]{32}$", + "matches": [ + "PHPS" + ] + }, + { + "regex": "^[0-9]{4}:[a-f0-9]{16}:[a-f0-9]{2080}$", + "matches": [ + "1Password(Agile Keychain)" + ] + }, + { + "regex": "^[a-f0-9]{64}:[a-f0-9]{32}:[0-9]{5}:[a-f0-9]{608}$", + "matches": [ + "1Password(Cloud Keychain)" + ] + }, + { + "regex": "^[a-f0-9]{256}:[a-f0-9]{256}:[a-f0-9]{16}:[a-f0-9]{16}:[a-f0-9]{320}:[a-f0-9]{16}:[a-f0-9]{40}:[a-f0-9]{40}:[a-f0-9]{32}$", + "matches": [ + "IKE-PSK MD5" + ] + }, + { + "regex": "^[a-f0-9]{256}:[a-f0-9]{256}:[a-f0-9]{16}:[a-f0-9]{16}:[a-f0-9]{320}:[a-f0-9]{16}:[a-f0-9]{40}:[a-f0-9]{40}:[a-f0-9]{40}$", + "matches": [ + "IKE-PSK SHA1" + ] + }, + { + "regex": "^[a-z0-9\\/+]{27}=$", + "matches": [ + "PeopleSoft" + ] + }, + { + "regex": "^crypt\\$[a-f0-9]{5}\\$[a-z0-9\\/.]{13}$", + "matches": [ + "Django(DES Crypt Wrapper)" + ] + }, + { + "regex": "^(\\$django\\$\\*1\\*)?pbkdf2_sha256\\$[0-9]+\\$[a-z0-9]+\\$[a-z0-9\\/+=]{44}$", + "matches": [ + "Django(PBKDF2-HMAC-SHA256)" + ] + }, + { + "regex": "^pbkdf2_sha1\\$[0-9]+\\$[a-z0-9]+\\$[a-z0-9\\/+=]{28}$", + "matches": [ + "Django(PBKDF2-HMAC-SHA1)" + ] + }, + { + "regex": "^bcrypt(\\$2[axy]|\\$2)\\$[0-9]{2}\\$[a-z0-9\\/.]{53}$", + "matches": [ + "Django(bcrypt)" + ] + }, + { + "regex": "^md5\\$[a-f0-9]+\\$[a-f0-9]{32}$", + "matches": [ + "Django(MD5)" + ] + }, + { + "regex": "^\\{PKCS5S2\\}[a-z0-9\\/+]{64}$", + "matches": [ + "PBKDF2(Atlassian)" + ] + }, + { + "regex": "^md5[a-f0-9]{32}$", + "matches": [ + "PostgreSQL MD5" + ] + }, + { + "regex": "^\\([a-z0-9\\/+]{49}\\)$", + "matches": [ + "Lotus Notes/Domino 8" + ] + }, + { + "regex": "^SCRYPT:[0-9]{1,}:[0-9]{1}:[0-9]{1}:[a-z0-9:\\/+=]{1,}$", + "matches": [ + "scrypt" + ] + }, + { + "regex": "^\\$8\\$[a-z0-9\\/.]{14}\\$[a-z0-9\\/.]{43}$", + "matches": [ + "Cisco Type 8" + ] + }, + { + "regex": "^\\$9\\$[a-z0-9\\/.]{14}\\$[a-z0-9\\/.]{43}$", + "matches": [ + "Cisco Type 9" + ] + }, + { + "regex": "^\\$office\\$\\*2007\\*[0-9]{2}\\*[0-9]{3}\\*[0-9]{2}\\*[a-z0-9]{32}\\*[a-z0-9]{32}\\*[a-z0-9]{40}$", + "matches": [ + "Microsoft Office 2007" + ] + }, + { + "regex": "^\\$office\\$\\*2010\\*[0-9]{6}\\*[0-9]{3}\\*[0-9]{2}\\*[a-z0-9]{32}\\*[a-z0-9]{32}\\*[a-z0-9]{64}$", + "matches": [ + "Microsoft Office 2010" + ] + }, + { + "regex": "^\\$office\\$\\*2013\\*[0-9]{6}\\*[0-9]{3}\\*[0-9]{2}\\*[a-z0-9]{32}\\*[a-z0-9]{32}\\*[a-z0-9]{64}$", + "matches": [ + "Microsoft Office 2013" + ] + }, + { + "regex": "^\\$fde\\$[0-9]{2}\\$[a-f0-9]{32}\\$[0-9]{2}\\$[a-f0-9]{32}\\$[a-f0-9]{3072}$", + "matches": [ + "Android FDE \u2264 4.3" + ] + }, + { + "regex": "^\\$oldoffice\\$[01]\\*[a-f0-9]{32}\\*[a-f0-9]{32}\\*[a-f0-9]{32}$", + "matches": [ + "Microsoft Office \u2264 2003 (MD5+RC4)", + "Microsoft Office \u2264 2003 (MD5+RC4) collider-mode #1", + "Microsoft Office \u2264 2003 (MD5+RC4) collider-mode #2" + ] + }, + { + "regex": "^\\$oldoffice\\$[34]\\*[a-f0-9]{32}\\*[a-f0-9]{32}\\*[a-f0-9]{40}$", + "matches": [ + "Microsoft Office \u2264 2003 (SHA1+RC4)", + "Microsoft Office \u2264 2003 (SHA1+RC4) collider-mode #1", + "Microsoft Office \u2264 2003 (SHA1+RC4) collider-mode #2" + ] + }, + { + "regex": "^(\\$radmin2\\$)?[a-f0-9]{32}$", + "matches": [ + "RAdmin v2.x" + ] + }, + { + "regex": "^{x-issha,\\s[0-9]{4}}[a-z0-9\\/+=]+$", + "matches": [ + "SAP CODVN H (PWDSALTEDHASH) iSSHA-1" + ] + }, + { + "regex": "^\\$cram_md5\\$[a-z0-9\\/+=-]+\\$[a-z0-9\\/+=-]{52}$", + "matches": [ + "CRAM-MD5" + ] + }, + { + "regex": "^[a-f0-9]{16}:2:4:[a-f0-9]{32}$", + "matches": [ + "SipHash" + ] + }, + { + "regex": "^[a-f0-9]{4,}$", + "matches": [ + "Cisco Type 7" + ] + }, + { + "regex": "^[a-z0-9\\/.]{13,}$", + "matches": [ + "BigCrypt" + ] + }, + { + "regex": "^(\\$cisco4\\$)?[a-z0-9\\/.]{43}$", + "matches": [ + "Cisco Type 4" + ] + }, + { + "regex": "^bcrypt_sha256\\$\\$(2[axy]|2)\\$[0-9]+\\$[a-z0-9\\/.]{53}$", + "matches": [ + "Django(bcrypt-SHA256)" + ] + }, + { + "regex": "^\\$postgres\\$.[^\\*]+[*:][a-f0-9]{1,32}[*:][a-f0-9]{32}$", + "matches": [ + "PostgreSQL Challenge-Response Authentication (MD5)" + ] + }, + { + "regex": "^\\$siemens-s7\\$[0-9]{1}\\$[a-f0-9]{40}\\$[a-f0-9]{40}$", + "matches": [ + "Siemens-S7" + ] + }, + { + "regex": "^(\\$pst\\$)?[a-f0-9]{8}$", + "matches": [ + "Microsoft Outlook PST" + ] + }, + { + "regex": "^sha256[:$][0-9]+[:$][a-z0-9\\/+]+[:$][a-z0-9\\/+]{32,128}$", + "matches": [ + "PBKDF2-HMAC-SHA256(PHP)" + ] + }, + { + "regex": "^(\\$dahua\\$)?[a-z0-9]{8}$", + "matches": [ + "Dahua" + ] + }, + { + "regex": "^\\$mysqlna\\$[a-f0-9]{40}[:*][a-f0-9]{40}$", + "matches": [ + "MySQL Challenge-Response Authentication (SHA1)" + ] + }, + { + "regex": "^\\$pdf\\$[24]\\*[34]\\*128\\*[0-9-]{1,5}\\*1\\*(16|32)\\*[a-f0-9]{32,64}\\*32\\*[a-f0-9]{64}\\*(8|16|32)\\*[a-f0-9]{16,64}$", + "matches": [ + "PDF 1.4 - 1.6 (Acrobat 5 - 8)" + ] + } +]