In meinem vorherigen Artikel zu OWASP Zap, ging es um die allgemeinen Informationen zu diesem Security Testing Tool. Ich habe es schon mehrfach in diversen Projekten eingesetzt und auch entsprechend in diversen CI Lösungen eingesetzt.
Da ich mir im Bereich Python + Selenium einiges angeeignet habe in den letzten Jahren, war auch mein erstes Ziel entsprechend OWASP Zap auch über eine Python zu Jenkins Pipeline zu arbeiten.
Um Owasp unter Python einzusetzen muss man das entsprechende Packet natürlich erstmal installieren. Ich gehe natürlich davon aus, dass ihr vorher schon Python Installiert habt. Wenn nicht, hier nochmal ein Tutorial was euch weiterhilft: https://www.python.org/downloads/
pip install python-owasp-zap-v2.4
OWASP Zap bietet über die Community auch direkte Beispiele an für Baseline Scanning u.a.
Anbei ein Beispiel für eine Python basierende API Spider:
#!/usr/bin/env python # A basic ZAP Python API example which spiders and scans a target URL import time from pprint import pprint from zapv2 import ZAPv2 ++ target = 'http://127.0.0.1' apikey = 'changeme' # Change to match the API key set in ZAP, or use None if the API key is disabled # # By default ZAP API client will connect to port 8080 zap = ZAPv2(apikey=apikey) # Use the line below if ZAP is not listening on port 8080, for example, if listening on port 8090 # zap = ZAPv2(apikey=apikey, proxies={'http': 'http://127.0.0.1:8090', 'https': 'http://127.0.0.1:8090'}) # Proxy a request to the target so that ZAP has something to deal with print('Accessing target {}'.format(target)) zap.urlopen(target) # Give the sites tree a chance to get updated time.sleep(2) print('Spidering target {}'.format(target)) scanid = zap.spider.scan(target) # Give the Spider a chance to start time.sleep(2) while (int(zap.spider.status(scanid)) < 100): # Loop until the spider has finished print('Spider progress %: {}'.format(zap.spider.status(scanid))) time.sleep(2) print ('Spider completed') while (int(zap.pscan.records_to_scan) > 0): print ('Records to passive scan : {}'.format(zap.pscan.records_to_scan)) time.sleep(2) print ('Passive Scan completed') print ('Active Scanning target {}'.format(target)) scanid = zap.ascan.scan(target) while (int(zap.ascan.status(scanid)) < 100): # Loop until the scanner has finished print ('Scan progress %: {}'.format(zap.ascan.status(scanid))) time.sleep(5) print ('Active Scan completed') # Report the results print ('Hosts: {}'.format(', '.join(zap.core.hosts))) print ('Alerts: ') pprint (zap.core.alerts())
Beispiel für einen passiven Angriff auf eine App
#!/usr/bin/env python import time from pprint import pprint from zapv2 import ZAPv2 apiKey = 'changeme' target = 'https://public-firing-range.appspot.com' zap = ZAPv2(apikey=apiKey, proxies={'http': 'http://127.0.0.1:8080', 'https': 'http://127.0.0.1:8080'}) # TODO : explore the app (Spider, etc) before using the Passive Scan API, Refer the explore section for details while int(zap.pscan.records_to_scan) > 0: # Loop until the passive scan has finished print('Records to passive scan : ' + zap.pscan.records_to_scan) time.sleep(2) print('Passive Scan completed') # Print Passive scan results/alerts print('Hosts: {}'.format(', '.join(zap.core.hosts))) print('Alerts: ') pprint(zap.core.alerts())
Ein weiteres Beispiel: Baseline Scanning
# Zed Attack Proxy (ZAP)nd its related class files. # # ZAP is an HTTP/HTTPS proxy for assessing web application security. # # Copyright 2012 ZAP Development Team # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This is a generic pytest (http://pytest.org/) script that can be used # for controlling and integrating ZAP with existing tests. # The script is configured via the config file (default name: test_zap.config) # the default file has plenty of comments to explain whats what. # You can use this script for a standalone security test - it can start ZAP, # run the spider and scanner against specified URLs, check for any alerts # raised and finally stop ZAP. # However its more effective if you start ZAP, then proxy existing functional # test via ZAP before running the spider and scanner. # That means you might need to start ZAP in one test, run your functional tests # and then run the spider and scanner, etc. in another (sequential) test. import ast import copy import os import platform import re import time from ConfigParser import SafeConfigParser from zap import ZAP def element_to_str(alert, element): return "'" + element + "':'" + re.escape(alert.get(element)) + "'" def alert_to_str(alert): return "{" + \ element_to_str(alert, "alert") + "," + \ element_to_str(alert, "risk") + "," + \ element_to_str(alert, "reliability") + "," + \ element_to_str(alert, "url") + "," + \ element_to_str(alert, "param") + "}" def match_alert_pattern (alert, pattern, element): #print "Alert = " + alert + " Pattern = " + pattern + " Element = " + element if (pattern.get(element)): return re.search(pattern.get(element), alert.get(element)) return True # No such pattern matches all def match_alerts (alert, pattern): if ( not match_alert_pattern (alert, pattern, "alert")): return False if ( not match_alert_pattern (alert, pattern, "url")): return False if ( not match_alert_pattern (alert, pattern, "reliability")): return False if ( not match_alert_pattern (alert, pattern, "risk")): return False if ( not match_alert_pattern (alert, pattern, "param")): return False return True # Returns a list of the alerts which dont match the 'ignoreAlerts' - a dictionary of regex patterns def strip_alerts (alerts, ignoreAlerts): stripped = [] for alert in alerts: include = True for ignore in ignoreAlerts: if ( match_alerts(alert, ignore)): include = False break if (include): stripped.append(alert) return stripped 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
Neueste Kommentare