def scan(scan_id): try: # # See if the scan exists. # scan = get_scan(cfg['api']['url'], scan_id) if not scan: logger.error("Cannot load scan %s" % scan_id) return # # Is the scan in the right state to be started? # if scan['state'] != 'QUEUED': logger.error("Scan %s has invalid state. Expected QUEUED but got %s" % (scan_id, scan['state'])) return # # Move the scan to the STARTED state # scan['state'] = 'STARTED' send_task("minion.backend.tasks.scan_start", [scan_id, time.time()], queue='state').get() # # Check this site against the access control lists # if not scannable(scan['configuration']['target'], scan_config().get('whitelist', []), scan_config().get('blacklist', [])): failure = {"hostname": socket.gethostname(), "reason": "target-blacklisted", "message": "The target cannot be scanned by Minion because its (IPv4) address has been blacklisted."} return set_finished(scan_id, 'ABORTED', failure=failure) # # Verify ownership prior to running scan # target = scan['configuration']['target'] site = get_site_info(cfg['api']['url'], target) if not site: return set_finished(scan_id, 'ABORTED') if site.get('verification') and site['verification']['enabled']: verified = ownership.verify(target, site['verification']['value']) if not verified: failure = {"hostname": socket.gethostname(), "reason": "target-ownership-verification-failed", "message": "The target cannot be scanned because the ownership verification failed."} return set_finished(scan_id, 'ABORTED', failure=failure) # # Run each plugin session # for session in scan['sessions']: # # Mark the session as QUEUED # session['state'] = 'QUEUED' #scans.update({"id": scan['id'], "sessions.id": session['id']}, {"$set": {"sessions.$.state": "QUEUED", "sessions.$.queued": datetime.datetime.utcnow()}}) send_task("minion.backend.tasks.session_queue", [scan['id'], session['id'], time.time()], queue='state').get() # # Execute the plugin. The plugin worker will set the session state and issues. # logger.info("Scan %s running plugin %s" % (scan['id'], session['plugin']['class'])) queue = queue_for_session(session, cfg) result = send_task("minion.backend.tasks.run_plugin", [scan_id, session['id']], queue=queue) #scans.update({"id": scan_id, "sessions.id": session['id']}, {"$set": {"sessions.$._task": result.id}}) send_task("minion.backend.tasks.session_set_task_id", [scan_id, session['id'], result.id], queue='state').get() try: plugin_result = result.get() except TaskRevokedError as e: plugin_result = "STOPPED" session['state'] = plugin_result # # If the user stopped the workflow or if the plugin aborted then stop the whole scan # if plugin_result in ('ABORTED', 'STOPPED'): # Mark the scan as failed #scans.update({"id": scan_id}, {"$set": {"state": plugin_result, "finished": datetime.datetime.utcnow()}}) send_task("minion.backend.tasks.scan_finish", [scan_id, plugin_result, time.time()], queue='state').get() # Mark all remaining sessions as cancelled for s in scan['sessions']: if s['state'] == 'CREATED': s['state'] = 'CANCELLED' #scans.update({"id": scan['id'], "sessions.id": s['id']}, {"$set": {"sessions.$.state": "CANCELLED", "sessions.$.finished": datetime.datetime.utcnow()}}) send_task("minion.backend.tasks.session_finish", [scan['id'], s['id'], "CANCELLED", time.time()], queue='state').get() # We are done with this scan return # # Move the scan to the FINISHED state # scan['state'] = 'FINISHED' #scans.update({"id": scan_id}, {"$set": {"state": "FINISHED", "finished": datetime.datetime.utcnow()}}) send_task("minion.backend.tasks.scan_finish", [scan_id, "FINISHED", time.time()], queue='state').get() except Exception as e: # # Our exception strategy is simple: if anything was thrown above that we did not explicitly catch then # we assume there was a non recoverable error that made the scan fail. We mark it as such and # record the exception. # logger.exception("Error while running scan. Marking scan FAILED.") try: failure = { "hostname": socket.gethostname(), "reason": "backend-exception", "message": str(e), "exception": traceback.format_exc() } send_task("minion.backend.tasks.scan_finish", [scan_id, "FAILED", time.time(), failure], queue='state').get() except Exception as e: logger.exception("Error when marking scan as FAILED")
def scan(scan_id): try: # # See if the scan exists. # scan = get_scan(cfg['api']['url'], scan_id) if not scan: logger.error("Cannot load scan %s" % scan_id) return # # Is the scan in the right state to be started? # if scan['state'] != 'QUEUED': logger.error( "Scan %s has invalid state. Expected QUEUED but got %s" % (scan_id, scan['state'])) return # # Move the scan to the STARTED state # scan['state'] = 'STARTED' send_task("minion.backend.tasks.scan_start", [scan_id, time.time()], queue='state').get() # # Check this site against the access control lists # if not scannable(scan['configuration']['target'], scan_config().get('whitelist', []), scan_config().get('blacklist', [])): failure = { "hostname": socket.gethostname(), "reason": "target-blacklisted", "message": "The target cannot be scanned by Minion because its IP address or hostname has been blacklisted." } return set_finished(scan_id, 'ABORTED', failure=failure) # # Verify ownership prior to running scan # target = scan['configuration']['target'] site = get_site_info(cfg['api']['url'], target) if not site: return set_finished(scan_id, 'ABORTED') if site.get('verification') and site['verification']['enabled']: verified = ownership.verify(target, site['verification']['value']) if not verified: failure = { "hostname": socket.gethostname(), "reason": "target-ownership-verification-failed", "message": "The target cannot be scanned because the ownership verification failed." } return set_finished(scan_id, 'ABORTED', failure=failure) # # Run each plugin session # for session in scan['sessions']: # # Mark the session as QUEUED # session['state'] = 'QUEUED' #scans.update({"id": scan['id'], "sessions.id": session['id']}, {"$set": {"sessions.$.state": "QUEUED", "sessions.$.queued": datetime.datetime.utcnow()}}) send_task("minion.backend.tasks.session_queue", [scan['id'], session['id'], time.time()], queue='state').get() # # Execute the plugin. The plugin worker will set the session state and issues. # logger.info("Scan %s running plugin %s" % (scan['id'], session['plugin']['class'])) queue = queue_for_session(session, cfg) result = send_task("minion.backend.tasks.run_plugin", [scan_id, session['id']], queue=queue) #scans.update({"id": scan_id, "sessions.id": session['id']}, {"$set": {"sessions.$._task": result.id}}) send_task("minion.backend.tasks.session_set_task_id", [scan_id, session['id'], result.id], queue='state').get() try: plugin_result = result.get() except TaskRevokedError as e: plugin_result = "STOPPED" session['state'] = plugin_result # # If the user stopped the workflow or if the plugin aborted then stop the whole scan # if plugin_result in ('ABORTED', 'STOPPED'): # Mark the scan as failed #scans.update({"id": scan_id}, {"$set": {"state": plugin_result, "finished": datetime.datetime.utcnow()}}) send_task("minion.backend.tasks.scan_finish", [scan_id, plugin_result, time.time()], queue='state').get() # Mark all remaining sessions as cancelled for s in scan['sessions']: if s['state'] == 'CREATED': s['state'] = 'CANCELLED' #scans.update({"id": scan['id'], "sessions.id": s['id']}, {"$set": {"sessions.$.state": "CANCELLED", "sessions.$.finished": datetime.datetime.utcnow()}}) send_task( "minion.backend.tasks.session_finish", [scan['id'], s['id'], "CANCELLED", time.time()], queue='state').get() # We are done with this scan return # # Move the scan to the FINISHED state # scan['state'] = 'FINISHED' # # If one of the plugin has failed then marked the scan as failed # for session in scan['sessions']: if session['state'] == 'FAILED': scan['state'] = 'FAILED' #scans.update({"id": scan_id}, {"$set": {"state": "FINISHED", "finished": datetime.datetime.utcnow()}}) send_task("minion.backend.tasks.scan_finish", [scan_id, scan['state'], time.time()], queue='state').get() except Exception as e: # # Our exception strategy is simple: if anything was thrown above that we did not explicitly catch then # we assume there was a non recoverable error that made the scan fail. We mark it as such and # record the exception. # logger.exception("Error while running scan. Marking scan FAILED.") try: failure = { "hostname": socket.gethostname(), "reason": "backend-exception", "message": str(e), "exception": traceback.format_exc() } send_task( "minion.backend.tasks.scan_finish", [scan_id, "FAILED", time.time(), failure], queue='state').get() except Exception as e: logger.exception("Error when marking scan as FAILED")
def test_regular_targets(self): for target in self.regular_targets: self.assertTrue(scannable(target, self.whitelist, self.blacklist), "Target is " + target)
def test_blacklisted_targets(self): for target in self.blacklisted_targets: self.assertFalse(scannable(target, self.whitelist, self.blacklist), "Target is " + target)