mirror of
https://github.com/shmilylty/OneForAll.git
synced 2026-08-26 12:57:50 +08:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e5255ae700 | |||
| 7c7c33c718 | |||
| 186532e12b | |||
| 2b1a041e7f | |||
| bfd8736640 | |||
| 566e6e224c | |||
| cefa100ba6 | |||
| 202f0c3aed | |||
| 4d1e0610b1 | |||
| bb5d5fc83e | |||
| 4febfaee47 | |||
| 9ecfda2291 | |||
| 3e3bd6f3cb | |||
| b5de6062ba |
@@ -0,0 +1 @@
|
|||||||
|
.git/
|
||||||
@@ -55,6 +55,8 @@ class Domain(object):
|
|||||||
|
|
||||||
:return: registered domain result
|
:return: registered domain result
|
||||||
"""
|
"""
|
||||||
|
if not settings.use_tld_extract:
|
||||||
|
return self.string
|
||||||
result = self.extract()
|
result = self.extract()
|
||||||
if result:
|
if result:
|
||||||
return result.registered_domain
|
return result.registered_domain
|
||||||
|
|||||||
+2
-2
@@ -248,11 +248,11 @@ def save_to_file(path, data):
|
|||||||
:return: 保存成功与否
|
:return: 保存成功与否
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
with open(path, 'w', errors='ignore', newline='') as file:
|
with open(path, 'w', errors='ignore', newline='', encoding='utf-8') as file:
|
||||||
file.write(data)
|
file.write(data)
|
||||||
return True
|
return True
|
||||||
except TypeError:
|
except TypeError:
|
||||||
with open(path, 'wb') as file:
|
with open(path, 'wb', encoding='utf-8') as file:
|
||||||
file.write(data)
|
file.write(data)
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
+4
-1
@@ -88,4 +88,7 @@ fullhunt_api_key = ''
|
|||||||
quake_api_key = ''
|
quake_api_key = ''
|
||||||
|
|
||||||
#https://www.racent.com/ctlog F2>Network抓包获取Token
|
#https://www.racent.com/ctlog F2>Network抓包获取Token
|
||||||
racent_api_token = ''
|
racent_api_token = ''
|
||||||
|
|
||||||
|
# https://windvane.lichoin.com/
|
||||||
|
windvane_api_token = ''
|
||||||
|
|||||||
@@ -250,3 +250,6 @@ hunter_api_key = ''
|
|||||||
|
|
||||||
# https://api-docs.fullhunt.io/
|
# https://api-docs.fullhunt.io/
|
||||||
fullhunt_api_key = ''
|
fullhunt_api_key = ''
|
||||||
|
|
||||||
|
# https://windvane.lichoin.com/
|
||||||
|
windvane_api_token = ''
|
||||||
|
|||||||
@@ -100,3 +100,9 @@ enable_random_ua = True # 使用随机UA(默认True,开启可以覆盖request
|
|||||||
# 搜索模块设置
|
# 搜索模块设置
|
||||||
enable_recursive_search = False # 递归搜索子域
|
enable_recursive_search = False # 递归搜索子域
|
||||||
search_recursive_times = 2 # 递归搜索层数
|
search_recursive_times = 2 # 递归搜索层数
|
||||||
|
|
||||||
|
# 网络空间测绘引擎设置
|
||||||
|
cam_records_maximum_per_domain = 1000 # 对于单个主域名,在测绘引擎中的最多查询多少条记录,防止泛解析和CDN浪费积分,对 fofa, hunter, quake, zoomeye 生效,最低为100
|
||||||
|
|
||||||
|
# 是否从输入的数据中使用tldextract提取主域名。若设为 False,OneForAll会直接将输入的域名作为主域名,比如北京分公司的域名 beijing.10086.com 就不会被解析成母公司的域名 10086.com
|
||||||
|
use_tld_extract = True
|
||||||
@@ -9,7 +9,7 @@ class CensysAPI(Query):
|
|||||||
self.domain = domain
|
self.domain = domain
|
||||||
self.module = 'Certificate'
|
self.module = 'Certificate'
|
||||||
self.source = "CensysAPIQuery"
|
self.source = "CensysAPIQuery"
|
||||||
self.addr = 'https://search.censys.io/api/v1/search/certificates'
|
self.addr = 'https://search.censys.io/api/v2/certificates/search'
|
||||||
self.id = settings.censys_api_id
|
self.id = settings.censys_api_id
|
||||||
self.secret = settings.censys_api_secret
|
self.secret = settings.censys_api_secret
|
||||||
self.delay = 3.0 # Censys 接口查询速率限制 最快2.5秒查1次
|
self.delay = 3.0 # Censys 接口查询速率限制 最快2.5秒查1次
|
||||||
@@ -20,26 +20,30 @@ class CensysAPI(Query):
|
|||||||
"""
|
"""
|
||||||
self.header = self.get_header()
|
self.header = self.get_header()
|
||||||
self.proxy = self.get_proxy(self.source)
|
self.proxy = self.get_proxy(self.source)
|
||||||
data = {
|
params = {
|
||||||
'query': f'parsed.names: {self.domain}',
|
'q': f'names: {self.domain}',
|
||||||
'page': 1,
|
'per_page': 100,
|
||||||
'fields': ['parsed.subject_dn', 'parsed.names'],
|
}
|
||||||
'flatten': True}
|
resp = self.get(self.addr, params=params, auth=(self.id, self.secret))
|
||||||
resp = self.post(self.addr, json=data, auth=(self.id, self.secret))
|
|
||||||
if not resp:
|
if not resp:
|
||||||
return
|
return
|
||||||
json = resp.json()
|
json = resp.json()
|
||||||
status = json.get('status')
|
status = json.get('status')
|
||||||
if status != 'ok':
|
if status != 'OK':
|
||||||
logger.log('ALERT', f'{self.source} module {status}')
|
logger.log('ALERT', f'{self.source} module {status}')
|
||||||
return
|
return
|
||||||
subdomains = self.match_subdomains(resp.text)
|
subdomains = self.match_subdomains(resp.text)
|
||||||
self.subdomains.update(subdomains)
|
self.subdomains.update(subdomains)
|
||||||
pages = json.get('metadata').get('pages')
|
next_cursor = json.get("result").get("links").get("next")
|
||||||
for page in range(2, pages + 1):
|
while next_cursor:
|
||||||
data['page'] = page
|
tmp_params = {
|
||||||
resp = self.post(self.addr, json=data, auth=(self.id, self.secret))
|
'q': f'names: {self.domain}',
|
||||||
self.subdomains = self.collect_subdomains(resp)
|
'per_page': 100,
|
||||||
|
"cursor": next_cursor
|
||||||
|
}
|
||||||
|
tmp_resp = self.get(self.addr, params=tmp_params, auth=(self.id, self.secret))
|
||||||
|
self.subdomains = self.collect_subdomains(tmp_resp)
|
||||||
|
next_cursor = tmp_resp.json().get("result").get("links").get("next")
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
from config import settings
|
||||||
|
from common.query import Query
|
||||||
|
|
||||||
|
|
||||||
|
class Windvane(Query):
|
||||||
|
def __init__(self, domain):
|
||||||
|
Query.__init__(self)
|
||||||
|
self.domain = domain
|
||||||
|
self.module = 'Dataset'
|
||||||
|
self.source = "WindvaneQuery"
|
||||||
|
self.addr = 'https://windvane.lichoin.com/trpc.backendhub.public.WindvaneService/ListSubDomain'
|
||||||
|
self.api_key = settings.windvane_api_token
|
||||||
|
self.page_size = 1000
|
||||||
|
|
||||||
|
def query(self):
|
||||||
|
"""
|
||||||
|
向接口查询子域并做子域匹配
|
||||||
|
"""
|
||||||
|
self.header = self.get_header()
|
||||||
|
self.header.update({
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Referer': 'https://windvane.lichoin.com'
|
||||||
|
})
|
||||||
|
|
||||||
|
if self.api_key:
|
||||||
|
self.header.update({'X-Api-Key': self.api_key})
|
||||||
|
|
||||||
|
self.proxy = self.get_proxy(self.source)
|
||||||
|
|
||||||
|
page = 1
|
||||||
|
total_pages = 1
|
||||||
|
all_subdomains = []
|
||||||
|
|
||||||
|
while page <= total_pages:
|
||||||
|
data = {
|
||||||
|
"domain": self.domain,
|
||||||
|
"page_request": {
|
||||||
|
"page": page,
|
||||||
|
"count": self.page_size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.post(self.addr, json=data)
|
||||||
|
if not resp:
|
||||||
|
break
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = resp.json()
|
||||||
|
|
||||||
|
if result.get('code') != 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
data_section = result.get('data', {})
|
||||||
|
|
||||||
|
subdomains = self.match_subdomains(resp)
|
||||||
|
if not subdomains:
|
||||||
|
break
|
||||||
|
self.subdomains.update(subdomains)
|
||||||
|
|
||||||
|
page_info = data_section.get('page_response', {})
|
||||||
|
total_pages = int(page_info.get('total_page', 1))
|
||||||
|
|
||||||
|
page += 1
|
||||||
|
|
||||||
|
except:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""
|
||||||
|
类执行入口
|
||||||
|
"""
|
||||||
|
self.begin()
|
||||||
|
self.query()
|
||||||
|
self.finish()
|
||||||
|
self.save_json()
|
||||||
|
self.gen_result()
|
||||||
|
self.save_db()
|
||||||
|
|
||||||
|
|
||||||
|
def run(domain):
|
||||||
|
"""
|
||||||
|
类统一调用入口
|
||||||
|
|
||||||
|
:param str domain: 域名
|
||||||
|
"""
|
||||||
|
query = Windvane(domain)
|
||||||
|
query.run()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
run('baidu.com')
|
||||||
@@ -7,7 +7,7 @@ class QueryMX(Lookup):
|
|||||||
self.domain = domain
|
self.domain = domain
|
||||||
self.module = 'dnsquery'
|
self.module = 'dnsquery'
|
||||||
self.source = "QueryMX"
|
self.source = "QueryMX"
|
||||||
self.type = 'MX' # 利用的DNS记录的MX记录收集子域
|
self.qtype = 'MX' # 利用的DNS记录的MX记录收集子域
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class FoFa(Search):
|
|||||||
self.page_num = 1
|
self.page_num = 1
|
||||||
subdomain_encode = f'domain="{self.domain}"'.encode('utf-8')
|
subdomain_encode = f'domain="{self.domain}"'.encode('utf-8')
|
||||||
query_data = base64.b64encode(subdomain_encode)
|
query_data = base64.b64encode(subdomain_encode)
|
||||||
while True:
|
while 100 * self.page_num < settings.cam_records_maximum_per_domain:
|
||||||
time.sleep(self.delay)
|
time.sleep(self.delay)
|
||||||
self.header = self.get_header()
|
self.header = self.get_header()
|
||||||
self.proxy = self.get_proxy(self.source)
|
self.proxy = self.get_proxy(self.source)
|
||||||
@@ -32,7 +32,7 @@ class FoFa(Search):
|
|||||||
'qbase64': query_data,
|
'qbase64': query_data,
|
||||||
'page': self.page_num,
|
'page': self.page_num,
|
||||||
'full': 'true',
|
'full': 'true',
|
||||||
'size': 1000}
|
'size': min(1000, settings.cam_records_maximum_per_domain)}
|
||||||
resp = self.get(self.addr, query)
|
resp = self.get(self.addr, query)
|
||||||
if not resp:
|
if not resp:
|
||||||
return
|
return
|
||||||
@@ -42,7 +42,7 @@ class FoFa(Search):
|
|||||||
break
|
break
|
||||||
self.subdomains.update(subdomains)
|
self.subdomains.update(subdomains)
|
||||||
size = resp_json.get('size')
|
size = resp_json.get('size')
|
||||||
if size < 1000:
|
if size < min(1000, settings.cam_records_maximum_per_domain):
|
||||||
break
|
break
|
||||||
self.page_num += 1
|
self.page_num += 1
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class Hunter(Search):
|
|||||||
self.page_num = 1
|
self.page_num = 1
|
||||||
subdomain_encode = f'domain_suffix="{self.domain}"'.encode('utf-8')
|
subdomain_encode = f'domain_suffix="{self.domain}"'.encode('utf-8')
|
||||||
query_data = base64.b64encode(subdomain_encode)
|
query_data = base64.b64encode(subdomain_encode)
|
||||||
while True:
|
while 100 * self.page_num < settings.cam_records_maximum_per_domain:
|
||||||
time.sleep(self.delay)
|
time.sleep(self.delay)
|
||||||
self.header = self.get_header()
|
self.header = self.get_header()
|
||||||
self.proxy = self.get_proxy(self.source)
|
self.proxy = self.get_proxy(self.source)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class Quake(Search):
|
|||||||
"""
|
"""
|
||||||
self.per_page_num = 100
|
self.per_page_num = 100
|
||||||
self.page_num = 0
|
self.page_num = 0
|
||||||
while True:
|
while self.per_page_num * self.page_num < settings.cam_records_maximum_per_domain:
|
||||||
time.sleep(self.delay)
|
time.sleep(self.delay)
|
||||||
self.header = self.get_header()
|
self.header = self.get_header()
|
||||||
self.header.update({'Content-Type': 'application/json'})
|
self.header.update({'Content-Type': 'application/json'})
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class ZoomEyeAPI(Search):
|
|||||||
"""
|
"""
|
||||||
self.per_page_num = 30
|
self.per_page_num = 30
|
||||||
self.page_num = 1
|
self.page_num = 1
|
||||||
while True:
|
while self.per_page_num * self.page_num < settings.cam_records_maximum_per_domain:
|
||||||
time.sleep(self.delay)
|
time.sleep(self.delay)
|
||||||
self.header = self.get_header()
|
self.header = self.get_header()
|
||||||
self.header.update({'API-KEY': self.key})
|
self.header.update({'API-KEY': self.key})
|
||||||
|
|||||||
+3
-2
@@ -1,10 +1,10 @@
|
|||||||
beautifulsoup4==4.11.1
|
beautifulsoup4==4.11.1
|
||||||
bs4==0.0.1
|
bs4==0.0.1
|
||||||
certifi==2023.7.22
|
certifi==2022.06.15
|
||||||
chardet==5.0.0
|
chardet==5.0.0
|
||||||
colorama==0.4.4
|
colorama==0.4.4
|
||||||
dnspython==2.2.1
|
dnspython==2.2.1
|
||||||
exrex==0.10.5
|
exrex==0.11.0
|
||||||
fire==0.4.0
|
fire==0.4.0
|
||||||
future==0.18.2
|
future==0.18.2
|
||||||
idna==3.3
|
idna==3.3
|
||||||
@@ -20,3 +20,4 @@ tqdm==4.64.0
|
|||||||
treelib==1.6.1
|
treelib==1.6.1
|
||||||
urllib3==1.26.9
|
urllib3==1.26.9
|
||||||
win32-setctime==1.1.0
|
win32-setctime==1.1.0
|
||||||
|
setuptools
|
||||||
|
|||||||
Reference in New Issue
Block a user