async def attack(self, request: Request): try: with open(os.path.join(self.user_config_dir, self.NIKTO_DB), encoding='utf-8') as nikto_db_file: reader = csv.reader(nikto_db_file) next(reader) self.nikto_db = [ line for line in reader if line != [] and line[0].isdigit() ] except IOError: logging.warning(_("Problem with local nikto database.")) logging.info(_("Downloading from the web...")) await self.update() self.finished = True root_url = request.url self.parts = urlparse(root_url) tasks = set() pending_count = 0 with open(os.path.join(self.user_config_dir, self.NIKTO_DB), encoding='utf-8') as nikto_db_file: reader = csv.reader(nikto_db_file) while True: if pending_count < self.options[ "tasks"] and not self._stop_event.is_set(): try: line = next(reader) except StopIteration: pass else: if line == [] or not line[0].isdigit(): continue task = asyncio.create_task(self.process_line(line)) tasks.add(task) if not tasks: break done_tasks, pending_tasks = await asyncio.wait( tasks, timeout=0.01, return_when=asyncio.FIRST_COMPLETED) pending_count = len(pending_tasks) for task in done_tasks: await task tasks.remove(task) if self._stop_event.is_set(): for task in pending_tasks: task.cancel() tasks.remove(task)
async def _verify_wapp_database(self, categories_file_path: str, technologies_base_path: str, groups_file_path: str): try: with open(categories_file_path, encoding='utf-8') as categories_file, \ open(technologies_base_path, encoding='utf-8') as technologies_file, \ open(groups_file_path, encoding='utf-8') as groups_file: json.load(categories_file) json.load(technologies_file) json.load(groups_file) except IOError: logging.warning(_("Problem with local wapp database.")) logging.info(_("Downloading from the web...")) await self.update()
async def finish(self): endpoint_url = f"{self.internal_endpoint}get_ssrf.php?session_id={self._session_id}" logging.info(_("[*] Asking endpoint URL {} for results, please wait...").format(endpoint_url)) await sleep(2) # A la fin des attaques on questionne le endpoint pour savoir s'il a été contacté endpoint_request = Request(endpoint_url) try: response = await self.crawler.async_send(endpoint_request) except RequestError: self.network_errors += 1 logging.error(_("[!] Unable to request endpoint URL '{}'").format(self.internal_endpoint)) else: data = response.json if isinstance(data, dict): for request_id in data: original_request = await self.persister.get_path_by_id(request_id) if original_request is None: raise ValueError("Could not find the original request with that ID") page = original_request.path for hex_param in data[request_id]: parameter = unhexlify(hex_param).decode("utf-8") for infos in data[request_id][hex_param]: request_url = infos["url"] # Date in ISO format request_date = infos["date"] request_ip = infos["ip"] request_method = infos["method"] # request_size = infos["size"] if parameter == "QUERY_STRING": vuln_message = Messages.MSG_QS_INJECT.format(self.MSG_VULN, page) else: vuln_message = _( "{0} via injection in the parameter {1}.\n" "The target performed an outgoing HTTP {2} request at {3} with IP {4}.\n" "Full request can be seen at {5}" ).format( self.MSG_VULN, parameter, request_method, request_date, request_ip, request_url ) mutator = Mutator( methods="G" if original_request.method == "GET" else "PF", payloads=[("http://external.url/page", Flags())], qs_inject=self.must_attack_query_string, parameters=[parameter], skip=self.options.get("skipped_parameters") ) mutated_request, __, __, __ = next(mutator.mutate(original_request)) await self.add_vuln_critical( request_id=original_request.path_id, category=NAME, request=mutated_request, info=vuln_message, parameter=parameter, wstg=WSTG_CODE ) log_red("---") log_red( Messages.MSG_QS_INJECT if parameter == "QUERY_STRING" else Messages.MSG_PARAM_INJECT, self.MSG_VULN, page, parameter ) log_red(Messages.MSG_EVIL_REQUEST) log_red(mutated_request.http_repr()) log_red("---")
async def _verify_htp_database(self, htp_database_path: str): if os.path.exists(htp_database_path) is False: logging.warning(_("Problem with local htp database.")) logging.info(_("Downloading from the web...")) await self.update()
async def finish(self): endpoint_url = f"{self.internal_endpoint}get_xxe.php?session_id={self._session_id}" logging.info( _("[*] Asking endpoint URL {} for results, please wait...").format( endpoint_url)) await sleep(2) # A la fin des attaques on questionne le endpoint pour savoir s'il a été contacté endpoint_request = Request(endpoint_url) try: response = await self.crawler.async_send(endpoint_request) except RequestError: self.network_errors += 1 logging.error( _("[!] Unable to request endpoint URL '{}'").format( self.internal_endpoint)) return data = response.json if not isinstance(data, dict): return for request_id in data: original_request = await self.persister.get_path_by_id(request_id) if original_request is None: continue # raise ValueError("Could not find the original request with ID {}".format(request_id)) page = original_request.path for hex_param in data[request_id]: parameter = unhexlify(hex_param).decode("utf-8") for infos in data[request_id][hex_param]: request_url = infos["url"] # Date in ISO format request_date = infos["date"] request_ip = infos["ip"] request_size = infos["size"] payload_name = infos["payload"] if parameter == "QUERY_STRING": vuln_message = Messages.MSG_QS_INJECT.format( self.MSG_VULN, page) elif parameter == "raw body": vuln_message = _( "Out-Of-Band {0} by sending raw XML in request body" ).format(self.MSG_VULN) else: vuln_message = _( "Out-Of-Band {0} via injection in the parameter {1}" ).format(self.MSG_VULN, parameter) more_infos = _( "The target sent {0} bytes of data to the endpoint at {1} with IP {2}.\n" "Received data can be seen at {3}.").format( request_size, request_date, request_ip, request_url) vuln_message += "\n" + more_infos # placeholder if shit happens payload = ( "<xml>" "See https://phonexicum.github.io/infosec/xxe.html#attack-vectors" "</xml>") for payload, _flags in self.payloads: if f"{payload_name}.dtd" in payload: payload = payload.replace( "[PATH_ID]", str(original_request.path_id)) payload = payload.replace("[PARAM_AS_HEX]", "72617720626f6479") break if parameter == "raw body": mutated_request = Request(original_request.path, method="POST", enctype="text/xml", post_params=payload) elif parameter == "QUERY_STRING": mutated_request = Request( f"{original_request.path}?{quote(payload)}", method="GET") elif parameter in original_request.get_keys or parameter in original_request.post_keys: mutator = Mutator( methods="G" if original_request.method == "GET" else "P", payloads=[(payload, Flags())], qs_inject=self.must_attack_query_string, parameters=[parameter], skip=self.options.get("skipped_parameters")) mutated_request, __, __, __ = next( mutator.mutate(original_request)) else: mutator = FileMutator( payloads=[(payload, Flags())], parameters=[parameter], skip=self.options.get("skipped_parameters")) mutated_request, __, __, __ = next( mutator.mutate(original_request)) await self.add_vuln_high( request_id=original_request.path_id, category=NAME, request=mutated_request, info=vuln_message, parameter=parameter, wstg=WSTG_CODE) log_red("---") log_red(vuln_message) log_red(Messages.MSG_EVIL_REQUEST) log_red(mutated_request.http_repr()) log_red("---")