├── README.md ├── config.yaml ├── e0e1-abroad.py ├── requirements.txt └── result └── test.txt /README.md: -------------------------------------------------------------------------------- 1 | # e0e1-abroad 2 | 3 | ### 简介 4 | 5 | > 用于收集国外众测项目内容,如项目其中的url、根域、app对应的内容等 6 | > 可用于联结自动化工具,进行扫描、信息收集、漏扫、fuzz等 7 | 8 | > 当前支持的国外众测系统:Intigriti、Hackerone、Bugcrowd、Openbugbounty、immunefi、inspectiv、yeswehack 9 | 10 | ### config配置 11 | 12 | > 需要进行配置的有:intigriti、hackerone、bugcrowd、inspectiv、yeswehack 13 | 14 | intigriti api-key配置:[key获取地址](https://app.intigriti.com/researcher/personal-access-tokens) 15 | 16 | hackerone 配置:[key获取地址](https://hackerone.com/settings/api_token/edit) 和 自己的名字 17 | 18 | Bugcrowd 配置:登录以后,获取cookie中 _bugcrowd_session的值 19 | 20 | inspectiv 配置:登录以后,获取Authorization:Token后面的值 21 | 22 | yeswehack 配置:登录以后,获取Authorization: Bearer后面的值 23 | 24 | ### 使用方法 25 | 26 | ``` 27 | 1.单纯获取Intigriti 所有程序内容 28 | python3 e0e1-abroad.py -it 29 | 30 | 2.获取Intigriti 所有程序内容,且额外提取url、app的内容出来 31 | python3 e0e1-abroad.py -it --url --app 32 | 33 | 3.获取Intigriti 所有程序内容,且额外提取url、app的内容出来,并且将url的内容进行优化 34 | python3 e0e1-abroad.py -it --url --app --url-op 35 | ``` 36 | ### 效果展示 37 | ![image](https://github.com/eeeeeeeeee-code/e0e1-abroad/assets/115862499/069ecfa2-ba08-4044-bedf-793106f715cc) 38 | 39 | 40 | ![0482e1b53827cb22e5407b3608551c6](https://github.com/eeeeeeeeee-code/e0e1-abroad/assets/115862499/e1a514d9-07d1-4e24-8509-171b380f090b) 41 | -------------------------------------------------------------------------------- /config.yaml: -------------------------------------------------------------------------------- 1 | intigriti: 2 | api-key: "" 3 | 4 | hackerone: 5 | hacker-user: "" 6 | hacker-key: "" 7 | 8 | bugcrowd: 9 | bug_token: "" 10 | 11 | inspectiv: 12 | in_token: "" 13 | 14 | yeswehack: 15 | yh_token: "" 16 | 17 | -------------------------------------------------------------------------------- /e0e1-abroad.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import argparse 3 | import time 4 | import requests 5 | import pandas as pd 6 | import concurrent.futures 7 | import re 8 | import os 9 | from bs4 import BeautifulSoup 10 | from colorama import Fore 11 | from yaml import safe_load 12 | 13 | requests.packages.urllib3.disable_warnings() 14 | 15 | 16 | class CONFIG: 17 | def __init__(self): 18 | config_path = os.path.join(os.path.dirname(__file__), "config.yaml") 19 | config = safe_load(open(config_path, "r",encoding="utf-8").read()) 20 | self.suffix_com = ['net', 'fr', 'me', 'ch', 'at', 'de', 'co', 'pt', 'se', 'it', 'pl', 'cloud', 'es', 'eu', 'be', 'jp', 'fi', 'nl', 'io', 'lu', 'link', 'tv', 'dk', 'info', 'ca', 'team', 'hu', 'com', 'cm', 'ie', 'no'] 21 | 22 | self.it_api = config['intigriti']['api-key'] 23 | self.it_max_thead = 5 24 | self.it_file_xlsx = "./result/it.xlsx" 25 | 26 | self.h1_user = config['hackerone']['hacker-user'] 27 | self.h1_key = config['hackerone']['hacker-key'] 28 | self.h1_max_thead = 5 29 | self.h1_file_xlsx = "./result/h1.xlsx" 30 | 31 | self.bc_token = config['bugcrowd']['bug_token'] 32 | self.bc_max_thead = 3 33 | self.bc_file_xlsx = "./result/bc.xlsx" 34 | 35 | self.ob_max_thead = 5 36 | self.ob_file_xlsx = "./result/ob.xlsx" 37 | 38 | self.im_max_thead = 5 39 | self.im_file_xlsx = "./result/im.xlsx" 40 | 41 | self.in_token = config["inspectiv"]["in_token"] 42 | self.in_max_thead = 5 43 | self.in_file_xlsx = "./result/inspectiv.xlsx" 44 | 45 | self.yh_token = config["yeswehack"]["yh_token"] 46 | self.yh_max_thead = 5 47 | self.yh_file_xlsx = "./result/yeswehack.xlsx" 48 | 49 | 50 | class Common: 51 | class Colored(object): 52 | def red(self, s): 53 | return Fore.RED + s + Fore.RESET 54 | 55 | def green(self, s): 56 | return Fore.GREEN + s + Fore.RESET 57 | 58 | def yellow(self, s): 59 | return Fore.YELLOW + s + Fore.RESET 60 | 61 | def blue(self, s): 62 | return Fore.BLUE + s + Fore.RESET 63 | 64 | def magenta(self, s): 65 | return Fore.MAGENTA + s + Fore.RESET 66 | 67 | def optimize_url(self, url): 68 | try: 69 | root_list = [] 70 | url_list = [] 71 | error_list = [] 72 | error_root_list = [] 73 | if url[0].startswith('*'): 74 | it_list = url[0].replace("*.", "").replace("/*", "").replace("/", "").strip() 75 | if it_list[-1] == "*": 76 | for i in CONFIG().suffix_com: 77 | it_com = it_list.split(".") 78 | it_com[1] = i 79 | url[0] = ".".join(it_com) 80 | root_list += (list(url)) 81 | elif re.search(r"[*()\[{\]}<>]", it_list): 82 | error_root_list += (["有问题自行处理的url:" + it_list, url[1]]) 83 | elif "." in it_list: 84 | url[0] = it_list 85 | root_list += url 86 | elif "." in url[0]: 87 | it_url = url[0].replace("/*", "").strip() 88 | if re.search(r"[*()\[{\]}<>]", it_url): 89 | error_list += (["有问题自行处理的url:" + it_url, url[1]]) 90 | else: 91 | url_list += ([it_url, url[1]]) 92 | return error_list + url_list, error_root_list + root_list 93 | except Exception as e: 94 | print(Common.Colored().red("bug :{}".format(e))) 95 | return [["", ""]], [["", ""]] 96 | 97 | def split_list_root(self, sublists): 98 | try: 99 | processed_list = [] 100 | 101 | def split_sublists(sublist): 102 | return [sublist[i:i + 2] for i in range(0, len(sublist), 2)] 103 | 104 | for item in sublists: 105 | if len(item) > 2: 106 | processed_list.extend(split_sublists(item)) 107 | else: 108 | processed_list.append(item) 109 | 110 | return processed_list 111 | except Exception as e: 112 | print(Common.Colored().red("bug :{}".format(e))) 113 | return [["", ""]] 114 | 115 | def url_optimize(self, url_result2): 116 | try: 117 | if argss.Urlop_tf: 118 | root_result = [] 119 | url_result = [] 120 | with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: 121 | results = executor.map(Common().optimize_url, url_result2) 122 | for i in results: 123 | c, b = i 124 | root_result.append(b) 125 | url_result.append(c) 126 | return (sorted(list(filter(None, root_result)), key=Intigriti().custom_sort)), (sorted(list(filter(None, url_result)), key=Intigriti().custom_sort)) 127 | except Exception as e: 128 | print(Common.Colored().red("bug :{}".format(e))) 129 | return [["", ""]], [["", ""]] 130 | 131 | 132 | class Process_Print2: 133 | def __init__(self, file_path): 134 | self.file_path = file_path 135 | 136 | def all_xlsx_file(self, data, columns_name, sheet_name): 137 | df = pd.DataFrame.from_records(data) 138 | df.columns = columns_name 139 | with pd.ExcelWriter(self.file_path, engine="openpyxl") as writer: 140 | df.to_excel(writer, sheet_name=sheet_name, engine='xlsxwriter', index=False) 141 | 142 | def add_xlsx_file(self, data, columns_name, sheet_name): 143 | df = pd.DataFrame.from_records(data) 144 | df.columns = columns_name 145 | with pd.ExcelWriter(self.file_path, engine="openpyxl", mode='a', if_sheet_exists="overlay") as writer: 146 | df.to_excel(writer, sheet_name=sheet_name, engine='xlsxwriter', index=False) 147 | 148 | 149 | class Intigriti: 150 | def __init__(self): 151 | self.it_api = CONFIG().it_api 152 | self.it_result = [] 153 | self.it_url_result = [] 154 | self.it_app_result = [] 155 | self.it_auth_result = [] 156 | self.headers = { 157 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3', 158 | "accept": "application/json", 159 | "Authorization": "Bearer {}".format(self.it_api) 160 | } 161 | 162 | def set_it_xlsx(self): 163 | Process_Print2(CONFIG().it_file_xlsx).all_xlsx_file(self.it_result, ['项目值', '项目名称'], "all") 164 | if argss.Urlop_tf: 165 | root_result, url_result = Common().url_optimize(self.it_url_result) 166 | Process_Print2(CONFIG().it_file_xlsx).add_xlsx_file(Common().split_list_root(root_result), ['项目值', '项目名称'], "root") 167 | Process_Print2(CONFIG().it_file_xlsx).add_xlsx_file(url_result, ['项目值', '项目名称'], "url") 168 | else: 169 | Process_Print2(CONFIG().it_file_xlsx).add_xlsx_file(self.it_url_result, ['项目值', '项目名称'], "url") 170 | if argss.App_tf: 171 | Process_Print2(CONFIG().it_file_xlsx).add_xlsx_file(self.it_app_result, ['项目值', '项目名称'], "app") 172 | Process_Print2(CONFIG().it_file_xlsx).add_xlsx_file(self.it_auth_result, ['项目值', '项目名称'], "auth") 173 | 174 | def find_jsonkey(self, item_data, key, name): 175 | try: 176 | for item in item_data: 177 | if item.get("tier", {}).get("value") != "Out Of Scope": 178 | type_value = item.get("type", {}).get("value") 179 | if key in item: 180 | self.it_result.append([item[key], name]) 181 | if argss.Url_tf: 182 | if key in item and type_value in ["Url", "Wildcard", "IpRange"]: 183 | self.it_url_result.append([item[key], name]) 184 | if argss.App_tf: 185 | if key in item and type_value in ["iOS", "Android"]: 186 | self.it_app_result.append([item[key], name]) 187 | if type_value in ['Device', 'Other']: 188 | self.it_auth_result.append([item[key], name]) 189 | except Exception as e: 190 | print(Common.Colored().red(e)) 191 | 192 | def custom_sort(self, item): 193 | if item[0].startswith("有问题"): 194 | return 0, item[0] 195 | elif not item[0].startswith('.'): 196 | return 1, item[0] 197 | return 2, item[0] 198 | 199 | def get_it_id(self): 200 | try: 201 | id_url = "https://api.intigriti.com/external/researcher/v1/programs/?limit=500" 202 | itreqo = requests.get(url=id_url, headers=self.headers, timeout=3, verify=False).json() 203 | print(Common.Colored().magenta("intigriti_id返回完成\n")) 204 | return itreqo['records'] 205 | except Exception as e: 206 | print(Common.Colored().red("get_it_id bugs: {}".format(e))) 207 | 208 | def fetch_data(self, it_id): 209 | pid_url = f"https://api.intigriti.com/external/researcher/v1/programs/{it_id['id']}" 210 | try: 211 | response = requests.get(pid_url, headers=self.headers, timeout=3, verify=False) 212 | data = response.json() 213 | self.find_jsonkey(data['domains']['content'], "endpoint", data["name"]) 214 | print(Common.Colored().green(f"已处理:{data['name']}")) 215 | except Exception as e: 216 | print(Common.Colored().red(f"it-id 问题 {it_id['id']}: {e}")) 217 | 218 | def get_it_programs(self): 219 | if self.it_api not in "": 220 | print(Common.Colored().magenta("开始收集it-url")) 221 | else: 222 | print(Common.Colored().red("请设置it-key")) 223 | exit(0) 224 | 225 | with concurrent.futures.ThreadPoolExecutor(max_workers=CONFIG().it_max_thead) as executor: 226 | executor.map(self.fetch_data, self.get_it_id()) 227 | 228 | self.set_it_xlsx() 229 | print(Common.Colored().yellow(f"Intigriti处理完成, 文件已保存至{CONFIG().it_file_xlsx}")) 230 | 231 | 232 | class Hackerone: 233 | def __init__(self): 234 | self.h1_user = CONFIG().h1_user 235 | self.h1_key = CONFIG().h1_key 236 | self.h1_reulst = [] 237 | self.h1_url = [] 238 | self.h1_app = [] 239 | self.h1_auth = [] 240 | self.headers = { 241 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3', 242 | 'Accept': 'application/json' 243 | } 244 | 245 | def set_it_xlsx(self): 246 | Process_Print2(CONFIG().h1_file_xlsx).all_xlsx_file(self.h1_reulst, ['项目值', '项目名称'], "all") 247 | if argss.Urlop_tf: 248 | root_result, url_result = Common().url_optimize(self.h1_url) 249 | Process_Print2(CONFIG().h1_file_xlsx).add_xlsx_file(Common().split_list_root(root_result), ['项目值', '项目名称'], "root") 250 | Process_Print2(CONFIG().h1_file_xlsx).add_xlsx_file(url_result, ['项目值', '项目名称'], "url") 251 | elif argss.Url_tf: 252 | Process_Print2(CONFIG().h1_file_xlsx).add_xlsx_file(self.h1_url, ['项目值', '项目名称'], "url") 253 | if argss.App_tf: 254 | Process_Print2(CONFIG().h1_file_xlsx).add_xlsx_file(self.h1_app, ['项目值', '项目名称'], "app") 255 | Process_Print2(CONFIG().h1_file_xlsx).add_xlsx_file(self.h1_auth, ['项目值', '项目名称'], "auth") 256 | 257 | def find_jsonkey(self, item_data, name): 258 | for item in item_data: 259 | if item.get('attributes').get("eligible_for_submission"): 260 | type_value = item.get('attributes').get("asset_type") 261 | self.h1_reulst.append([item["attributes"]["asset_identifier"], name]) 262 | if argss.Url_tf: 263 | if type_value in ["URL", "WILDCARD", "OTHER", "CIDR", "API"]: 264 | self.h1_url.append([item["attributes"]["asset_identifier"], name]) 265 | if argss.App_tf: 266 | if type_value in ["GOOGLE_PLAY_APP_ID", "OTHER_APK", "GOOGLE_PLAY_APP_ID", "WINDOWS_APP_STORE_APP_ID", "TESTFLIGHT"]: 267 | self.h1_app.append([item["attributes"]["asset_identifier"], name]) 268 | if type_value in ["AI_MODEL", "HARDWARE", "OTHER", "DOWNLOADABLE_EXECUTABLES0", "SMART_CONTRACT", "SOURCE_CODE"]: 269 | self.h1_auth.append([item["attributes"]["asset_identifier"], name]) 270 | 271 | def get_h1_id(self): 272 | number = 1 273 | prams = [] 274 | while True: 275 | api_url = f"https://api.hackerone.com/v1/hackers/programs?page[size]=100&page[number]={number}" 276 | try: 277 | response = requests.get(api_url, auth=(self.h1_user, self.h1_key)) 278 | if response.status_code != 200: 279 | print(Common.Colored().red("回显不为200,重新配置h1 user和key")) 280 | exit(0) 281 | h1_req = response.json().get("data") 282 | if not h1_req: 283 | return prams 284 | prams += h1_req 285 | except requests.exceptions.RequestException as e: 286 | print(Common.Colored().red("user或者key错误")) 287 | break 288 | number += 1 289 | print(Common.Colored().magenta("获取id完成~~~~~")) 290 | return prams 291 | 292 | def get_h1_url(self, id_params): 293 | try: 294 | h1_name = id_params["attributes"]["handle"] 295 | api_url = "https://api.hackerone.com/v1/hackers/programs/{}/structured_scopes?page[number]=1&page[size]=100".format(h1_name) 296 | h1_req = requests.get(api_url, auth=(self.h1_user, self.h1_key)).json() 297 | h1_data = h1_req['data'] 298 | self.find_jsonkey(h1_data, h1_name) 299 | print(Common.Colored().green(f"已处理:{h1_name}")) 300 | except Exception as e: 301 | print(Common.Colored().red("bugs {}".format(e))) 302 | 303 | def get_h1_programs(self): 304 | try: 305 | if self.h1_user != "" and self.h1_key != "": 306 | print(Common.Colored().magenta("h1已配置")) 307 | else: 308 | print(Common.Colored().red("h1 user和key未配置")) 309 | exit(0) 310 | 311 | id_params = Hackerone().get_h1_id() 312 | with concurrent.futures.ThreadPoolExecutor(max_workers=CONFIG().h1_max_thead) as executor: 313 | executor.map(self.get_h1_url, id_params) 314 | 315 | self.set_it_xlsx() 316 | print(Common.Colored().yellow(f"Hackerone 处理完成,结果保存至{CONFIG().h1_file_xlsx}")) 317 | except Exception as e: 318 | print(Common.Colored().red("bugs {}".format(e))) 319 | 320 | 321 | class Bugcrowd: 322 | def __init__(self): 323 | self.bc_result = [] 324 | self.bc_url = [] 325 | self.bc_app = [] 326 | self.bc_auth = [] 327 | self.headers = { 328 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3', 329 | 'Cookies': f'_bugcrowd_session={CONFIG().bc_token}', 330 | 'Accept': '*/*' 331 | } 332 | 333 | def set_it_xlsx(self): 334 | Process_Print2(CONFIG().bc_file_xlsx).all_xlsx_file(self.bc_result, ['项目值', '项目名称'], "all") 335 | if argss.Urlop_tf: 336 | root_result, url_result = Common().url_optimize(self.bc_url) 337 | Process_Print2(CONFIG().bc_file_xlsx).add_xlsx_file(Common().split_list_root(root_result), ['项目值', '项目名称'], "root") 338 | Process_Print2(CONFIG().bc_file_xlsx).add_xlsx_file(url_result, ['项目值', '项目名称'], "url") 339 | else: 340 | Process_Print2(CONFIG().bc_file_xlsx).add_xlsx_file(self.bc_url, ['项目值', '项目名称'], "url") 341 | if argss.App_tf: 342 | Process_Print2(CONFIG().bc_file_xlsx).add_xlsx_file(self.bc_app, ['项目值', '项目名称'], "app") 343 | Process_Print2(CONFIG().bc_file_xlsx).add_xlsx_file(self.bc_auth, ['项目值', '项目名称'], "auth") 344 | 345 | def find_jsonkey(self, item_data, name): 346 | for item in item_data: 347 | type_value = item.get('category') 348 | self.bc_result.append([item["name"], name]) 349 | if type_value in ["other", "hardware"]: 350 | self.bc_auth.append([item["name"], name]) 351 | if argss.Url_tf: 352 | if type_value in ["website", "api"]: 353 | self.bc_url.append([item["name"], name]) 354 | if argss.App_tf: 355 | if type_value in ["android", "ios"]: 356 | self.bc_app.append([item["name"], name]) 357 | 358 | def get_handle(self): 359 | try: 360 | jurl = "https://bugcrowd.com/engagements.json?category=bug_bounty&sort_by=promoted&sort_direction=desc&page=" 361 | page = 1 362 | br_list = [] 363 | while True: 364 | repose = requests.get(f"{jurl}{page}", headers=self.headers, timeout=5, verify=False).json() 365 | print(repose) 366 | if not repose['engagements']: 367 | break 368 | br_list += [eng['briefUrl'] for eng in repose['engagements']] 369 | page += 1 370 | time.sleep(0.3) 371 | print(Common.Colored().magenta("获取handle完成")) 372 | return br_list 373 | except Exception as e: 374 | print(Common.Colored().red(e)) 375 | 376 | def get_handle_url(self, handle): 377 | try: 378 | bc_url = f"https://bugcrowd.com" 379 | repose_url = requests.get(f'{bc_url}{handle}/target_groups', headers=self.headers, timeout=5, verify=False).json() 380 | targets_list = [tars["targets_url"] for tars in repose_url['groups'] if tars["in_scope"]] 381 | for tar in targets_list: 382 | repose_tars = requests.get(f'{bc_url}/{tar}', headers=self.headers, timeout=5, verify=False) 383 | self.find_jsonkey(repose_tars.json()["targets"], handle) 384 | print(Common.Colored().green(f"已处理:{handle}")) 385 | except Exception as e: 386 | print(Common.Colored().red(e)) 387 | 388 | def get_bc_programs(self): 389 | try: 390 | if CONFIG().bc_token == "": 391 | print(Common.Colored().red("bc_token未设置")) 392 | exit(0) 393 | else: 394 | print(Common.Colored().magenta("bc_token已经设置")) 395 | 396 | handle_list = self.get_handle() 397 | with concurrent.futures.ThreadPoolExecutor(max_workers=CONFIG().bc_max_thead) as executor: 398 | executor.map(self.get_handle_url, handle_list) 399 | 400 | self.set_it_xlsx() 401 | print(Common.Colored().yellow(f"Bugcrowd 已处理完成,结果保存至{CONFIG().bc_file_xlsx}")) 402 | except Exception as e: 403 | print(Common.Colored().red(e)) 404 | 405 | 406 | class Openbugbounty: 407 | def __init__(self): 408 | self.ob_result = [] 409 | self.headers = { 410 | 'accept': 'application/json, text/javascript, */*; q=0.01', 411 | 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 412 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', 413 | 'x-requested-with': 'XMLHttpRequest', 414 | } 415 | self.headers2 = { 416 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', 417 | } 418 | 419 | def set_it_xlsx(self): 420 | Process_Print2(CONFIG().ob_file_xlsx).all_xlsx_file(self.ob_result, ['项目值', '项目名称'], "all") 421 | if argss.Urlop_tf: 422 | root_result, url_result = Common().url_optimize(self.ob_result) 423 | Process_Print2(CONFIG().ob_file_xlsx).add_xlsx_file(Common().split_list_root(root_result), ['项目值', '项目名称'], "root") 424 | Process_Print2(CONFIG().ob_file_xlsx).add_xlsx_file(url_result, ['项目值', '项目名称'], "url") 425 | 426 | def get_ob_handle(self): 427 | try: 428 | page_int = 49 429 | a_tag_list = [] 430 | while True: 431 | data = { 432 | 'draw': '40', 433 | 'columns[0][data]': '0', 434 | 'columns[0][name]': '', 435 | 'columns[0][searchable]': 'true', 436 | 'columns[0][orderable]': 'false', 437 | 'columns[0][search][value]': '', 438 | 'columns[0][search][regex]': 'false', 439 | 'columns[1][data]': '1', 440 | 'columns[1][name]': '', 441 | 'columns[1][searchable]': 'true', 442 | 'columns[1][orderable]': 'false', 443 | 'columns[1][search][value]': '', 444 | 'columns[1][search][regex]': 'false', 445 | 'columns[2][data]': '2', 446 | 'columns[2][name]': '', 447 | 'columns[2][searchable]': 'true', 448 | 'columns[2][orderable]': 'false', 449 | 'columns[2][search][value]': '', 450 | 'columns[2][search][regex]': 'false', 451 | 'start': page_int, 452 | 'length': '50', 453 | 'search[value]': '', 454 | 'search[regex]': 'false', 455 | } 456 | 457 | response = requests.post('https://www.openbugbounty.org/bugbounty-list/ajax.php', headers=self.headers, data=data, timeout=5, verify=False) 458 | 459 | if "/images/404.jpg" in response.text: 460 | break 461 | for a_tag in response.json()["data"]: 462 | soup = BeautifulSoup(a_tag[0], "html.parser") 463 | a_tag_list.append(soup.a["href"]) 464 | page_int += 50 465 | print(Common.Colored().magenta("获取handle完成~~\n")) 466 | return a_tag_list 467 | except Exception as e: 468 | print(Common.Colored().red(e)) 469 | 470 | def get_ob_handleurl(self, handle): 471 | try: 472 | response = requests.get(f'https://www.openbugbounty.org{handle}', headers=self.headers2, timeout=5, verify=False) 473 | soup = BeautifulSoup(response.content, "html.parser") 474 | tables = soup.find_all('table', class_="wishlist open-bounty")[0] 475 | self.ob_result += [[td_tar.text, handle] for td_tar in tables.find_all("td")] 476 | print(Common.Colored().green(f"已处理:{handle}")) 477 | except Exception as e: 478 | print(Common.Colored().red(e)) 479 | 480 | def get_ob_parms(self): 481 | try: 482 | print(Common.Colored().magenta("Openbugbounty 已准备完成")) 483 | handle_list = self.get_ob_handle() 484 | 485 | with concurrent.futures.ThreadPoolExecutor(max_workers=CONFIG().ob_max_thead) as executor: 486 | executor.map(self.get_ob_handleurl, handle_list) 487 | 488 | self.set_it_xlsx() 489 | print(Common.Colored().yellow(f"Openbugbounty 处理完成,结果保存至{CONFIG().ob_file_xlsx}")) 490 | except Exception as e: 491 | print(Common.Colored().red(e)) 492 | 493 | 494 | class immunefi: 495 | def __init__(self): 496 | self.im_result = [] 497 | self.headers = { 498 | 'accept': 'application/json, text/plain, */*', 499 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', 500 | } 501 | 502 | def set_it_xlsx(self): 503 | Process_Print2(CONFIG().im_file_xlsx).all_xlsx_file(self.im_result, ['项目值', '项目名称'], "all") 504 | if argss.Urlop_tf: 505 | root_result, url_result = Common().url_optimize(self.im_result) 506 | Process_Print2(CONFIG().im_file_xlsx).add_xlsx_file(Common().split_list_root(root_result), ['项目值', '项目名称'], "root") 507 | Process_Print2(CONFIG().im_file_xlsx).add_xlsx_file(url_result, ['项目值', '项目名称'], "url") 508 | 509 | def get_im_handle(self): 510 | try: 511 | repose = requests.get("https://immunefi.com/_next/data/MyPLbGoqDLuTD2N74EBK7/bug-bounty.json", headers=self.headers).json() 512 | name_list = [tar["id"] for tar in repose["pageProps"]["bounties"]] 513 | print(Common.Colored().magenta("name 获取完成~~~~")) 514 | return name_list 515 | except Exception as e: 516 | print(Common.Colored().red(e)) 517 | 518 | def get_im_handle_url(self, handle): 519 | try: 520 | repose = requests.get(f"https://immunefi.com/bounty/{handle}/", headers=self.headers) 521 | soup = BeautifulSoup(repose.text, "html.parser") 522 | section = soup.find_all('section', class_='mb-12') 523 | for section in section: 524 | h3_tag = section.find('h3') 525 | if h3_tag is not None and h3_tag.text == 'Assets in scope': 526 | a_tags = section.find_all('a') 527 | for a_tag in a_tags: 528 | try: 529 | self.im_result.append([a_tag['title'], handle]) 530 | except: 531 | pass 532 | print(Common.Colored().green(f"已处理:{handle}")) 533 | except Exception as e: 534 | print(Common.Colored().red(e)) 535 | 536 | def get_im_parms(self): 537 | try: 538 | print(Common.Colored().magenta("im 开始~~~~~")) 539 | 540 | name_list = self.get_im_handle() 541 | 542 | with concurrent.futures.ThreadPoolExecutor(max_workers=CONFIG().im_max_thead) as executor: 543 | executor.map(self.get_im_handle_url, name_list) 544 | 545 | self.set_it_xlsx() 546 | print(Common.Colored().yellow(f"immunefi 已处理完成,结果保存至{CONFIG().im_file_xlsx}")) 547 | except Exception as e: 548 | print(Common.Colored().red(e)) 549 | 550 | 551 | class inspectiv: 552 | def __init__(self): 553 | self.in_result = [] 554 | self.headers = { 555 | 'accept': 'application/json, text/plain, */*', 556 | 'authorization': f'Token {CONFIG().in_token}', 557 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', 558 | } 559 | 560 | def set_it_xlsx(self): 561 | Process_Print2(CONFIG().in_file_xlsx).all_xlsx_file(self.in_result, ['项目值', '项目名称'], "all") 562 | if argss.Urlop_tf: 563 | root_result, url_result = Common().url_optimize(self.in_result) 564 | Process_Print2(CONFIG().in_file_xlsx).add_xlsx_file(Common().split_list_root(root_result), ['项目值', '项目名称'], "root") 565 | Process_Print2(CONFIG().in_file_xlsx).add_xlsx_file(url_result, ['项目值', '项目名称'], "url") 566 | 567 | def get_in_handle(self): 568 | try: 569 | parg_int = 1 570 | uuid_list = [] 571 | while True: 572 | params = { 573 | 'page': parg_int, 574 | 'search': '', 575 | 'all': 'true', 576 | 'private': 'false', 577 | 'favorites': 'false', 578 | 579 | } 580 | 581 | response = requests.get('https://api.bounty.inspectiv.com/api/programs/short-list/', params=params, headers=self.headers).json() 582 | try: 583 | if str(response["status_code"]) == "404": 584 | break 585 | except: 586 | pass 587 | uuid_list += [tars["uuid"] for tars in response["results"]] 588 | parg_int += 1 589 | print(Common.Colored().magenta("uuid收集完成")) 590 | return uuid_list 591 | except Exception as e: 592 | print(Common.Colored().red(e)) 593 | 594 | def get_in_handleurl(self, handle): 595 | try: 596 | repose = requests.get(f"https://api.bounty.inspectiv.com/api/programs/{handle}/", headers=self.headers) 597 | url_name = repose.json()["company_name"] 598 | url_list = re.findall(r"(?:Tier [123])\s*\|\s*(.*?)\s*(?=\|)", repose.text) 599 | self.in_result += [[tar, url_name] for tar in url_list] 600 | print(Common.Colored().green(f"已处理:{url_name}")) 601 | except Exception as e: 602 | print(Common.Colored().red(e)) 603 | 604 | def get_in_parms(self): 605 | try: 606 | if CONFIG().in_token == "": 607 | print(Common.Colored().red("请配置in_token")) 608 | exit(0) 609 | else: 610 | print(Common.Colored().magenta("已配置in_token")) 611 | 612 | uuid_list = self.get_in_handle() 613 | with concurrent.futures.ThreadPoolExecutor(max_workers=CONFIG().in_max_thead) as executor: 614 | executor.map(self.get_in_handleurl, uuid_list) 615 | 616 | self.set_it_xlsx() 617 | print(Common.Colored().yellow(f"inspectiv 处理完成,结果已保存至{CONFIG().in_file_xlsx}")) 618 | except Exception as e: 619 | print(Common.Colored().red(e)) 620 | 621 | 622 | class Yeswehack: 623 | def __init__(self): 624 | self.yh_result = [] 625 | self.yh_url = [] 626 | self.yh_app = [] 627 | self.yh_auth = [] 628 | self.headers = { 629 | 'accept': 'application/json, text/plain, */*', 630 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', 631 | 'Authorization': f"Bearer {CONFIG().yh_token}" 632 | } 633 | 634 | def set_it_xlsx(self): 635 | Process_Print2(CONFIG().yh_file_xlsx).all_xlsx_file(self.yh_result, ['项目值', '项目名称'], "all") 636 | if argss.Urlop_tf: 637 | root_result, url_result = Common().url_optimize(self.yh_url) 638 | Process_Print2(CONFIG().yh_file_xlsx).add_xlsx_file(Common().split_list_root(root_result), ['项目值', '项目名称'], "root") 639 | Process_Print2(CONFIG().yh_file_xlsx).add_xlsx_file(url_result, ['项目值', '项目名称'], "url") 640 | elif argss.Url_tf: 641 | Process_Print2(CONFIG().yh_file_xlsx).add_xlsx_file(self.yh_url, ['项目值', '项目名称'], "url") 642 | if argss.App_tf: 643 | Process_Print2(CONFIG().yh_file_xlsx).add_xlsx_file(self.yh_app, ['项目值', '项目名称'], "app") 644 | Process_Print2(CONFIG().yh_file_xlsx).add_xlsx_file(self.yh_auth, ['项目值', '项目名称'], "auth") 645 | def find_jsonkey(self, item_data, name): 646 | for item in item_data: 647 | type_value = item.get('scope_type') 648 | self.yh_result.append([item["scope"], name]) 649 | if argss.Url_tf: 650 | if type_value in ["web-application", "api", "ip-address"]: 651 | self.yh_url.append([item["scope"], name]) 652 | if argss.App_tf: 653 | if type_value in ["mobile-application-android", "mobile-application-ios", "mobile-application"]: 654 | self.yh_app.append([item["scope"], name]) 655 | if type_value in ["other", "application"]: 656 | self.yh_auth.append([item["scope"], name]) 657 | 658 | def get_yh_handle(self): 659 | try: 660 | page_int = 1 661 | handle_list = [] 662 | while True: 663 | repose = requests.get(f"https://api.yeswehack.com/programs?page={page_int}&resultsPerPage=50", headers=self.headers, timeout=5, verify=False).json() 664 | if not repose["items"]: 665 | break 666 | for i in repose["items"]: 667 | handle_list.append(i["slug"]) 668 | page_int += 1 669 | print(Common.Colored().magenta("ye slug列表获取完成")) 670 | return handle_list 671 | except Exception as e: 672 | print(Common.Colored().red(e)) 673 | 674 | def get_yh_handle_url(self, handle): 675 | try: 676 | repose = requests.get(f"https://api.yeswehack.com/programs/{handle}", headers=self.headers, timeout=5, verify=False).json() 677 | scope_list = repose["scopes"] 678 | self.find_jsonkey(scope_list, handle) 679 | print(Common.Colored().green(f"已处理:{handle}")) 680 | except Exception as e: 681 | print(Common.Colored().red(e)) 682 | 683 | def get_yh_parms(self): 684 | try: 685 | if CONFIG().yh_token == "": 686 | print(Common.Colored().red("yeswehack 没有配置token")) 687 | exit(0) 688 | else: 689 | print(Common.Colored().magenta("yeswehack token已配置")) 690 | 691 | handle_list = self.get_yh_handle() 692 | with concurrent.futures.ThreadPoolExecutor(max_workers=CONFIG().yh_max_thead) as executor: 693 | executor.map(self.get_yh_handle_url, handle_list) 694 | 695 | self.set_it_xlsx() 696 | print(Common.Colored().yellow(f"Yeswehack 已处理完成,结果保存至{CONFIG().yh_file_xlsx}")) 697 | except Exception as e: 698 | print(Common.Colored().red(e)) 699 | 700 | 701 | def args_port(): 702 | try: 703 | parser = argparse.ArgumentParser(description='Abroad input') 704 | parser.add_argument('--it', dest='Intigriti_tf', action='store_true', help='获取Intigriti程序内容') 705 | parser.add_argument('--h1', dest='Hackerone_tf', action='store_true', help='获取hackeron程序内容') 706 | parser.add_argument('--bc', dest='Bugcrowd_tf', action='store_true', help='获取bugcrowd程序内容') 707 | parser.add_argument('--ob', dest='Openbugbounty_tf', action='store_true', help='获取Openbugbounty程序内容') 708 | parser.add_argument('--im', dest='Immunefi_tf', action='store_true', help='获取immunefi程序内容') 709 | parser.add_argument('--in', dest='Inspectiv_tf', action='store_true', help='获取Inspectiv程序内容') 710 | parser.add_argument('--yh', dest='Yeswehack_tf', action='store_true', help='获取Yeswehack程序内容') 711 | parser.add_argument('--url', dest='Url_tf', action='store_true', help='额外获取url内容') 712 | parser.add_argument('--app', dest='App_tf', action='store_true', help='额外获取app内容') 713 | parser.add_argument('--url-op', dest='Urlop_tf', action='store_true', help='选择是否优化url内容') 714 | args = parser.parse_args() 715 | return args 716 | except Exception as e: 717 | print("args_port bugs: {}".format(e)) 718 | 719 | 720 | def run(): 721 | try: 722 | e0e1_abroad = Common.Colored().green(''' 723 | ------------------------------------------------------------- 724 | | ___ _ _ _ | 725 | | ___ / _ \ ___/ | __ _| |__ _ __ ___ __ _ __| | | 726 | | / _ \ | | |/ _ \ |_____ / _` | '_ \| '__/ _ \ / _` |/ _` | | 727 | | | __/ |_| | __/ |_____| (_| | |_) | | | (_) | (_| | (_| | | 728 | | \___|\___/ \___|_| \__,_|_.__/|_| \___/ \__,_|\__,_| | 729 | | -- by: eeeeee -- | 730 | | -- 该工具仅用于学习参考,均与作者无关 -- | 731 | -------------------------------------------------------------- 732 | ''') 733 | 734 | if argss.Intigriti_tf: 735 | print(e0e1_abroad) 736 | Intigriti().get_it_programs() 737 | 738 | if argss.Hackerone_tf: 739 | print(e0e1_abroad) 740 | Hackerone().get_h1_programs() 741 | 742 | if argss.Bugcrowd_tf: 743 | print(e0e1_abroad) 744 | Bugcrowd().get_bc_programs() 745 | 746 | if argss.Openbugbounty_tf: 747 | print(e0e1_abroad) 748 | Openbugbounty().get_ob_parms() 749 | 750 | if argss.Immunefi_tf: 751 | print(e0e1_abroad) 752 | immunefi().get_im_parms() 753 | 754 | if argss.Inspectiv_tf: 755 | print(e0e1_abroad) 756 | inspectiv().get_in_parms() 757 | 758 | if argss.Yeswehack_tf: 759 | print(e0e1_abroad) 760 | Yeswehack().get_yh_parms() 761 | except Exception as e: 762 | print("__run bugs: {}".format(e)) 763 | 764 | 765 | if __name__ == "__main__": 766 | global argss 767 | argss = args_port() 768 | run() 769 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | beautifulsoup4==4.11.1 2 | colorama==0.4.6 3 | pandas==2.0.1 4 | PyYAML==6.0.1 5 | Requests==2.31.0 6 | -------------------------------------------------------------------------------- /result/test.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eeeeeeeeee-code/e0e1-abroad/7ad445bd10a07e66f4356220db296422297095c4/result/test.txt --------------------------------------------------------------------------------