def test_zap(zapconfig): parser = SafeConfigParser() parser.read(zapconfig) zapUrl = parser.get("Proxy", "url") zap = ZAP(proxies={'http': zapUrl, 'https': zapUrl}) if (parser.getboolean("Actions", "start")): # print "platform=" + platform.system() if (platform.system() == "Windows"): zapScript = "start /b zap.bat" else: zapScript = "zap.sh" zapInstall = parser.get("Proxy", "install") if (len(zapInstall) == 0): if (platform.system() == "Windows"): # Win 7 default path zapInstall = "C:\Program Files (x86)\OWASP\Zed Attack Proxy" if (not os.path.exists(zapInstall)): # Win XP default path zapInstall = "C:\Program Files\OWASP\Zed Attack Proxy" else: # No default path for Mac OS or Linux print "Installation directory must be set in " + zapconfig if (len(parser.get("Proxy", "home")) > 0): zapScript = zapScript + " -d " + parser.get("Proxy", "home") os.chdir(zapInstall) os.system(zapScript) time.sleep(20) spiderUrls = parser.get("Actions", "spider") if (len(spiderUrls) > 0): for spiderUrl in spiderUrls.split(','): zap.urlopen(spiderUrl) # Give the sites tree a chance to get updated time.sleep(2) print 'Spidering %s' % spiderUrl zap.start_spider(spiderUrl) # Give the Spider a chance to start time.sleep(2) while (int(zap.spider_status[0]) < 100): #print 'Spider progress %: ' + zap.spider_status[0] time.sleep(5) print 'Finished spidering %s' % spiderUrl print 'Spider completed' # Give the passive scanner a chance to finish time.sleep(5) scanUrls = parser.get("Actions", "scan") if (len(scanUrls) > 0): for scanUrl in scanUrls.split(','): print 'Scanning %s' % scanUrl zap.start_scan(scanUrl) while (int(zap.scan_status[0]) < 100): #print 'Scan progress %: ' + zap.scan_status[0] time.sleep(5) print 'Finished scanning %s' % scanUrl print 'Scanner completed' saveSession = parser.get("Actions", "savesession") if (len(saveSession) > 0): time.sleep(5) # Will this help?? zap.save_session(saveSession) #zapAlerts = zap.alerts # Save for later, in case ZAP is stopped.. zapAlerts = copy.deepcopy( zap.alerts) # Save for later, in case ZAP is stopped.. if (parser.getboolean("Actions", "stop")): # TODO: this is causing problems right now :( zap.shutdown() requireAlertsStr = parser.get("Alerts", "require") if (len(requireAlertsStr) > 0): for requireAlertStr in requireAlertsStr.split("\n"): requireAlert = ast.literal_eval(requireAlertStr) # Check at least one match found in the alerts found = False for alert in zapAlerts: if (match_alerts(alert, requireAlert)): found = True break if (not found): # No match, fail the test print "Required alert not present: " + requireAlertStr assert 0 ignoreAlertsStr = parser.get("Alerts", "ignore") ignoreAlerts = [] if (len(ignoreAlertsStr) > 0): for ignoreAlertStr in ignoreAlertsStr.split("\n"): ignoreAlerts.append(ast.literal_eval(ignoreAlertStr)) strippedAlerts = strip_alerts(zapAlerts, ignoreAlerts) saveAlerts = parser.get("Alerts", "savealerts") if (len(saveAlerts) > 0): alertsFile = open(saveAlerts, 'w') for alert in strippedAlerts: alertsFile.write(alert_to_str(alert)) alertsFile.write("\n") alertsFile.close() assert len(strippedAlerts) == 0
['Check.Pasv.Cookie.Secure.php', 'InsecureCookie', 'pass'],\ ['Check.Pasv.CrossDomain.ScriptReference.php', 'CrossJS', 'pass'], \ ['Check.Pasv.Header.ContentTypeMissing.php', 'XContent', 'pass'], \ ['Check.Pasv.Header.FrameOptions.php', 'XFrame', 'pass'],\ ['Check.Pasv.Header.IeXssProtection.php', 'IE8XSSfilter ', 'pass'], \ ['Check.Pasv.Header.CacheControl.php', 'CacheControl', 'pass'], \ ['Check.Pasv.Header.MimeSniff.php', 'NoContentHeader', 'pass'],\ ['Check.Pasv.Header.WeakAuth.php', 'WeakAuth', 'pass'], \ ['Check.Pasv.InformationDisclosure.Comments.php', 'InfoComments', 'pass'], \ ['Check.Pasv.InformationDisclosure.DatabaseErrors.php', 'InfoDb', 'pass'], \ ['Check.Pasv.InformationDisclosure.DebugErrors.php', 'InfoDebug', 'pass'], \ ['Check.Pasv.InformationDisclosure.InUrl.php', 'InfoUrl', 'pass'], \ ['watcher/Check.Pasv.Cookie.Secure.php', 'InsecureCookie', 'pass'],\ ] zap = ZAP(proxies={'http': zapUrl, 'https': zapUrl}) alerts = zap.alerts uniqueUrls = set([]) # alertsPerUrl is a dictionary of urlsummary to a dictionary of type to set of alertshortnames ;) alertsPerUrl = {} plugins = set([]) for alert in alerts: url = alert.get('url') # Grab the url before any '?' url = url.split('?')[0] #print 'URL: ' + url urlEl = url.split('/') if (len(urlEl) > 4):
class ZapPlugin(MinionPlugin): zap = ZAP(proxies={'http': 'http://127.0.0.1:8090', 'https': 'http://127.0.0.1:8090'}) default = { "template" : { "target" : { "type" : "url", "is_list" : True, "required" : True} }, "safechecks" : { "type" : "bool", "value" : True} } def __init__(self): MinionPlugin.__init__(self, ZapPlugin.default) self.state = MinionPlugin.STATUS_PENDING self.messages = { "PENDING" : "Plugin is pending execution.", "WAITING" : "Execution is suspending, waiting for RESUME.", "RUNNING" : "Execution is in progress.", "COMPLETE" : "Execution is finished.", "CANCELLED" : "Execution was cancelled.", "FAILED" : "Execution failed." } self.allow_states = { MinionPlugin.STATUS_PENDING : [MinionPlugin.STATE_START], MinionPlugin.STATUS_WAITING : [MinionPlugin.STATE_RESUME, MinionPlugin.STATE_TERMINATE], MinionPlugin.STATUS_RUNNING : [MinionPlugin.STATE_SUSPEND, MinionPlugin.STATE_TERMINATE], MinionPlugin.STATUS_COMPLETE : [], MinionPlugin.STATUS_CANCELLED : [], MinionPlugin.STATUS_FAILED : [] } def do_validate(self, config): return True def do_validate_key(self, key, value): return True def do_status(self): return self.create_status(True, self.messages[self.state], self.state) def do_start(self): target = "http://localhost:8080/bodgeit/" print "ZapPlugin pre start" try: zct = ZapScanThread() zct.setZap(self.zap) zct.setTarget(target) zct.start() except Exception as e: print "ZapPlugin failed %s" % e print "ZapPlugin post start" self.state = MinionPlugin.STATUS_RUNNING #return self.create_status(True, self.messages[self.state], self.state) return self.create_std_status(True, self.state) def do_suspend(self): self.state = MinionPlugin.STATUS_WAITING return self.create_status(True, self.messages[self.state], self.state) def do_resume(self): self.state = MinionPlugin.STATUS_RUNNING return self.create_status(True, self.messages[self.state], self.state) def do_terminate(self): self.state = MinionPlugin.STATUS_CANCELLED return self.create_status(True, self.messages[self.state], self.state) def do_get_states(self): return self.allow_states[self.state]