├── zoomeye_http_result.txt ├── Zfresult └── 每次使用前需要请移走或重命名该目录文件 ├── dork.txt ├── APIkey.txt ├── zfre_scan.config ├── module ├── ffuf.py ├── XRaEh.py └── ZoomEye.py ├── zfre_scan.py └── README.md /zoomeye_http_result.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Zfresult/每次使用前需要请移走或重命名该目录文件: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dork.txt: -------------------------------------------------------------------------------- 1 | x.x.x.0/24 2 | x.x.x.0/24 -------------------------------------------------------------------------------- /APIkey.txt: -------------------------------------------------------------------------------- 1 | xxxxxxxxxxxxxxx 2 | xxxxxxxxxxxxxxx -------------------------------------------------------------------------------- /zfre_scan.config: -------------------------------------------------------------------------------- 1 | Ehole_path = C:\Ehole2.0-win\Ehold_v2.exe 2 | ffuf_path = C:\ffuf_1.2.1_windows_amd64\ffuf.exe 3 | ffuf_dict_path = C:\Zfre_scan\module\dict.txt 4 | rad_path = C:\rad_windows_amd64.exe\rad_windows_amd64.exe 5 | xray_path = C:\xray_windows_amd64.exe\xray_windows_amd64.exe 6 | Zoomeye_file_path = dork.txt 7 | zoomeye_http_result = zoomeye_http_result.txt -------------------------------------------------------------------------------- /module/ffuf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | import os 3 | import re 4 | import optparse 5 | 6 | def test_ffuf(ffuf_path, zoomeye_txt, ffuf_dict_path): 7 | with open(zoomeye_txt, "r", encoding='utf-8') as f: 8 | for line in f.readlines(): 9 | line = line.strip('\n') #去掉列表中每一个元素的换行符 10 | url = line + "/FUZZ" 11 | cmd = "{} -w {} -u {} -ac -mc 200,302 -maxtime 120".format(ffuf_path, ffuf_dict_path, url) 12 | result = os.popen(cmd) 13 | result = result.buffer.read().decode(encoding='utf-8') #os.popen输出编码转换 14 | ffuf2txt(result, line, zoomeye_txt) 15 | 16 | def ffuf2txt(result, line, zoomeye_txt): 17 | result = result.strip("\n") #去掉换行符 18 | url_list = result.split("]") 19 | with open(zoomeye_txt, "a", encoding='utf-8') as f: 20 | for url in url_list: 21 | if re.search(".*\[Status:", url): #排除最后一行 22 | url = url.split()[0].strip() 23 | if "[Status" in url: #部分目录可能为空白 24 | continue 25 | else: 26 | url = "\n" + line + "/" + url 27 | print(url) 28 | f.write(url) 29 | 30 | def main(ffuf_path, ffuf_dict_path, zoomeye_http_result): 31 | test_ffuf(ffuf_path, zoomeye_http_result, ffuf_dict_path) 32 | 33 | if __name__ == '__main__': 34 | main() 35 | -------------------------------------------------------------------------------- /module/XRaEh.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os 3 | import time 4 | from multiprocessing import Process 5 | from openpyxl import Workbook 6 | import optparse 7 | import re 8 | 9 | def toexcel(result_list): 10 | wb = Workbook() 11 | ws = wb.active 12 | head = ["url", "指纹", "APP", "状态码", "size", "title"] 13 | ws.append(head) 14 | for list in result_list: 15 | ws.append(list) 16 | wb.save('Zfresult\\EHole_result.xlsx') 17 | 18 | def rad(zoomeye_http_result, rad_path): 19 | with open(zoomeye_http_result, "r",encoding='utf-8') as f: #读取关键字 20 | for line in f.readlines(): 21 | line = line.strip('\n') # 去掉列表中每一个元素的换行符 22 | os.system("{} -t {} -http-proxy 127.0.0.1:7770".format(rad_path, line)) 23 | print("----------------Rad爬虫结束----------------") 24 | 25 | def xray(xray_path): 26 | cmd = "{} webscan --listen 127.0.0.1:7770 --html-output Zfresult\\xray_result.html".format(xray_path) 27 | os.system(cmd) 28 | print(cmd) 29 | 30 | def Ehole(zoomeye_http_result, Ehole_path): 31 | Ehole_path = Ehole_path.split("\\", -1) 32 | print("\\".join(Ehole_path[:-1])) 33 | cmd = "cd {} & {} -l {}".format("\\".join(Ehole_path[:-1]), Ehole_path[-1], zoomeye_http_result) 34 | Ehold_result = os.popen(cmd) # 这个地方不能合并一行写,会出错说 read of closed file 35 | Ehold_result = Ehold_result.buffer.read().decode(encoding='utf8') 36 | new_list = [] 37 | Ehold_result_list = Ehold_result.split("[") 38 | for each_Ehold_result in Ehold_result_list: 39 | new_list.append(each_Ehold_result.split("|")) 40 | if "重点资产:" in each_Ehold_result: 41 | new_list.append(["重点资产:"]) 42 | toexcel(new_list) 43 | 44 | def main(Ehole_path, rad_path, xray_path, zoomeye_http_result): 45 | zoomeye_http_result = os.getcwd() + "\\" + zoomeye_http_result 46 | p3 = Process(target=Ehole, kwargs={'zoomeye_http_result': zoomeye_http_result, 'Ehole_path': Ehole_path}) 47 | p1 = Process(target=xray, kwargs={'xray_path': xray_path}) 48 | time.sleep(30) 49 | p2 = Process(target=rad, kwargs={'zoomeye_http_result': zoomeye_http_result, 'rad_path': rad_path}) 50 | p1.start() 51 | p3.start() 52 | p2.start() 53 | 54 | if __name__ == '__main__': 55 | main() -------------------------------------------------------------------------------- /zfre_scan.py: -------------------------------------------------------------------------------- 1 | import module.XRaEh 2 | import module.ZoomEye 3 | import os 4 | import module.ffuf 5 | import optparse 6 | import re 7 | 8 | def get_config(zfre_scan_config): 9 | with open(zfre_scan_config, "r", encoding='utf-8') as f: 10 | for line in f.readlines(): 11 | if re.search("Zoomeye_file_path = (.*)", line): 12 | Zoomeye_file_path = line.split("=")[1].strip() 13 | if re.search("ffuf_path = (.*)", line): 14 | ffuf_path = line.split("=")[1].strip() 15 | if re.search("ffuf_dict_path = (.*)", line): 16 | ffuf_dict_path = line.split("=")[1].strip() 17 | if re.search("Ehole_path = (.*)", line): 18 | Ehole_path = line.split("=")[1].strip() 19 | if re.search("rad_path = (.*)", line): 20 | rad_path = line.split("=")[1].strip() 21 | if re.search("xray_path = (.*)", line): 22 | xray_path = line.split("=")[1].strip() 23 | if re.search("zoomeye_http_result = (.*)", line): 24 | zoomeye_http_result = line.split("=")[1].strip() 25 | return Zoomeye_file_path, ffuf_path, ffuf_dict_path, Ehole_path, rad_path, xray_path, zoomeye_http_result 26 | 27 | def main(): 28 | usage = "python %prog -m/M zfre -c/C " # 用于显示帮助信息 29 | parser = optparse.OptionParser(usage) # 创建对象实例 30 | parser.add_option('-M', '-m', dest='module', type='string', help='python module(z,f,re)', default='zfre') ## -p/-P 都可以 31 | parser.add_option('-C', '-c', dest='config', type='string', help='zfre_scan.config path', default='zfre_scan.config') ## -p/-P 都可以 32 | (options, args) = parser.parse_args() 33 | Zoomeye_file_path, ffuf_path, ffuf_dict_path, Ehole_path, rad_path, xray_path , zoomeye_http_result= get_config(options.config) 34 | print(options.module) 35 | 36 | if re.search("z", options.module, re.IGNORECASE): 37 | print("----------Start ZoomEye.py-----------") 38 | module.ZoomEye.main(Zoomeye_file_path) 39 | if re.search("f", options.module, re.IGNORECASE): 40 | print("-----------Start ffuf.py-------------") 41 | module.ffuf.main(ffuf_path, ffuf_dict_path, zoomeye_http_result) 42 | if re.search("re", options.module, re.IGNORECASE): 43 | print("-----------Start XRaEh.py------------") 44 | module.XRaEh.main(Ehole_path, rad_path, xray_path, zoomeye_http_result) 45 | 46 | if __name__ == '__main__': 47 | main() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zfre_scan 2 | HVV信息收集,优秀开源工具的整合,通过Zoomeye+ffuf+EHole+Xray+Rad进行自动化信息收集与结果输出 3 | 4 | 分为三个模块: 5 | 1、Zoomeye.py:调用zoomeye接口获取数据 6 | 2、ffuf.py:调用ffuf对url列表进行目录扫描 7 | 3、XraEh.py:调用xray与rad对url列表进行爬虫与被动扫描 8 | 9 | 10 | - Input:Zoomeye搜索的关键字 11 | - Output:ffuf目录扫描结果、EHole指纹识别结果、Xray+Rad扫描结果 12 | 13 | **本项目所有内容仅作为安全研究和授权测试使用, 相关人员对因误用和滥用该项目造成的一切损害概不负责** 14 | 15 | ## 运行环境 16 | 语言:python3 17 | 18 | 操作系统:目前只试过windows上使用 19 | 20 | Python模块:openpyxl 21 | 22 | `pip install openpyxl` 23 | 24 | 25 | ## 配置: 26 | ### 1、下载各个模块使用到的开源工具: 27 | 28 | Zoomeye获取IP、端口、协议(无需下载,需要注册获取APIkey):[https://www.zoomeye.org/](https://www.zoomeye.org/) 29 | 30 | ffuf目录扫描(目录字典也需要准备):[https://github.com/ffuf/ffuf](https://github.com/ffuf/ffuf) 31 | 32 | EHole指纹识别、title识别:[https://github.com/EdgeSecurityTeam/EHole](https://github.com/EdgeSecurityTeam/EHole) 33 | 34 | Xray被动扫描:[https://github.com/chaitin/xray](https://github.com/chaitin/xray) 35 | 36 | Rad爬虫:[https://github.com/chaitin/rad](https://github.com/chaitin/rad) 37 | 38 | ### 2、zfre_scan.config配置文件写入信息: 39 | 40 | ``` 41 | Ehole_path = Ehole绝对路径 42 | ffuf_path = ffuf绝对路径 43 | ffuf_dict_path = ffuf目录字典绝对路径 44 | rad_path = rad绝对路径 45 | xray_path = xray绝对路径 46 | Zoomeye_file_path = zoomeye读取的关键字或者C段文件路径 47 | zoomeye_http_result = ffuf、rad、xray、Ehole读取的url文件路径(文件里需要带上http或者https协议) 48 | ``` 49 | 50 | ## 使用: 51 | ### 1、多模块调用: 52 | 53 | ``` 54 | 1、Zoomeye+ffuf+EHole+Xray+Rad: python zfre_scan.py -m zfre 55 | 2、Zoomeye+EHole+Xray+Rad: python zfre_scan.py -m zre 56 | 3、ffuf+EHole+Xray+Rad: python zfre_scan.py -m fre 57 | 4、Zoomeye+ffuf: python zfre_scan.py -m zf 58 | 59 | 输入:├── dork.txt #zoomeye读取的关键字或者C段文件路径,需要配置到zfre_scan.config里 60 | 输出: 61 | ├── Zfresult #结果输出目录 62 | │   ├── xray_result.html #xray扫描结果 63 | │   ├── EHole_result.xlsx #EHole指纹识别结果 64 | │   └── zoomeye_result.xlsx #zoomeye输出结果,主要看非http协议 65 | └── zoomeye_http_result.txt #zoomeye.py执行输出的http协议url(暂时无法修改输出路径与文件名);ffuf.py的输入;ffuf.py执行后会在这里新增扫描到的url 66 | ``` 67 | ### 2、单模块调用: 68 | ``` 69 | 1、Zoomeye: python zfre_scan.py -m z 70 | 输入:├── dork.txt #zoomeye读取的关键字或者C段文件路径,需要配置到zfre_scan.config里 71 | 输出: 72 | ├── Zfresult #结果输出目录 73 | │   └── zoomeye_result.xlsx #zoomeye输出结果,主要看非http协议 74 | └── zoomeye_http_result.txt #zoomeye.py执行输出的http协议url(暂时无法修改输出路径与文件名) 75 | 76 | 2、EHole+Xray+Rad: python zfre_scan.py -m re 77 | 输入:├── zoomeye_http_result.txt #url,每个url直接换行,需要带上http://或https:// 78 | 输出: 79 | ├── Zfresult #结果输出目录 80 | │   ├── xray_result.html #xray扫描结果 81 | │ └── EHole_result.xlsx #EHole指纹识别结果 82 | └──────────────────────── 83 | 84 | 3、ffuf: python zfre_scan.py -m f 85 | 输入:├── zoomeye_http_result.txt #url,每个url直接换行,需要带上http://或https:// 86 | 输出: 87 | └── zoomeye_http_result.txt #ffuf.py模块执行后会在后面新增扫描到的url 88 | ``` 89 | ## 注: 90 | - 每次使用前需要自行重命名或者移走Zfresult目录下的文件,否则会覆盖原有结果,或者Xray无法监听 91 | - Xray目前需要手动关掉监听进程 92 | 93 | 20210503更新: 94 | 95 | 1、dork.txt可直接输入搜索语法,例如:x.x.x.x +app:"Apache httpd" 96 | 97 | 2、添加zoomeye API超时重传机制 98 | 99 | 3、zoomeye.py如果中途报错也可以输出结果 100 | 101 | -------------------------------------------------------------------------------- /module/ZoomEye.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | from openpyxl import Workbook 3 | import time 4 | import requests 5 | import json 6 | import optparse 7 | import re 8 | import socket 9 | from urllib.parse import quote 10 | from requests.adapters import HTTPAdapter 11 | 12 | result_list = [] 13 | 14 | def search_zoomeye(dork, page, apikey): 15 | dork = quote(dork, 'utf-8') 16 | s = requests.Session() 17 | s.mount('http://', HTTPAdapter(max_retries=5)) 18 | s.mount('https://', HTTPAdapter(max_retries=5)) 19 | burp0_url = "https://api.zoomeye.org/host/search?query={}&page={}".format(dork, page) 20 | burp0_headers = {"API-KEY": apikey} 21 | print(burp0_url) 22 | result = s.get(burp0_url, headers=burp0_headers, timeout=10) 23 | if result.status_code == 200: 24 | total = json.loads(result.text)["total"] 25 | matches = json.loads(result.text)["matches"] 26 | if total != 0 and matches == []: #key余额已用完 27 | return None 28 | for each_match in matches: 29 | IP = each_match["ip"] 30 | portinfo = each_match["portinfo"] 31 | port = portinfo["port"] 32 | service = portinfo["service"] 33 | if "http" in service: 34 | service = "http" 35 | elif "https" in service: 36 | service = "https" 37 | try: 38 | title = str(portinfo["title"]) 39 | except: 40 | title = "" 41 | url = "{}://{}:{}".format(service, IP, port) 42 | test_telnet_result = test_socket(IP, port) #socket连接测试端口通不通 43 | if test_telnet_result == 1: 44 | result_list.append([url, service, title]) 45 | print("[+]", url, title.encode("utf-8", "ignore"), "Open") 46 | else: 47 | print("[-]", url, title.encode("utf-8", "ignore"), "Close") 48 | continue 49 | print(url, title.encode("utf-8", "ignore")) 50 | return total 51 | 52 | else: #非200响应码返回错误信息 53 | print(result.status_code, result.text) 54 | 55 | 56 | def toexcel(result_list): 57 | wb = Workbook() 58 | ws = wb.active 59 | head = ["url", "service", "title"] 60 | ws.append(head) 61 | for list in result_list: 62 | ws.append(list) 63 | wb.save('Zfresult\\zoomeye_result.xlsx') 64 | 65 | def totxt(result_list): 66 | with open("zoomeye_http_result.txt", "w", encoding='utf-8') as f: 67 | for line in result_list: 68 | if "http" in line[1]: 69 | f.write(line[0] + "\n") 70 | f.close() 71 | 72 | def test_socket(IP, port): 73 | sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 74 | sk.settimeout(5) 75 | try: 76 | sk.connect((IP, port)) 77 | return 1 78 | except Exception: 79 | return 0 80 | sk.close() 81 | 82 | def get_apikey(): 83 | apikey_list = [] 84 | with open("APIkey.txt", "r") as f: #读取关键字 85 | for line in f.readlines(): 86 | line = line.strip('\n') # 去掉列表中每一个元素的换行符 87 | burp0_url = "https://api.zoomeye.org/resources-info" 88 | burp0_headers = {"API-KEY": line} 89 | result = requests.get(burp0_url, headers=burp0_headers) 90 | search = json.loads(result.text)["resources"]["search"] 91 | if search != 0: 92 | apikey_list.append(line) 93 | else: 94 | continue 95 | return apikey_list 96 | 97 | def main(Zoomeye_file_path, add_pram): 98 | try: 99 | apikey_list = get_apikey() 100 | apikey_len = len(apikey_list) 101 | apikey_index = 0 102 | with open(Zoomeye_file_path, "r",encoding='utf-8') as f: #读取关键字 103 | for line in f.readlines(): 104 | line = line.strip('\n').strip() # 去掉列表中每一个元素的换行符 105 | if line == "": # 有空行会返回500导致报错 106 | continue 107 | else: 108 | line = line + " " + add_pram 109 | if apikey_list == []: 110 | print("APIKey一滴也没有了") 111 | break 112 | total = search_zoomeye(line, 1, apikey_list[apikey_index]) #获取第一页数据,并获取total 113 | if total == None: #该key余额已用完 114 | apikey_index += 1 #切换到下一个key 115 | if apikey_len == apikey_index: #所有key余额已用完 116 | print("APIKey一滴也没有了") 117 | break 118 | else: 119 | total = search_zoomeye(line, 1, apikey_list[apikey_index]) #使用下一个key 120 | if total <= 20: #不用翻页 121 | continue 122 | else: #通过total判断是否需要翻页 123 | page_num = total//20 + 1 #计算翻页的页数 124 | print("[+]Zoomeye总共页数:" + str(page_num)) 125 | for page in range(2, page_num + 1): 126 | print("[+]Zoomeye目前页数:" + str(page)) 127 | total = search_zoomeye(line, page, apikey_list[apikey_index]) 128 | if total == None: #该key余额已用完 129 | apikey_index += 1 #切换到下一个key 130 | if apikey_len == apikey_index: #所有key余额已用完 131 | print("APIKey一滴也没有了") 132 | break 133 | else: 134 | search_zoomeye(line, page, apikey_list[apikey_index]) #使用下一个key 135 | print(result_list) 136 | except Exception as e: 137 | print(str(e)) 138 | 139 | totxt(result_list) 140 | toexcel(result_list) 141 | 142 | if __name__ == '__main__': 143 | main() --------------------------------------------------------------------------------