def test_wrong_object(self): target = Target("192.167.1.1") assert target.name == "192.167.1.1" with pytest.raises(AssertionError): assert Target(None) assert Target(1)
def test_patterns(self): target = Target("192.167.1.1") assert target.name == "192.167.1.1" with pytest.raises(AssertionError): assert Target("169.254.169.254") assert Target("127.0.0.1") assert Target("http://github.com")
def test_resolves_validity(self): target = Target("ssh.mozilla.com") assert target.name == "ssh.mozilla.com" target = Target(u'ssh.mozilla.com') assert target.name == u'ssh.mozilla.com' target = Target("github.com") assert target.name == "github.com" with pytest.raises(AssertionError): assert Target("notarealdomainname.mozilla.com")
def test_private_addresses(self): target = Target("192.167.1.1") assert target.name == "192.167.1.1" target = Target("192.169.1.1") assert target.name == "192.169.1.1" with pytest.raises(AssertionError): assert Target("192.168.1.1") assert Target("10.0.0.0.1") assert Target("172.16.0.0.1")
def queue(self, event, context): # print("Event: {}, context: {}".format(event, context.invoked_function_arn)) source_event = Event(event, context) data = source_event.parse() if data: target = Target(data.get('target')) if not target: self.logger.error("Target validation failed of: {}".format(target.name)) return Response({ "statusCode": 400, "body": json.dumps({'error': 'Target was not valid or missing'}) }).with_security_headers() scan_uuid = str(uuid.uuid4()) self.sqs_client.send_message( QueueUrl=self.queueURL, MessageBody="portscan|" + target.name + "|" + scan_uuid ) # Use a UUID for the scan type and return it return Response({ "statusCode": 200, "body": json.dumps({'uuid': scan_uuid}) }).with_security_headers() else: self.logger.error("Unrecognized payload: {}".format(data)) return Response({ "statusCode": 400, "body": json.dumps({'error': 'Unrecognized payload'}) }).with_security_headers()
def formatForSNS(self, event, context): # This is a step function called from a state machine # Event type will always be "step-function" source_event = Event(event, context) data = source_event.parse() if data: target = Target(data.get('target')) if not target: self.logger.error("Target validation failed of: {}".format( target.name)) return False # Extract the dictionary here and signed URL output_tracker = event['responses']['Generatedownloadlink'][ 'output'] signed_url = event['responses']['Generatedownloadlink']['url'] contents = (target.name, output_tracker, signed_url) formatter = Formatter(self.logger) subject, body = formatter.formatForEmail(contents) return {'subject': subject, 'body': body} else: self.logger.error("Unrecognized payload: {}".format(data)) return False
def generateDownloadLink(self, event, context): # This is a step function called from a state machine # Event type will always be "step-function" source_event = Event(event, context) data = source_event.parse() if data: target = Target(data.get('target')) if not target: self.logger.error("Target validation failed of: {}".format( target.name)) return False results = Results(target.name, self.s3_client, self.bucket, self.base_results_path) status, output, download_url = results.generateURL() if download_url: return { 'status': status, 'output': output, 'url': download_url } else: if status == 404: message = 'No results found for target' else: message = 'Unknown error' return {'status': status, 'message': message} else: self.logger.error("Unrecognized payload: {}".format(data)) return False
def pollScanResults(self, event, context): # This function will take a Tenable.io scan ID, and # query Tenable.io API for the status of that scan, and # if completed, return the results a JSON object source_event = Event(event, context) data = source_event.parse() if data: target = Target(data.get('target')) if not target: self.logger.error("Target validation failed of: {}".format( target.name)) return False scanID = event['responses']['Tenablescan']['id'] scanner = TIOScanner(logger=self.logger) json_result = scanner.scanResult(scanID, result_format="json") html_result = scanner.scanResult(scanID, result_format="html") if json_result and html_result: send_to_s3(target.name + "_tenablescan", json_result, client=self.s3_client, bucket=self.s3_bucket) send_to_s3(target.name + "_tenablescan", html_result, client=self.s3_client, bucket=self.s3_bucket) return {'statusCode': 200} else: self.logger.error("Unrecognized payload: {}".format(data)) return False
def downloadResults(self, event, context): # This is a lambda function called from API GW # Event type will always be "api-gw" source_event = Event(event, context) data = source_event.parse() if data: target = Target(data.get('target')) if not target: self.logger.error("Target validation failed of: {}".format( target.name)) return Response({ "statusCode": 400, "body": json.dumps({'error': 'Target was not valid or missing'}) }).with_security_headers() results = Results(target.name, self.s3_client, self.bucket, self.base_results_path) # Always use the download route scan_results, status = results.download() if scan_results: return Response({ "statusCode": status, "headers": { "Content-Type": "application/gzip", "Content-Disposition": "attachment; filename={}.tgz".format(target.name) }, "body": base64.b64encode(scan_results.getvalue()).decode("utf-8"), "isBase64Encoded": True }).with_security_headers() else: if status == 404: resp_body = 'No results found for target' elif status == 500: resp_body = 'Unable to download scan results' else: resp_body = 'Unknown error' return Response({ "statusCode": status, "body": json.dumps({'error': resp_body}) }).with_security_headers() else: self.logger.error("Unrecognized payload: {}".format(data)) return Response({ "statusCode": 400, "body": json.dumps({'error': 'Unrecognized payload'}) }).with_security_headers()
def putInQueue(event, context): # For demo purposes, this function is invoked manually # Also for demo purposes, we will use a static list here # We need to figure out a way to put stuff in the queue regularly target_list = [ "www.mozilla.org", "infosec.mozilla.org", ] hosts = Hosts(target_list) target = Target(hosts.next()) SQS_CLIENT.send_message(QueueUrl=os.getenv('SQS_URL'), MessageBody="manual|" + target.name)
def read_and_process_image(self, stream): start_time = time.time() original_img = stream.read() if original_img is None: return None filter = (60, 87, 120, 255, 50, 255) img = filters.apply_hsv_filter(original_img, filter) img = filters.erode(img, 1) img = filters.dilate(img, 1) target = Target(self.robot, img, original_img, self) target.acquire_target() if target.acquired == False: self.comms.send_no_target_message(start_time) else: self.comms.send_target_info_message(target, start_time) if self.width != self.output_width or self.height != self.output_height: target.annotated_image = cv2.resize( target.annotated_image, (self.output_width, self.output_height)) return target.annotated_image
def runFromStepFunction(self, event, context): source_event = Event(event, context) data = source_event.parse() if data: target = Target(data.get('target')) if not target: self.logger.error("Target validation failed of: {}".format( target.name)) return False # Run the scan here and return the ScanRef object scanner = TIOScanner(logger=self.logger) scanner_ref = scanner.scan(target.name) if scanner_ref: scanner_ref.launch(wait=False) return {'id': scanner_ref.id} else: return False else: self.logger.error("Unrecognized payload: {}".format(data)) return False
def test_assert_valid_function_call(call, result): assert Target.assert_valid_function_call(call) == result
def test_parse_func_call(func_call, func_name, func_args): name, args = Target._parse_func_call(func_call) assert name == func_name assert args == func_args
def test_parse_port(): port = Target._parse_port('abc:123') assert port == 123
def getResults(self, event, context): # print("Event: {}, context: {}".format(event, context)) source_event = Event(event, context) data = source_event.parse() print(source_event.type) if data: target = Target(data.get('target')) if not target: self.logger.error("Target validation failed of: {}".format( target.name)) return Response({ "statusCode": 400, "body": json.dumps({'error': 'Target was not valid or missing'}) }).with_security_headers() results = Results(target.name, self.s3_client, self.bucket, self.base_results_path) if source_event.type == "step-function": # Use generateURL route download_url, status = results.generateDownloadURL() if download_url: return Response({ "statusCode": status, "body": json.dumps({'url': download_url}) }).with_security_headers() else: if status == 404: resp_body = 'No results found for target' else: resp_body = 'Unknown error' return Response({ "statusCode": status, "body": json.dumps({'error': resp_body}) }).with_security_headers() else: # Use download route scan_results, status = results.download() if scan_results: return Response({ "statusCode": status, "headers": { "Content-Type": "application/gzip", "Content-Disposition": "attachment; filename={}.tgz".format(target.name) }, "body": base64.b64encode( scan_results.getvalue()).decode("utf-8"), "isBase64Encoded": True }).with_security_headers() else: if status == 404: resp_body = 'No results found for target' elif status == 500: resp_body = 'Unable to download scan results' else: resp_body = 'Unknown error' return Response({ "statusCode": status, "body": json.dumps({'error': resp_body}) }).with_security_headers() else: self.logger.error("Unrecognized payload: {}".format(data)) return Response({ "statusCode": 400, "body": json.dumps({'error': 'Unrecognized payload'}) }).with_security_headers()
sys.exit(-1) # Establish a session with that profile session = boto3.Session(profile_name=AWS_PROFILE) # Programmatically obtain the API GW URL, and the REST API key apigw_client = session.client('apigateway') aws_response = apigw_client.get_api_keys( nameQuery='vautomator-serverless', includeValues=True)['items'][0] rest_api_id, stage_name = "".join(aws_response['stageKeys']).split('/') gwapi_key = aws_response['value'] API_GW_URL = "https://{}.execute-api.{}.amazonaws.com/".format(rest_api_id, session.region_name) fqdn = input("Provide the FQDN (Fully Qualified Domain Name) you want to scan: ") try: target = Target(fqdn) except AssertionError: logging.error("Target validation failed: target must be an FQDN or IPv4 only.") sys.exit(-2) portscan_url = API_GW_URL + "{}/ondemand/portscan".format(stage_name) httpobs_scan_url = API_GW_URL + "{}/ondemand/httpobservatory".format(stage_name) tlsobs_scan_url = API_GW_URL + "{}/ondemand/tlsobservatory".format(stage_name) sshobs_scan_url = API_GW_URL + "{}/ondemand/sshobservatory".format(stage_name) tenableio_scan_url = API_GW_URL + "{}/ondemand/tenablescan".format(stage_name) direnum_scan_url = API_GW_URL + "{}/ondemand/direnum".format(stage_name) websearch_url = API_GW_URL + "{}/ondemand/websearch".format(stage_name) scan_types = { 'port': portscan_url, 'httpobservatory': httpobs_scan_url,
stats[hop]['total'] += 1 stats[hop]['skipped'] += len(cands) == 0 return stats if __name__ == '__main__': H = range(1, 7) network = Network('./data/dataset_1000a.txt') isolated_nodes = [n for n, d in network.graph.degree() if d == 1] edges = [edge for edge in network.edges if edge[0] not in isolated_nodes and edge[1] not in isolated_nodes] num_targets = math.ceil(len(edges)/2) num_attackers = math.ceil(len(network.nodes)/2) targets = [Target(edge, network.graph, H) for edge in tqdm(random.sample(edges, num_targets))] attackers = random.sample(network.nodes, num_attackers) with Pool() as p: stats = p.map(attack, [(target, attackers) for target in targets]) stats_h = {h: reduce(lambda x, y: Counter(x, **y), [stat[h] for stat in stats]) for h in H} for h, stat in stats_h.items(): print(f'Hop: {h}, Total: {stat["total"]}, Passed: {stat["passed"]}, Ratio: {stat["total"] and stat["passed"]/stat["total"]}') with open('stats.pkl', 'wb') as f: pickle.dump(stats_h, f)
parser.add_argument("-x", "--extract", help="Auto extract results", action="store_true") parser.add_argument("--results", help="Specify a results directory", default=os.path.join(os.getcwd(), "results/")) args = parser.parse_args() # Establish a session with that profile if given session = boto3.Session(profile_name=args.profile, region_name=args.region) # Programmatically obtain the REST API key apigw_client = session.client("apigateway") aws_response = apigw_client.get_api_keys(nameQuery="vautomator-serverless", includeValues=True)["items"][0] rest_api_id, stage_name = "".join(aws_response["stageKeys"]).split("/") gwapi_key = aws_response["value"] # We are now using a custom domain to host the API custom_domain = "vautomator.security.allizom.org" try: target = Target(args.fqdn) except AssertionError: logging.error("Target validation failed: target must be an FQDN or IPv4 only.") sys.exit(127) download_url = "https://{}".format(custom_domain) + "/api/results" session = requests.Session() session.headers.update({"X-Api-Key": gwapi_key, "Accept": "application/gzip", "Content-Type": "application/json"}) logging.info("Sending POST to {}".format(download_url)) response = session.post(download_url, data='{"target":"' + target.name + '"}', stream=True) if ( response.status_code == 200 or response.status_code == 202 and response.headers["Content-Type"] == "application/gzip" ):
def _start_debug_session_wrapper(self, *args): func_call = args[0] target = Target(self.database.dsn) proxy = Proxy(self.database.dsn) self._start_debug_session(func_call, target, proxy)