def attack_upload(self, original_request): # Should not yield request as it will mark it as attacked mutator = FileMutator(payloads=self.payloads) current_parameter = None vulnerable_parameter = False for mutated_request, parameter, payload, flags in mutator.mutate(original_request): try: if current_parameter != parameter: # Forget what we know about current parameter current_parameter = parameter vulnerable_parameter = False elif vulnerable_parameter: # If parameter is vulnerable, just skip till next parameter continue if self.verbose == 2: print("[¨] {0}".format(mutated_request)) try: response = self.crawler.send(mutated_request) except RequestException as exception: yield exception else: pattern = search_pattern(response.content, self.flag_to_patterns(flags)) if pattern and not self.false_positive(original_request, pattern): self.add_vuln( request_id=original_request.path_id, category=Vulnerability.XXE, level=Vulnerability.HIGH_LEVEL, request=mutated_request, info="XXE vulnerability leading to file disclosure", parameter=parameter ) self.log_red("---") self.log_red( Vulnerability.MSG_PARAM_INJECT, self.MSG_VULN, original_request.url, parameter ) self.log_red(Vulnerability.MSG_EVIL_REQUEST) self.log_red(mutated_request.http_repr()) self.log_red("---") vulnerable_parameter = True self.vulnerables.add(original_request.path_id) except KeyboardInterrupt as exception: yield exception
async def attack_upload(self, original_request): mutator = FileMutator(payloads=self.payloads) current_parameter = None vulnerable_parameter = False for mutated_request, parameter, _payload, flags in mutator.mutate(original_request): if current_parameter != parameter: # Forget what we know about current parameter current_parameter = parameter vulnerable_parameter = False elif vulnerable_parameter: # If parameter is vulnerable, just skip till next parameter continue if self.verbose == 2: print("[¨] {0}".format(mutated_request)) try: response = await self.crawler.async_send(mutated_request) except RequestError: self.network_errors += 1 else: pattern = search_pattern(response.content, self.flag_to_patterns(flags)) if pattern and not await self.false_positive(original_request, pattern): self.add_vuln( request_id=original_request.path_id, category=NAME, level=HIGH_LEVEL, request=mutated_request, info="XXE vulnerability leading to file disclosure", parameter=parameter ) self.log_red("---") self.log_red( Messages.MSG_PARAM_INJECT, self.MSG_VULN, original_request.url, parameter ) self.log_red(Messages.MSG_EVIL_REQUEST) self.log_red(mutated_request.http_repr()) self.log_red("---") vulnerable_parameter = True self.vulnerables.add(original_request.path_id)
def finish(self): endpoint_url = "{}get_xxe.php?session_id={}".format( self.internal_endpoint, self._session_id) print( _("[*] Asking endpoint URL {} for results, please wait...").format( endpoint_url)) 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 = self.crawler.send(endpoint_request) except RequestException: self.network_errors += 1 print( _("[!] 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 = 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 "{}.dtd".format(payload_name) 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("{}?{}".format( 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)) self.add_vuln(request_id=original_request.path_id, category=NAME, level=HIGH_LEVEL, request=mutated_request, info=vuln_message, parameter=parameter) self.log_red("---") self.log_red(vuln_message) self.log_red(Messages.MSG_EVIL_REQUEST) self.log_red(mutated_request.http_repr()) self.log_red("---")