mirror of
https://github.com/shmilylty/OneForAll.git
synced 2026-08-26 04:47:48 +08:00
254 lines
8.6 KiB
Python
254 lines
8.6 KiB
Python
#!/usr/bin/python3
|
||
# coding=utf-8
|
||
|
||
"""
|
||
OneForAll is a powerful subdomain collection tool
|
||
|
||
:copyright: Copyright (c) 2019, Jing Ling. All rights reserved.
|
||
:license: GNU General Public License v3.0, see LICENSE for more details.
|
||
"""
|
||
|
||
from datetime import datetime
|
||
|
||
import fire
|
||
|
||
import dbexport
|
||
from brute import Brute
|
||
from collect import Collect
|
||
from common import utils, resolve, request
|
||
from common.database import Database
|
||
from config import setting
|
||
from config.log import logger
|
||
from takeover import Takeover
|
||
|
||
yellow = '\033[01;33m'
|
||
white = '\033[01;37m'
|
||
green = '\033[01;32m'
|
||
blue = '\033[01;34m'
|
||
red = '\033[1;31m'
|
||
end = '\033[0m'
|
||
|
||
version = 'v0.2.0#dev'
|
||
message = white + '{' + red + version + white + '}'
|
||
|
||
banner = f"""
|
||
OneForAll is a powerful subdomain collection tool{yellow}
|
||
___ _ _
|
||
___ ___ ___| _|___ ___ ___| | | {message}{green}
|
||
| . | | -_| _| . | _| .'| | | {blue}
|
||
|___|_|_|___|_| |___|_| |__,|_|_| {white}git.io/fjHT1
|
||
|
||
{red}OneForAll is under development and make a lot of iteration, update every time before use please!!{end}
|
||
"""
|
||
|
||
|
||
class OneForAll(object):
|
||
"""
|
||
OneForAll help summary page
|
||
|
||
OneForAll is a powerful subdomain collection tool
|
||
|
||
Example:
|
||
python3 oneforall.py version
|
||
python3 oneforall.py --target example.com run
|
||
python3 oneforall.py --target ./domains.txt run
|
||
python3 oneforall.py --target example.com --alive False run
|
||
python3 oneforall.py --target example.com --brute True run
|
||
python3 oneforall.py --target example.com --port medium run
|
||
python3 oneforall.py --target example.com --format csv run
|
||
python3 oneforall.py --target example.com --dns False run
|
||
python3 oneforall.py --target example.com --req False run
|
||
python3 oneforall.py --target example.com --takeover False run
|
||
python3 oneforall.py --target example.com --show True run
|
||
|
||
Note:
|
||
--alive True/False Only export alive subdomains or not (default False)
|
||
--port default/small/large See details in ./config/setting.py(default port 80)
|
||
--format rst/csv/tsv/json/yaml/html/jira/xls/xlsx/dbf/latex/ods (result format)
|
||
--path Result directory (default directory is ./results)
|
||
|
||
:param str target: One domain or File path of one domain per line (required)
|
||
:param bool brute: Use brute module (default False)
|
||
:param bool dns: Use DNS resolution (default True)
|
||
:param bool req: HTTP request subdomains (default True)
|
||
:param str port: The port range request to the subdomains (default port 80)
|
||
:param bool alive: Only export alive subdomains (default False)
|
||
:param str format: Result format (default csv)
|
||
:param str path: Result directory (default None)
|
||
:param bool takeover: Scan subdomain takeover (default False)
|
||
"""
|
||
|
||
def __init__(self, target, brute=None, dns=None, req=None, port=None,
|
||
alive=None, format=None, path=None, takeover=None):
|
||
self.target = target
|
||
self.brute = brute
|
||
self.dns = dns
|
||
self.req = req
|
||
self.port = port
|
||
self.alive = alive
|
||
self.format = format
|
||
self.path = path
|
||
self.takeover = takeover
|
||
self.domain = str() # The domain currently being collected
|
||
self.domains = set() # All domains that are to be collected
|
||
self.data = list() # The subdomain results of the current domain
|
||
self.datas = list() # All subdomain results of the domain
|
||
self.old_table = str() # The table name of the last result
|
||
self.new_table = str() # The table name of the current result
|
||
self.origin_table = str() # The table name of the origin result
|
||
self.resolve_table = str() # The table name of the resolute result
|
||
|
||
def config(self):
|
||
"""
|
||
Configuration parameter
|
||
"""
|
||
if self.brute is None:
|
||
self.brute = bool(setting.enable_brute_module)
|
||
if self.dns is None:
|
||
self.dns = bool(setting.enable_dns_resolve)
|
||
if self.req is None:
|
||
self.req = bool(setting.enable_http_request)
|
||
if self.takeover is None:
|
||
self.takeover = bool(setting.enable_takeover_check)
|
||
if self.port is None:
|
||
self.port = setting.http_request_port
|
||
if self.alive is None:
|
||
self.alive = bool(setting.result_export_alive)
|
||
if self.format is None:
|
||
self.format = setting.result_save_format
|
||
if self.path is None:
|
||
self.path = setting.result_save_path
|
||
|
||
def export(self, table):
|
||
"""
|
||
Export data from the database and do some follow-up processing
|
||
|
||
:param table: table name
|
||
:return: export data
|
||
:rtype: list
|
||
"""
|
||
db = Database()
|
||
data = dbexport.export(table, alive=self.alive, format=self.format)
|
||
db.drop_table(self.new_table)
|
||
db.rename_table(self.domain, self.new_table)
|
||
db.close()
|
||
return data
|
||
|
||
def deal_db(self):
|
||
"""
|
||
Process the data when the collection task is completed
|
||
"""
|
||
db = Database()
|
||
db.deal_table(self.domain, self.origin_table)
|
||
db.close()
|
||
|
||
def mark(self):
|
||
"""
|
||
Mark the new discovered subdomain
|
||
|
||
:return: marked data
|
||
:rtype: list
|
||
"""
|
||
db = Database()
|
||
old_data = list()
|
||
now_data = db.get_data(self.domain).as_dict()
|
||
# Database pre-processing when it is not the first time to collect this subdomain
|
||
if db.exist_table(self.new_table):
|
||
db.drop_table(self.old_table) # If there is the last collection result table, delete it first
|
||
db.rename_table(self.new_table, self.old_table) # Rename the new table to the old table
|
||
old_data = db.get_data(self.old_table).as_dict()
|
||
db.close()
|
||
marked_data = utils.mark_subdomain(old_data, now_data)
|
||
return marked_data
|
||
|
||
def main(self):
|
||
"""
|
||
OneForAll main process
|
||
|
||
:return: subdomain results
|
||
:rtype: list
|
||
"""
|
||
self.old_table = self.domain + '_old_result'
|
||
self.new_table = self.domain + '_now_result'
|
||
self.origin_table = self.domain + '_origin_result'
|
||
self.resolve_table = self.domain + '_resolve_result'
|
||
|
||
collect = Collect(self.domain, export=False)
|
||
collect.run()
|
||
if self.brute:
|
||
# Due to there will be a large number of dns resolution requests, may cause other network tasks to be error
|
||
brute = Brute(self.domain, word=True, export=False)
|
||
brute.check_env = False
|
||
brute.run()
|
||
|
||
# Database processing
|
||
self.deal_db()
|
||
# Mark the new discovered subdomain
|
||
self.data = self.mark()
|
||
|
||
# Export results without resolve
|
||
if not self.dns:
|
||
return self.export(self.domain)
|
||
|
||
# Resolve subdomains
|
||
self.data = resolve.run_resolve(self.domain, self.data)
|
||
# Save resolve results
|
||
resolve.save_data(self.resolve_table, self.data)
|
||
|
||
# Export results without HTTP request
|
||
if not self.req:
|
||
return self.export(self.resolve_table)
|
||
|
||
# HTTP request
|
||
self.data = request.run_request(self.domain, self.data, self.port)
|
||
# Save HTTP request result
|
||
request.save_data(self.domain, self.data)
|
||
|
||
# Add the final result list to the total data list
|
||
self.datas.extend(self.data)
|
||
|
||
# Export
|
||
self.export(self.domain)
|
||
|
||
# Scan subdomain takeover
|
||
if self.takeover:
|
||
subdomains = utils.get_subdomains(self.data)
|
||
takeover = Takeover(subdomains)
|
||
takeover.run()
|
||
return self.data
|
||
|
||
def run(self):
|
||
"""
|
||
OneForAll running entrance
|
||
|
||
:return: All subdomain results
|
||
:rtype: list
|
||
"""
|
||
print(banner)
|
||
dt = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||
print(f'[*] Starting OneForAll @ {dt}\n')
|
||
utils.check_env()
|
||
logger.log('DEBUG', 'Python ' + utils.python_version())
|
||
logger.log('DEBUG', 'OneForAll ' + version)
|
||
logger.log('INFOR', f'Start Running OneForAll')
|
||
self.config()
|
||
self.domains = utils.get_domains(self.target)
|
||
if self.domains:
|
||
for self.domain in self.domains:
|
||
self.main()
|
||
utils.export_all(self.format, self.path, self.datas)
|
||
else:
|
||
logger.log('FATAL', f'Failed to obtain domain')
|
||
logger.log('INFOR', f'Finished OneForAll')
|
||
|
||
@staticmethod
|
||
def version():
|
||
print(banner)
|
||
exit(0)
|
||
|
||
|
||
if __name__ == '__main__':
|
||
fire.Fire(OneForAll)
|
||
# OneForAll('example.com').run()
|
||
# OneForAll('./domains.txt').run()
|