├── .gitignore ├── Config.py ├── Mmp_Script.py ├── Mmpscan.py ├── readme.md └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | target.txt 6 | .idea 7 | # C extensions 8 | *.so 9 | /venv 10 | /save 11 | /Result 12 | /old_mmpscan 13 | /mmpscan_venv 14 | /Tmp 15 | debug.log 16 | # Distribution / packaging 17 | .Python 18 | migrations/ 19 | build/ 20 | develop-eggs/ 21 | dist/ 22 | downloads/ 23 | eggs/ 24 | .eggs/ 25 | lib/ 26 | lib64/ 27 | parts/ 28 | sdist/ 29 | var/ 30 | wheels/ 31 | pip-wheel-metadata/ 32 | share/python-wheels/ 33 | *.egg-info/ 34 | .installed.cfg 35 | *.egg 36 | MANIFEST 37 | 38 | # PyInstaller 39 | # Usually these files are written by a python script from a template 40 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 41 | *.manifest 42 | *.spec 43 | 44 | # Installer logs 45 | pip-log.txt 46 | pip-delete-this-directory.txt 47 | 48 | # Unit test / coverage reports 49 | htmlcov/ 50 | .tox/ 51 | .nox/ 52 | .coverage 53 | .coverage.* 54 | .cache 55 | nosetests.xml 56 | coverage.xml 57 | *.cover 58 | *.py,cover 59 | .hypothesis/ 60 | .pytest_cache/ 61 | 62 | # Translations 63 | *.mo 64 | *.pot 65 | 66 | # Django stuff: 67 | *.log 68 | local_settings.py 69 | db.sqlite3 70 | db.sqlite3-journal 71 | 72 | # Flask stuff: 73 | instance/ 74 | .webassets-cache 75 | 76 | # Scrapy stuff: 77 | .scrapy 78 | 79 | # Sphinx documentation 80 | docs/_build/ 81 | 82 | # PyBuilder 83 | target/ 84 | 85 | # Jupyter Notebook 86 | .ipynb_checkpoints 87 | 88 | # IPython 89 | profile_default/ 90 | ipython_config.py 91 | 92 | # pyenv 93 | .python-version 94 | 95 | # pipenv 96 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 97 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 98 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 99 | # install all needed dependencies. 100 | #Pipfile.lock 101 | 102 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 103 | __pypackages__/ 104 | 105 | # Celery stuff 106 | celerybeat-schedule 107 | celerybeat.pid 108 | 109 | # SageMath parsed files 110 | *.sage.py 111 | 112 | # Environments 113 | .env 114 | .venv 115 | env/ 116 | venv/ 117 | ENV/ 118 | env.bak/ 119 | venv.bak/ 120 | 121 | # Spyder project settings 122 | .spyderproject 123 | .spyproject 124 | 125 | # Rope project settings 126 | .ropeproject 127 | 128 | # mkdocs documentation 129 | /site 130 | 131 | # mypy 132 | .mypy_cache/ 133 | .dmypy.json 134 | dmypy.json 135 | 136 | # Pyre type checker 137 | .pyre/ 138 | -------------------------------------------------------------------------------- /Config.py: -------------------------------------------------------------------------------- 1 | # *coding:UTF-8 * 2 | import os 3 | 4 | from fake_useragent import UserAgent 5 | 6 | '''!!!以下配置因人而异。需要自己更改!!!''' 7 | 8 | """ 9 | python运行环境配置: 10 | python_default 物理机运行环境 11 | 如你平时使用的: python Oneforall 则填python, python3 Oneforall 则填python3, 12 | python_venv_enable 启用venv运行环境 13 | 如果不想用本机python环境启用。则设置为True 14 | python_venv_autoinstall_enable 自动帮安装venv环境 15 | 如果本机python没有安装venv_name包,则会自动帮安装 16 | python_venv_pipinstall_enable 自动帮每个venv环境安装pip依赖 17 | 原理:> (venv) pip install -r requirements.txt 18 | """ 19 | # 如果要使用本机python环境,则请将python_venv_enable改为 False。不然我编写的调用脚本会执行 python_venv_xxx 20 | python_venv_enable = False 21 | # 如果是本机python环境。 请更改成本机调用python的语句。或者本脚本venv的python路径 常用语句 py -3 | python3 | python 22 | python_default = 'python' 23 | # 自动帮每个调用脚本安装venv环境,True为开启,False为关闭 24 | python_venv_autoinstall_enable = False 25 | # 自动帮在每个调用脚本在venv环境下安装pip依赖,True为开启,False为关闭 26 | python_venv_pipinstall_enable = False 27 | # 默认的venv模块名称 28 | venv_name = 'Mmpscan_venv' 29 | # 为每个脚本设置一个Mmpscan内部名称,可以影响到结果保存文件名 !!!开发修改!!! 30 | Mmpscan_scan_script_name = { 31 | 'oneforall':'oneforall', 32 | 'subfinder':'subfinder', 33 | 'subDomainsBrute':'subDomainsBrute', 34 | } 35 | Mmpscan_crack_script_name = { 36 | 'xray':'xray', 37 | 'dirsearch':'dirsearch', 38 | 39 | } 40 | 41 | 42 | 43 | """ 44 | 脚本路径配置: 45 | oneforall 路径(文件夹) 46 | dirsearch 路径(文件夹) 47 | xray 路径(exe文件) 48 | 49 | 脚本路径, 顺序不要轻易修改 50 | """ 51 | #被调用脚本路径!!!开发修改!!! 52 | abs_default_folder = fr'D:\长期桌面文件\Mmp' #你的工具所在的统一文件夹 53 | abs_oneforall_path = fr"{abs_default_folder}\OneForAll" 54 | abs_dirsearch_path = fr"{abs_default_folder}\dirsearch" 55 | abs_xray_path = fr"{abs_default_folder}\Xray_Rad_Fusion\xray.exe" 56 | abs_subfinger_path = fr"{abs_default_folder}\subfinder.exe" 57 | abs_subDomainsBrute_path = fr"{abs_default_folder}\subDomainsBrute" 58 | #venv虚拟环境路径!!!需要则修改!!! 59 | python_venv_oneforall = fr'{abs_oneforall_path}\{venv_name}' 60 | python_venv_dirsearch = fr'{abs_dirsearch_path}\{venv_name}' 61 | 62 | abs_path = os.path.dirname(os.path.abspath(__file__))# 绝对路径 63 | result_path = abs_path + '\\Result' # 保存全部结果的路径 64 | result_scan_path = result_path + '\\scan-info' # 保存scan结果的路径 65 | result_crack_path = result_path + '\\crack-info' # 保存crack结果的路径 66 | 67 | # 要创建的目录集合 68 | mkdir_path = [result_path, result_scan_path, result_crack_path] 69 | 70 | """ 71 | venv命令配置: 72 | 生成venv环境 73 | 自动调用pip install 74 | """ 75 | venv_path = [python_venv_oneforall,python_venv_dirsearch] 76 | cmd_pip_venv = [path + r'\Scripts\pip.exe install -r requirements.txt' for path in venv_path] 77 | cmd_python_path_sufiix = r'\Scripts\python.exe' #python文件后缀 78 | 79 | 80 | 81 | 82 | 83 | 84 | '''以下配置可按照自己喜好运行。不用修改也能运行''' 85 | 86 | 87 | 88 | 89 | """ 90 | 线程: #还没开发到 91 | 扫描 92 | 爆破 93 | """ 94 | # 同时进行的Scan扫描线程数 95 | scan_thread_count = 3 96 | # 同时进行的Crack攻击线程数 97 | crack_thread_count = 3 98 | 99 | 100 | 101 | """ 102 | 保存文件路径: 103 | 运行结果 104 | """ 105 | 106 | 107 | 108 | """ 109 | 黑名单: 110 | 在黑名单列表里的url或关键字,将会不实施扫描和攻击 111 | """ 112 | black_list = ["spider", "org", "gov"] 113 | 114 | 115 | """ 116 | 随机请求头生成: 117 | 发包时采用随机请求头 118 | """ 119 | useragent = UserAgent() 120 | def get_headers(): 121 | headers = {'User-Agent': useragent.random} 122 | return headers 123 | 124 | 125 | """ 126 | 配置代理: #功能未完成 127 | 根据需要自己添加,是个列表,元素为字典 128 | proxies_ip = { 129 | 'https' : '127.0.0.1', 130 | 'http' : '127.0.0.1' 131 | } 132 | """ 133 | proxies_ip = [] 134 | # 默认为空,即不设置代理 135 | 136 | 137 | """ 138 | 其他配置: 139 | ip资产 - 集合 - 用于存放资产收集得到的ip,自动去重 140 | 域名资产 - 集合 - 用于存放资产收集扫描得到的域名,自动去重 141 | logger_show_time - 单位秒(int) - 在屏幕显示信息,防止过快看不到(其实是鸡肋配置) 142 | domain_ip_split_sign - 字符串 - 保存成tmp文件时,分割domain和ip用的 143 | force_run_althought_exist - bool - 扫描过的情况下,再次运行脚本是否完全重新扫描 144 | """ 145 | # scan得到的ip 146 | ip_set = set() 147 | # scan得到的domain 148 | domain_set = set() 149 | # scan得到的C段ip 150 | cip_set = set() 151 | # 部分关键信息停留在窗口的秒数。方便看清,如果程序能够稳定运行,则建议为0。默认为1 152 | logger_INFO_show_time = 0 153 | logger_WARNNING_show_time = 0 154 | # 已经扫描过的domain,程序一开始就会保存当前目标到这里 155 | already_scan_txt = 'already.txt' 156 | # 若程序意外退出,从上一次already.txt最后一个domain开始扫描。(这是扫描到一半还没扫完意外退出的补救措施)。True为开启,则意外退出再次扫描从alredy最后一个取一目标 157 | already_last_enable = False 158 | force_run_althought_exist = False #若对应的调用脚本之前执行过此次目标,是否强制重新执行覆盖,True为强制执行 159 | -------------------------------------------------------------------------------- /Mmp_Script.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import csv 3 | import os 4 | import subprocess 5 | from time import sleep,strftime,localtime,time,strptime,mktime 6 | from loguru import logger 7 | import Config 8 | 9 | if not Config.python_venv_enable: 10 | python = Config.python_default 11 | 12 | def http_delete(target): 13 | if r'http://' in target: 14 | target = ''.join(target.split(r'http://')[1]) 15 | if r'https://' in target: 16 | target = ''.join(target.split(r'https://')[1]) 17 | return target 18 | 19 | def get_last_result(Script_name,target): 20 | file_name = [] 21 | Script_name = Script_name 22 | target = target 23 | for i, j, k in os.walk(Config.result_scan_path): 24 | for name in k: 25 | if Script_name in name and target in name: 26 | file_name.append(name) 27 | last_date = 0 28 | last_date_file = '' 29 | for name in file_name: 30 | #转换为时间戳再做比较 31 | date = mktime(strptime(''.join(name.split('.')[-2].split('@')[-1]), '%Y-%m-%d-%H点%M分%S秒')) 32 | if date > last_date: 33 | last_date = date 34 | last_date_file = name 35 | return last_date_file 36 | 37 | #切换工作目录到目标脚本,帮执行命令,最后切换回来 38 | def chdir_script_path(path,command): 39 | # 保存当前脚本运行路径 40 | current_cwd = os.getcwd() 41 | if os.path.exists(path): 42 | os.chdir(path) 43 | try: 44 | # 创建venv环境 45 | logger.info(f"当前命令 : {command}") 46 | os.system(command) 47 | except Exception as e: 48 | logger.error(f"chdir_script_path 代执行命令失败,错误{e}") 49 | os.chdir(current_cwd) 50 | class OneForAll(): 51 | def __init__(self, target=''): 52 | # 格式: 2022-05-27-10点13分03秒 53 | now = strftime("%Y-%m-%d-%H点%M分%S秒", localtime(time())) 54 | script_name = Config.Mmpscan_scan_script_name['oneforall'] 55 | self.target = target 56 | self.file_name = fr"{target}@{script_name}@{now}.csv" 57 | # 保存扫描结果的路径 58 | self.result_path = fr"{Config.result_scan_path}\{self.file_name}" 59 | # 上一个结果的路径 60 | self.last_result_path = fr'{Config.result_scan_path}\{get_last_result(script_name, target)}' if not Config.force_run_althought_exist else '' 61 | self.python = Config.python_venv_oneforall + Config.cmd_python_path_sufiix if Config.python_venv_enable else python 62 | 63 | def start(self): 64 | #强制调用一次。如果有该文件则不需要再次运行了 65 | if not Config.force_run_althought_exist: 66 | if self.get_result(): 67 | return Config.domain_set, Config.ip_set, Config.cip_set 68 | else: 69 | logger.info(f"OneForall 将重新扫描 {self.target}") 70 | command = f"{self.python} {Config.abs_oneforall_path}\oneforall.py --target {self.target} --path {self.result_path} run" 71 | logger.info(f"OneForall 开始运行!!!\n target为:{self.target}") 72 | try: 73 | res = subprocess.Popen(command, stdout=None, stderr=None) 74 | output, error = res.communicate() 75 | logger.info("OneForall顺利结束了 ,目前保存文件中......") 76 | except KeyboardInterrupt(os.devnull, 'w'): 77 | logger.info("检测到Ctrl+c 主动退出本次扫描") 78 | pass 79 | except: 80 | logger.error("[-]OneForall 故障!!!") 81 | pass 82 | 83 | self.get_result() 84 | return Config.domain_set, Config.ip_set,Config.cip_set 85 | 86 | def get_result(self): # 结果筛选另存为 87 | result_path = self.last_result_path if self.last_result_path else self.result_path 88 | try: 89 | self.csvFile = open(result_path, "r") 90 | self.reader = csv.reader(self.csvFile) 91 | for item in self.reader: 92 | if self.reader.line_num == 1: # 忽略第一行 93 | continue 94 | #后面用来可视化 95 | for ip in item[5].split(','): 96 | Config.domain_set.add(ip.strip()) # 加载ip到集合 97 | for ip in item[8].split(','): 98 | Config.ip_set.add(ip.strip()) # 加载ip到集合 99 | for ip in item[16].split(','): 100 | Config.cip_set.add(ip.strip()) # 加载ip到集合 101 | return True 102 | except FileNotFoundError: 103 | if result_path: 104 | logger.error(f"Oneforall 找不到文件 {result_path}") 105 | else: 106 | pass 107 | except Exception as e: 108 | logger.error(f"oneforall结果另存为失败 {e}") 109 | sleep(3) 110 | 111 | return False 112 | 113 | class SubFinder(): 114 | def __init__(self,target=''): 115 | #格式: 2022-05-27-10点13分03秒 116 | now = strftime("%Y-%m-%d-%H点%M分%S秒", localtime(time())) 117 | script_name = Config.Mmpscan_scan_script_name['subfinder'] 118 | self.target = target 119 | self.file_name = fr"{target}@{script_name}@{now}.txt" 120 | #保存扫描结果的路径 121 | self.result_path = fr"{Config.result_scan_path}\{self.file_name}" 122 | #上一个结果的路径 123 | self.last_result_path = fr'{Config.result_scan_path}\{get_last_result(script_name,target)}' if not Config.force_run_althought_exist else '' 124 | def start(self): 125 | if not Config.force_run_althought_exist: 126 | if self.get_result(): 127 | return Config.domain_set,Config.ip_set 128 | logger.info(f"subfinderScan 开始 !当前的subdomain个数为{len(Config.domain_set)}") 129 | scanCommand = f"{Config.abs_subfinger_path} -d {self.target} -o {self.result_path}" 130 | os.system(scanCommand) 131 | self.get_result() 132 | return Config.domain_set, Config.ip_set 133 | def get_result(self): 134 | #是否开启了 135 | result_path = self.last_result_path if self.last_result_path else self.result_path 136 | try: 137 | f = open(result_path, 'r') 138 | lines = f.readlines() 139 | for line in lines: 140 | Config.domain_set.add(http_delete(line.rstrip('\n'))) 141 | f.close() 142 | logger.info(f"subfinderScan 结束 !当前的subdomain个数为{len(Config.domain_set)}") 143 | return True 144 | except FileNotFoundError: 145 | if result_path: 146 | logger.error(f"subfinder 找不到文件 {result_path}") 147 | else: 148 | pass 149 | except Exception as e: 150 | logger.error(f"subfinder 错误 {e}") 151 | 152 | return False 153 | 154 | class SubDomainsBrute(): 155 | def __init__(self,target): 156 | # 格式: 2022-05-27-10点13分03秒 157 | now = strftime("%Y-%m-%d-%H点%M分%S秒", localtime(time())) 158 | script_name = Config.Mmpscan_scan_script_name['subDomainsBrute'] 159 | self.target = target 160 | self.file_name = fr"{target}@{script_name}@{now}.txt" 161 | # 保存扫描结果的路径 162 | self.result_path = fr"{Config.result_scan_path}\{self.file_name}" 163 | # 上一个结果的路径 164 | self.last_result_path = fr'{Config.result_scan_path}\{get_last_result(script_name, target)}' if not Config.force_run_althought_exist else '' 165 | def start(self): 166 | if not Config.force_run_althought_exist: 167 | if self.get_result(): 168 | return Config.domain_set, Config.ip_set 169 | else: 170 | logger.info(f"subDomainsBrute 将重新扫描 {self.target}") 171 | logger.info(f"subDomainsBrute 开始 !当前的subdomain个数为{len(Config.domain_set)}") 172 | command = fr"{python} {Config.abs_subDomainsBrute_path}\subDomainsBrute.py -t 10 --output {self.result_path} {self.target}" 173 | chdir_script_path(Config.abs_subDomainsBrute_path,command) 174 | 175 | return Config.domain_set, Config.ip_set 176 | def get_result(self): 177 | # 是否开启了 178 | result_path = self.last_result_path if self.last_result_path else self.result_path 179 | try: 180 | f = open(result_path, 'r') 181 | lines = f.readlines() 182 | for line in lines: 183 | Config.domain_set.add(http_delete(line.split()[0].strip('\n'))) 184 | for i in (line.split(',')): 185 | if len(i) > 16: 186 | Config.ip_set.add(i.split()[-1].strip('\n')) 187 | else: 188 | Config.ip_set.add(i.strip('\n')) 189 | f.close() 190 | logger.info(f"subDomainsBruteScan 结束 !当前的subdomain个数为{len(Config.domain_set)}") 191 | return True 192 | except FileNotFoundError: 193 | if result_path: 194 | logger.error(f"subDomainsBruteScan 找不到文件 {result_path}") 195 | else: 196 | pass 197 | except Exception as e: 198 | logger.error(f"subDomainsBruteScan 错误 {e}") 199 | 200 | return False 201 | if __name__ == '__main__': 202 | OneForAll(target='www.cqut.edu.cn').start() 203 | SubFinder('baidu.com').start() -------------------------------------------------------------------------------- /Mmpscan.py: -------------------------------------------------------------------------------- 1 | # -*- conding:utf-8 -*- 2 | import os 3 | from optparse import OptionParser 4 | from loguru import logger 5 | from time import sleep 6 | import subprocess 7 | from concurrent.futures import ThreadPoolExecutor 8 | from multiprocessing import Process,Queue 9 | import threading 10 | 11 | import Config 12 | import Mmp_Script 13 | 14 | 15 | banner =""" 16 | @ Author : Throokie 17 | @ Version : 0.5 18 | @ Example : 19 | python Mmpscan.py --target target.com 20 | python Mmpscan.py --file target.txt 21 | python Mmpscan.py --venv True 22 | @ 说明: 23 | target 要攻击的目标 24 | file 保存要攻击的目标的文件 25 | venv [True|Force] 是否创建虚拟目录 26 | @ TODO 27 | ①添加更多工具 28 | ②自动更换ip代理扫描 29 | ③web端(可能要很久) 30 | """ 31 | 32 | sleep(0.5) 33 | 34 | def init(): 35 | path = '' 36 | try: 37 | for path in Config.mkdir_path: 38 | # 路径初始化 39 | if not os.path.exists(path): 40 | try: 41 | os.makedirs(path) 42 | except Exception as e: 43 | logger.info("目录初始化失败: ", e) 44 | 45 | 46 | except Exception as e: 47 | logger.warning(f"目录尚未初始化完成,错误path:{path}") 48 | sleep(10) 49 | 50 | 51 | ''' 52 | 名称:Before_Start 53 | 功能:启动脚本,配置任务,获取要扫描的目标 54 | ''' 55 | class Before_Start(object): 56 | def __init__(self, options, args): 57 | self.targets_list = list() #保存domain目标——有序版 58 | self.targets_set = set() #保存domain目标——乱序版 59 | self.options = options 60 | self.args = args 61 | self.youxu_key = 'True' 62 | def start(self): 63 | self.venv_start() 64 | _list = self.get_domain() 65 | return _list 66 | #虚拟环境的使用。包括自动创建,执行pip install 67 | def venv_start(self): 68 | if (self.options.venv == 'True' and Config.python_venv_autoinstall_enable) or (self.options.venv == 'Force' and Config.python_venv_autoinstall_enable): 69 | logger.info('venv自动安装已开启') 70 | if (self.options.venv == 'Force'): 71 | logger.info('强制重新生成venv路径') 72 | logger.info(f'正在为每个venv路径进行venv初始化, 默认venv名称为:{Config.venv_name}') 73 | sleep(Config.logger_INFO_show_time) 74 | mmp_cwd = os.getcwd() 75 | # 保存当前脚本运行路径 76 | 77 | for path in Config.venv_path: 78 | #创建venv环境 79 | #TODO 兼容linux 80 | if not os.path.exists(path) or self.options.venv == 'Force': 81 | os.chdir(path + '\\..\\') 82 | cmd = fr'virtualenv {Config.venv_name}' 83 | try: 84 | #创建venv环境 85 | logger.info(f"当前命令 : {cmd}") 86 | os.system(cmd) 87 | logger.info(f"创建{path+Config.venv_name} 成功") 88 | except Exception as e: 89 | logger.error(f"执行创建命令错误: {e}") 90 | 91 | 92 | for pip_cmd in Config.cmd_pip_venv: 93 | # 为venv环境执行pip install 94 | logger.info(pip_cmd) 95 | try: 96 | res = subprocess.Popen(pip_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 97 | output, error = res.communicate() 98 | if error: 99 | logger.error(error) 100 | if output: 101 | logger.info(output) 102 | logger.info(f"pip auto install 执行成功") 103 | except Exception as e: 104 | logger.error(f"执行pip auto install失败: {e}") 105 | 106 | 107 | os.chdir(mmp_cwd) 108 | # 恢复原来脚本执行路径 109 | sleep(Config.logger_WARNNING_show_time) 110 | def get_domain(self): 111 | # 传入域名时的操作,保存域名到列表 targets_set 112 | if self.options.domain: 113 | for black in Config.black_list: 114 | if black in self.options.domain: 115 | logger.warning(f"{self.options.domain}位于黑名单") 116 | exit(0) 117 | self.targets_list.append(self.options.domain) 118 | logger.info(f"{self.options.domain}加载成功") 119 | # 传入文件时的操作,提取文件中的目标 120 | elif self.options.filename: 121 | try: 122 | fo = open(f"{self.options.filename}", "r") 123 | lines = fo.readlines() 124 | black_number = 0 125 | black_sign = False 126 | #判断是否命中黑名单 127 | for target in lines: 128 | for black in Config.black_list: 129 | if black in target: 130 | black_number += 1 131 | black_sign = True 132 | if black_sign: 133 | black_sign = False 134 | else: 135 | #自动去除http头 136 | if r'http://' in target: 137 | target = ''.join(target.split(r'http://')[1]) 138 | if r'https://' in target: 139 | target = ''.join(target.split(r'https://')[1]) 140 | self.targets_list.append(target.strip()) 141 | self.targets_set = list(self.targets_list) 142 | repeat_target = (len(self.targets_set) - len(self.targets_list)) 143 | if repeat_target: 144 | logger.info(f"目标target中有{repeat_target}个重复目标,有序模式为:{self.youxu_key}") 145 | if self.youxu_key == 'True': 146 | self.sort_targets_list = list(self.targets_set) 147 | self.sort_targets_list.sort(key=self.targets_list.index) 148 | 149 | logger.info(f"{self.options.filename} 加载成功,共有{len(self.targets_list)}行不重复个目标,{black_number}个黑名单") 150 | 151 | except FileNotFoundError: 152 | logger.error("文件没有找到") 153 | exit(0) 154 | except Exception as e: 155 | logger.error(f"其他错误 : {e}") 156 | exit(0) 157 | 158 | else: 159 | logger.error("请传入目标参数!!!") 160 | 161 | return list(self.targets_list) 162 | 163 | 164 | def Scan(target_list, target_queue, data_queue): 165 | data_dict = dict() 166 | for target in target_list: 167 | data_dict[target] = { 168 | 'subdomain':set(), 169 | 'ip':set(), 170 | 'cip':set(), 171 | } 172 | try: 173 | #调用oneforall执行脚本 174 | sub_domain, ip, cip = Mmp_Script.OneForAll(target).start() 175 | data_dict[target]['subdomain'].update(sub_domain) 176 | data_dict[target]['ip'].update(ip) 177 | data_dict[target]['cip'].update(cip) 178 | #调用subfinder执行脚本 179 | sub_domain, ip = Mmp_Script.SubFinder(target).start() 180 | data_dict[target]['subdomain'].update(sub_domain) 181 | data_dict[target]['ip'].update(ip) 182 | #调用subDomainsBrute执行脚本 183 | sub_domain, ip = Mmp_Script.SubDomainsBrute(target).start() 184 | data_dict[target]['subdomain'].update(sub_domain) 185 | data_dict[target]['ip'].update(ip) 186 | 187 | target_queue.put(target) 188 | data_queue.put(data_dict) 189 | except Exception as e: 190 | target_queue.put(target) 191 | data_queue.put(data_dict) 192 | 193 | logger.info(f'Scan模块出现错误:{e}') 194 | 195 | #Scan发送扫描完毕信号,等到Crack取到该信号则退出 196 | target_queue.put('In the End') 197 | data_queue.put('error') 198 | 199 | 200 | def Crack(target_queue,data_queue): 201 | while True: 202 | try: 203 | target = target_queue.get() 204 | if target == 'In the End': 205 | return 206 | data_dict = data_queue.get() 207 | print(len(data_dict[target]['subdomain'])) 208 | print(len(data_dict[target]['ip'])) 209 | print(list(data_dict[target]['ip'])) 210 | print(list(data_dict[target]['cip'])) 211 | # Mmp_Script.OneForAll(target)' 212 | except Exception as e: 213 | logger.info(f'Crack模块出现错误:{e}') 214 | 215 | 216 | def main(): 217 | print(banner) 218 | usage = "用法: %prog -f | -u " 219 | parser = OptionParser(usage=usage) # 若输入错误,则输出提示usage 220 | parser.add_option("-u", "--target", type="string", dest="domain", help="python MmpScan -u baidu.com") 221 | parser.add_option("-f", "--file", type="string", dest="filename", help="python MmpScan -f domains.txt") 222 | parser.add_option("--venv", type="string", dest="venv", help="python MmpScan --venv True") 223 | (options, args) = parser.parse_args() 224 | 225 | # 获取要扫描的目标 226 | targets_list = Before_Start(options, args).start() 227 | # 扫描目标,创建Scan、Crack模块的两个进程 228 | target_queue = Queue() 229 | data_queue = Queue() 230 | Scan_process = Process(target=Scan, args=(targets_list,target_queue,data_queue)) 231 | Crack_process = Process(target=Crack, args=(target_queue,data_queue)) 232 | Scan_process.start() 233 | Crack_process.start() 234 | Crack_process.join() 235 | Scan_process.join() 236 | logger.info(f"Congratulations !!! 扫描完成,本次扫描的目标有:{targets_list}") 237 | 238 | if __name__ == '__main__': 239 | init() 240 | main() 241 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 介绍' 2 | 3 | 如果你有很多电脑。如果你不想让他们浪费。如果你刚好看某个网站不顺眼,但眼下没空对他进行信息收集和攻击。 4 | 5 | 那么,该工具能够很好的帮助你。他能帮你对目标进行信息收集,并且自动攻击。再将结果梳理给你。 6 | 7 | 这款工具的亮点就是,能够利用其他工具的优点。调用他们,为这款工具所用。 8 | 9 | 我认为没有最好的工具,如果在同类工具之间互补。那才能发挥出整体最大威力。但缺点也显而易见,简单的调用势必会有很多重复的IO请求。是的,所以该脚本推荐挂机时用,挖点漏洞碰下运气什么的。 10 | 11 | TODO 12 | 1、添加更多调用工具 13 | 2、添加web端 14 | 15 | 16 | # 设计思路 17 | 主程序MmpScan.py下生成两个进程,分别是 18 | 1. Scan 19 | 2. Crack 20 | 21 | Scan负责信息收集(子域名、ip、C段)等信息 22 | Crack负责爆破和攻击(目录,rdp,xray)等工具 23 | 24 | 调用脚本:指的是集成进来的工具 25 | 26 | 目前Scan模块集成了Oneforall,subfinger,subdomainbrute调用脚本 27 | Crack模块暂未集成 28 | 29 | 如果需要添加自己的调用脚本,请将脚本以class格式写进Mmp_Scripy.py里,并且MmpScan主程序调用这个类。当然Config.py也需要进行相关配置 30 | 31 | # 以后具体功能 32 | 33 | 1. 加入dirsearch 34 | 2. 加入Xray 35 | 3. 加入C段扫描 36 | 4. 加入rdp、ssh等可登陆端口爆破 37 | 38 | # 使用方法 39 | 40 | 创建python venv虚拟环境(可选) 41 | 42 | ```python 43 | ''' 44 | virtualenv venv 创建虚拟环境,名字为venv 45 | .\venv\Scripts\activate.bat 进入虚拟环境(windows环境) 46 | .\Scripts\deactivate.bat 退出虚拟环境 47 | ''' 48 | ``` 49 | 50 | 1、 安装依赖 51 | 52 | ```python 53 | ''' 54 | pip install -r requirements.txt 55 | ''' 56 | ``` 57 | 58 | 2、 运行脚本 59 | 60 | - `python MmpScan.py --target www.target.com` 61 | 62 | 输入单个url 63 | 64 | - `python MmpScan.py --file targets.txt` 65 | 66 | 输入文件,读取多个主域名不同的url。 67 | 68 | - `python MmpScan.py --venv True` 69 | 70 | 为调用脚本自动生成venv环境并且安装相关依赖。(还未完全测试,不推荐使用) -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | -i https://mirrors.aliyun.com/pypi/simple/ 2 | beautifulsoup4==4.9.3 3 | bs4==0.0.1 4 | certifi==2020.6.20 5 | chardet==3.0.4 6 | colorama==0.4.4; sys_platform == 'win32' 7 | dnspython==2.0.0 8 | exrex==0.10.5 9 | fire==0.3.1 10 | future==0.18.2; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' 11 | idna==2.10; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' 12 | loguru==0.5.3 13 | pysocks==1.7.1 14 | requests==2.24.0 15 | six==1.15.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' 16 | soupsieve==2.0.1; python_version >= '3.0' 17 | sqlalchemy==1.3.20 18 | tenacity==6.2.0 19 | termcolor==1.1.0 20 | tqdm==4.51.0 21 | treelib==1.6.1 22 | urllib3==1.25.11; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4' 23 | win32-setctime==1.0.3; sys_platform == 'win32' 24 | fake_useragent 25 | --------------------------------------------------------------------------------