mirror of
https://github.com/shmilylty/OneForAll.git
synced 2026-08-26 04:47:48 +08:00
添加fuzz模式支持字典功能
This commit is contained in:
@@ -77,39 +77,16 @@ def detect_wildcard(domain, authoritative_ns):
|
||||
wildcard = do_query_a(random_subdomain, resolver)
|
||||
except Exception as e:
|
||||
logger.log('DEBUG', e.args)
|
||||
logger.log('ALERT', f'Multiple detection errors, so temporarily {domain} does not use wildcard dns record')
|
||||
logger.log('ALERT', f'Multiple detection errors, so temporarily {domain} '
|
||||
f'does not use wildcard dns record')
|
||||
return False
|
||||
else:
|
||||
return wildcard
|
||||
|
||||
|
||||
def gen_fuzz_subdomains(expression, rule):
|
||||
def gen_subdomains(expression, path):
|
||||
"""
|
||||
Generate subdomains based on fuzz mode
|
||||
|
||||
:param str expression: generate subdomains's expression
|
||||
:param str rule: regexp rule
|
||||
:return list subdomains: list of subdomains
|
||||
"""
|
||||
subdomains = list()
|
||||
fuzz_count = exrex.count(rule)
|
||||
if fuzz_count > 10000000:
|
||||
logger.log('ALERT', f'The dictionary generated by this rule is too large:{fuzz_count} > 10000000')
|
||||
logger.log('DEBUG', f'Dictionary size based on fuzz mode: {fuzz_count}')
|
||||
for fuzz_string in exrex.generate(rule):
|
||||
fuzz_string = fuzz_string.lower()
|
||||
if not fuzz_string.isalnum():
|
||||
continue
|
||||
fuzz_domain = expression.replace('*', fuzz_string)
|
||||
subdomains.append(fuzz_domain)
|
||||
random_domain = random.choice(subdomains)
|
||||
logger.log('ALERT', f'Please check whether {random_domain} is correct or not')
|
||||
return subdomains
|
||||
|
||||
|
||||
def gen_word_subdomains(expression, path):
|
||||
"""
|
||||
Generate subdomains based on word mode
|
||||
Generate subdomains
|
||||
|
||||
:param str expression: generate subdomains's expression
|
||||
:param str path: path of wordlist
|
||||
@@ -129,12 +106,59 @@ def gen_word_subdomains(expression, path):
|
||||
word = word[:-1]
|
||||
subdomain = expression.replace('*', word)
|
||||
subdomains.append(subdomain)
|
||||
size = len(subdomains)
|
||||
logger.log('DEBUG', f'The size of the dictionary generated by {path} is {size}')
|
||||
if size == 0:
|
||||
logger.log('ALERT', 'Please check the dictionary content!')
|
||||
else:
|
||||
random_domain = random.choice(subdomains)
|
||||
logger.log('DEBUG', f'Dictionary based on word mode size: {len(subdomains)}')
|
||||
logger.log('ALERT', f'Please check whether {random_domain} is correct or not')
|
||||
return subdomains
|
||||
|
||||
|
||||
def gen_fuzz_subdomains(expression, rule, fuzzlist):
|
||||
"""
|
||||
Generate subdomains based on fuzz mode
|
||||
|
||||
:param str expression: generate subdomains's expression
|
||||
:param str rule: regexp rule
|
||||
:param str fuzzlist: fuzz dictionary
|
||||
:return list subdomains: list of subdomains
|
||||
"""
|
||||
subdomains = list()
|
||||
if fuzzlist:
|
||||
fuzz_domain = gen_subdomains(expression, fuzzlist)
|
||||
subdomains = subdomains.extend(fuzz_domain)
|
||||
if rule:
|
||||
fuzz_count = exrex.count(rule)
|
||||
if fuzz_count > 10000000:
|
||||
logger.log('ALERT', f'The dictionary generated by this rule is too large: '
|
||||
f'{fuzz_count} > 10000000')
|
||||
for fuzz_string in exrex.generate(rule):
|
||||
fuzz_string = fuzz_string.lower()
|
||||
if not fuzz_string.isalnum():
|
||||
continue
|
||||
fuzz_domain = expression.replace('*', fuzz_string)
|
||||
subdomains.append(fuzz_domain)
|
||||
random_domain = random.choice(subdomains)
|
||||
logger.log('ALERT', f'Please check whether {random_domain} is correct or not')
|
||||
logger.log('DEBUG', f'Dictionary size based on fuzz mode: {len(subdomains)}')
|
||||
return subdomains
|
||||
|
||||
|
||||
def gen_word_subdomains(expression, path):
|
||||
"""
|
||||
Generate subdomains based on word mode
|
||||
|
||||
:param str expression: generate subdomains's expression
|
||||
:param str path: path of wordlist
|
||||
:return list subdomains: list of subdomains
|
||||
"""
|
||||
subdomains = gen_subdomains(expression, path)
|
||||
logger.log('DEBUG', f'Dictionary based on word mode size: {len(subdomains)}')
|
||||
return subdomains
|
||||
|
||||
|
||||
def query_domain_ns_a(ns_list):
|
||||
logger.log('INFOR', f'Querying A record from authoritative name server: {ns_list} ')
|
||||
if not isinstance(ns_list, list):
|
||||
@@ -172,7 +196,8 @@ def query_domain_ns(domain):
|
||||
|
||||
@tenacity.retry(stop=tenacity.stop_after_attempt(2))
|
||||
def get_wildcard_record(domain, resolver):
|
||||
logger.log('INFOR', f'Query {domain} \'s wildcard dns record in authoritative name server')
|
||||
logger.log('INFOR', f"Query {domain} 's wildcard dns record "
|
||||
f"in authoritative name server")
|
||||
try:
|
||||
answer = resolver.query(domain, 'A')
|
||||
# 如果查询随机域名A记录时抛出Timeout异常则重新查询
|
||||
@@ -186,7 +211,8 @@ def get_wildcard_record(domain, resolver):
|
||||
return None, None
|
||||
except Exception as e:
|
||||
logger.log('ERROR', e.args)
|
||||
logger.log('ERROR', f'Query {domain} wildcard dns record in authoritative name server error')
|
||||
logger.log('ERROR', f'Query {domain} wildcard dns record in '
|
||||
f'authoritative name server error')
|
||||
exit(1)
|
||||
else:
|
||||
if answer.rrset is None:
|
||||
@@ -444,6 +470,7 @@ class Brute(Module):
|
||||
brute.py --target domain.com --word True --wordlist subnames.txt run
|
||||
brute.py --target domain.com --word True --recursive True --depth 2 run
|
||||
brute.py --target d.com --fuzz True --place m.*.d.com --rule '[a-z]' run
|
||||
brute.py --target d.com --fuzz True --place m.*.d.com --fuzzlist subnames.txt run
|
||||
|
||||
Note:
|
||||
--alive True/False Only export alive subdomains or not (default False)
|
||||
@@ -455,14 +482,15 @@ class Brute(Module):
|
||||
:param int process: Number of processes (default 1)
|
||||
:param int concurrent: Number of concurrent (default 10000)
|
||||
:param bool word: Use word mode generate dictionary (default False)
|
||||
:param str wordlist: Dictionary path used in word mode (default use ./config/setting.py)
|
||||
:param str wordlist: Dictionary path used in word mode (default use ./config/default.py)
|
||||
:param bool recursive: Use recursion (default False)
|
||||
:param int depth: Recursive depth (default 2)
|
||||
:param str nextlist: Dictionary file path used by recursive (default use ./config/setting.py)
|
||||
:param str nextlist: Dictionary file path used by recursive (default use ./config/default.py)
|
||||
:param bool fuzz: Use fuzz mode generate dictionary (default False)
|
||||
:param bool alive: Only export alive subdomains (default False)
|
||||
:param str place: Designated fuzz position (required if use fuzz mode)
|
||||
:param str rule: Specify the regexp rules used in fuzz mode (required if use fuzz mode)
|
||||
:param str fuzzlist: Dictionary path used in fuzz mode (default use ./config/default.py)
|
||||
:param bool export: Export the results (default True)
|
||||
:param str format: Result format (default csv)
|
||||
:param str path: Result directory (default None)
|
||||
@@ -471,8 +499,8 @@ class Brute(Module):
|
||||
|
||||
def __init__(self, target, process=None, concurrent=None, word=False,
|
||||
wordlist=None, recursive=False, depth=None, nextlist=None,
|
||||
fuzz=False, place=None, rule=None, export=True, alive=True,
|
||||
format='csv', path=None):
|
||||
fuzz=False, place=None, rule=None, fuzzlist=None, export=True,
|
||||
alive=True, format='csv', path=None):
|
||||
Module.__init__(self)
|
||||
self.module = 'Brute'
|
||||
self.source = 'Brute'
|
||||
@@ -487,6 +515,7 @@ class Brute(Module):
|
||||
self.fuzz = fuzz or settings.enable_fuzz
|
||||
self.place = place or settings.fuzz_place
|
||||
self.rule = rule or settings.fuzz_rule
|
||||
self.fuzzlist = fuzzlist or settings.fuzz_list
|
||||
self.export = export
|
||||
self.alive = alive
|
||||
self.format = format
|
||||
@@ -516,7 +545,7 @@ class Brute(Module):
|
||||
# set可以合并list
|
||||
dict_set = dict_set.union(word_subdomains)
|
||||
if self.fuzz:
|
||||
fuzz_subdomains = gen_fuzz_subdomains(self.place, self.rule)
|
||||
fuzz_subdomains = gen_fuzz_subdomains(self.place, self.rule, self.fuzzlist)
|
||||
dict_set = dict_set.union(fuzz_subdomains)
|
||||
count = len(dict_set)
|
||||
logger.log('INFOR', f'Dictionary size: {count}')
|
||||
@@ -532,8 +561,11 @@ class Brute(Module):
|
||||
if len(self.domains) > 1:
|
||||
self.bulk = True
|
||||
if self.fuzz:
|
||||
if self.place is None or self.rule is None:
|
||||
logger.log('FATAL', f'No fuzz position or rules specified')
|
||||
if self.place is None:
|
||||
logger.log('FATAL', f'No fuzz position specified')
|
||||
exit(1)
|
||||
if self.rule is None and self.fuzzlist is None:
|
||||
logger.log('FATAL', f'No fuzz rules or fuzz dictionary specified')
|
||||
exit(1)
|
||||
if self.bulk:
|
||||
logger.log('FATAL', f'Cannot use fuzz mode in the bulk brute')
|
||||
@@ -614,7 +646,7 @@ class Brute(Module):
|
||||
return self.subdomains
|
||||
|
||||
def run(self):
|
||||
logger.log('INFOR', f'Start runing {self.source} module')
|
||||
logger.log('INFOR', f'Start running {self.source} module')
|
||||
if self.check_env:
|
||||
utils.check_env()
|
||||
self.domains = utils.get_domains(self.target)
|
||||
@@ -622,7 +654,8 @@ class Brute(Module):
|
||||
for self.domain in self.domains:
|
||||
self.check_brute_params()
|
||||
if self.recursive_brute:
|
||||
logger.log('INFOR', f'Start recursively brute the first layer subdomain of {self.domain}')
|
||||
logger.log('INFOR', f'Start recursively brute the 1 layer subdomain'
|
||||
f' of {self.domain}')
|
||||
valid_subdomains = self.main(self.domain)
|
||||
all_subdomains.extend(valid_subdomains)
|
||||
|
||||
@@ -631,8 +664,8 @@ class Brute(Module):
|
||||
if self.recursive_brute:
|
||||
for layer_num in range(1, self.recursive_depth):
|
||||
# 之前已经做过1层子域爆破 当前实际递归层数是layer+1
|
||||
logger.log('INFOR', f'Start recursively brute'
|
||||
f'the {layer_num + 1} layer subdomain of {self.domain}')
|
||||
logger.log('INFOR', f'Start recursively brute the {layer_num+1} layer'
|
||||
f' subdomain of {self.domain}')
|
||||
for subdomain in all_subdomains:
|
||||
self.place = '*.' + subdomain
|
||||
# 进行下一层子域爆破的限制条件
|
||||
|
||||
+2
-1
@@ -73,7 +73,8 @@ only_save_valid = True # 是否在处理爆破结果时只存入解析成功的
|
||||
check_time = 10 # 检查字典配置停留时间(默认10秒)
|
||||
enable_fuzz = False # 是否使用fuzz模式枚举域名
|
||||
fuzz_place = None # 指定爆破的位置 指定的位置用`@`表示 示例:www.@.example.com
|
||||
fuzz_rule = None # fuzz域名的正则 示例:'[a-z][0-9]' 表示第一位是字母 第二位是数字
|
||||
fuzz_rule = None # fuzz域名使用的正则表达式 示例:'[a-z][0-9]' 表示第一位是字母 第二位是数字
|
||||
fuzz_list = None # fuzz域名使用的字典路径
|
||||
brute_ip_blacklist = {'0.0.0.0', '0.0.0.1'} # IP黑名单 子域解析到IP黑名单则标记为非法子域
|
||||
ip_appear_maximum = 100 # 多个子域解析到同一IP次数超过100次则标记为非法(泛解析)子域
|
||||
|
||||
|
||||
Reference in New Issue
Block a user