def zap(config): if 'supervisor.sock no such file' in execute( 'supervisorctl restart zap')[0].decode('utf-8'): execute('/usr/bin/supervisord', communicate=False) status = execute('zap-cli status')[0].decode('utf-8') while 'ZAP is running' not in status: sleep(10) status = execute('zap-cli status')[0].decode('utf-8') if config.get('zap_context_file_path', None): context = os.path.join('/tmp', config.get('zap_context_file_path')) if os.path.exists(context): execute( f'zap-cli context import /tmp/{config.get("zap_context_file_path")}' ) execute( f'zap-cli quick-scan -s {config.get("scan_types", "xss,sqli")} {config.get("params", "")}' f' -c "{context}" -l Informational' f' {config.get("protocol")}://{config.get("host")}:{config.get("port")}' ) else: execute( f'zap-cli quick-scan -s {config.get("scan_types", "xss,sqli")} {config.get("params", "")}' f'-l Informational {config.get("protocol")}://{config.get("host")}:{config.get("port")}' ) execute('zap-cli report -o /tmp/zap.xml -f xml') result = ZapXmlParser('/tmp/zap.xml', "ZAP").items execute('supervisorctl stop zap') common_post_processing(config, result, "ZAP") return result
def nmap(config): excluded_addon = f'--exclude-ports {config.get("exclusions", None)}' if config.get( "exclusions", None) else "" ports = config.get("inclusions", "0-65535") nse_scripts = config.get( "nse_scripts", "ssl-date,http-mobileversion-checker,http-robots.txt,http-title," "http-waf-detect,http-chrono,http-headers,http-comments-displayer," "http-date") exec_cmd = f'nmap -PN -p{ports} {excluded_addon} ' \ f'--min-rate 1000 --max-retries 0 --max-rtt-timeout 200ms ' \ f'{config["host"]}' res = execute(exec_cmd) tcp_ports = '' udp_ports = '' for each in re.findall(r'([0-9]*/[tcp|udp])', str(res[0])): if '/t' in each: tcp_ports += f'{each.replace("/t", "")},' elif '/u' in each: udp_ports += f'{each.replace("/u", "")},' ports = f"-pT:{tcp_ports[:-1]}" if tcp_ports else "" ports += f" -pU:{udp_ports[:-1]}" if udp_ports else "" if not ports: return params = config.get("params", "-v -sVA") exec_cmd = f'nmap {params} {ports} ' \ f'--min-rate 1000 --max-retries 0 ' \ f'--script={nse_scripts} {config["host"]} -oX /tmp/nmap.xml' execute(exec_cmd) result = NmapXMLParser('/tmp/nmap.xml', "NMAP").items common_post_processing(config, result, "NMAP") return result
def python(config): exec_cmd = "bandit -r /code --format json" res = execute(exec_cmd, cwd='/code') with open("/tmp/bandit.json", "w") as f: f.write(res[0].decode('utf-8', errors='ignore')) result = BanditParser("/tmp/bandit.json", "pybandit").items common_post_processing(config, result, "pybandit") return result
def retirejs(config): devdeps = [] if config.get('devdep') \ else json.load(open('/code/package.json')).get('devDependencies', {}).keys() exec_cmd = "retire --jspath=/code --outputformat=json " \ "--outputpath=/tmp/retirejs.json --includemeta --exitwith=0" res = execute(exec_cmd, cwd='/tmp') result = RetireScanParser("/tmp/retirejs.json", "RetireScan", devdeps).items common_post_processing(config, result, "RetireScan") return result
def nikto(config): if os.path.exists("/tmp/nikto.xml"): os.remove("/tmp/nikto.xml") exec_cmd = f'perl nikto.pl {config.get("param", "")} -h {config["host"]} -p {config["port"]} ' \ f'-Format xml -output /tmp/nikto.xml -Save /tmp/extended_nikto' cwd = '/opt/nikto/program' execute(exec_cmd, cwd) result = NiktoXMLParser("/tmp/nikto.xml", "Nikto").items common_post_processing(config, result, "nikto") return result
def npm(config): devdeps = [] if config.get('devdep') \ else json.load(open('/code/package.json')).get('devDependencies', {}).keys() exec_cmd = "npm audit --json" res = execute(exec_cmd, cwd='/code') with open('/tmp/npm_audit.json', 'w') as npm_audit: print(res[0].decode(encoding='ascii', errors='ignore'), file=npm_audit) result = NpmScanParser("/tmp/npm_audit.json", "NpmScan", devdeps).items common_post_processing(config, result, "NpmScan") return result
def qualys(config): qualys_scanner_type = config.get("qualys_scanner_type", "EXTERNAL").upper() # TODO : think on optimization or unification of Qualys pools for Internal scanners qualys_scanner = config.get("qualys_scanner", '') qualys_scanners_pool = config.get("scanners_pool", '') if qualys_scanners_pool: qualys_scanners_pool = randrange(1, int(qualys_scanners_pool) + 1) # randrange specifics qualys_profile_id = config.get("qualys_profile_id", None) qualys_template_id = config.get("qualys_template_id", None) if not (qualys_profile_id or qualys_template_id): return [] project_name = config.get('project_name') target = f'{config.get("protocol")}://{config.get("host")}:{config.get("port")}' qualys = WAS() ts = datetime.utcfromtimestamp(int( time())).strftime('%Y-%m-%d %H:%M:%S') project_id = qualys.search_for_project(project_name) if qualys_scanner_type == 'INTERNAL': scanner_appliance = f"<type>{qualys_scanner_type}</type>" \ f"<friendlyName>{qualys_scanner}{qualys_scanners_pool}</friendlyName>" else: scanner_appliance = f"<type>{qualys_scanner_type}</type>" if not project_id: project_id = qualys.create_webapp_request(project_name, target, qualys_profile_id) if not project_id: print("Something went wrong and project wasn't found and created") return [] scan_id = qualys.start_scan(project_name, ts, project_id, qualys_profile_id, scanner_appliance) if not scan_id: print("Scan haven't been started") return [] while not qualys.scan_status(scan_id): sleep(30) # qualys.download_scan_report(scan_id) report_id = qualys.request_report(project_name, ts, scan_id, project_id, qualys_template_id) if not report_id: print("Request report failed") return [] while not qualys.get_report_status(report_id): sleep(30) qualys.download_report(report_id) qualys.delete_asset("report", report_id) qualys.delete_asset("wasscan", scan_id) qualys.delete_asset("webapp", project_id) result = QualysWebAppParser("/tmp/qualys.xml", "qualys_was").items common_post_processing(config, result, "qualys_was") return result
def ruby(config): included_checks = '' exclude_checks = '' if config.get('include_checks', None): included_checks = f'-t {config.get("include_checks")} ' if config.get('exclude_checks', None): exclude_checks = f'-x {config.get("exclude_checks")} ' if config.get('excluded_files', None): exclude_checks = f'--skip-files {config.get("excluded_files")} ' excluded_files = '' exec_cmd = f"brakeman {included_checks}{exclude_checks}--no-exit-on-warn --no-exit-on-error {excluded_files}" \ f"-o /tmp/brakeman.json /code" execute(exec_cmd, cwd='/code') result = BrakemanParser("/tmp/brakeman.json", "brakeman").items common_post_processing(config, result, "brakeman") return result
def w3af(config): config_file = config.get("config_file", "/tmp/w3af_full_audit.w3af") w3af_execution_command = f'w3af_console -y -n -s {config_file}' with open(config_file, 'r') as f: config_content = f.read() if '{target}' in config_content: config_content = config_content.format( target= f'{config.get("protocol")}://{config.get("host")}:{config.get("port")}', output_section=c.W3AF_OUTPUT_SECTION) with open(config_file, 'w') as f: f.write(config_content) execute(w3af_execution_command) result = W3AFXMLParser("/tmp/w3af.xml", "w3af").items common_post_processing(config, result, "w3af") return result
def masscan(config): host = config["host"] if not (find_ip(host)): host = find_ip(str(execute(f'getent hosts {host}')[0])) if len(host) > 0: host = host[0].strip() if host: if config.get("exclusions", None): excluded_addon = f'--exclude-ports {config.get("exclusions", None)}' else: excluded_addon = '' ports = config.get("inclusions", "0-65535") exec_cmd = f'masscan {host} -p {ports} -pU:{ports} --rate 1000 -oJ /tmp/masscan.json {excluded_addon}' execute(exec_cmd.strip()) result = MasscanJSONParser("/tmp/masscan.json", "masscan").items common_post_processing(config, result, "masscan") return result return []
def execute_parallel(scan_fns, config, language): all_results = [] params = [] for fn in scan_fns: params.append((fn, config)) results = run_in_parallel(params) for result in results: all_results.extend(result) filtered_result = common_post_processing(config, all_results, language) return filtered_result
def nodejs(config): exec_cmd = "nodejsscan -o nodejsscan -d /code" res = execute(exec_cmd, cwd='/tmp') result = NodeJsScanParser("/tmp/nodejsscan.json", "NodeJsScan").items common_post_processing(config, result, "NodeJsScan") return result
def java(config): exec_cmd = "spotbugs -xml:withMessages -output /tmp/spotbugs.xml /code" res = execute(exec_cmd, cwd='/code') result = SpotbugsParser("/tmp/spotbugs.xml", "spotbugs").items common_post_processing(config, result, "spotbugs") return result
def main(): args = parse_args() logging_level = logging.DEBUG if args.debug or os.environ.get( "debug", False) else logging.INFO logging.basicConfig( level=logging_level, datefmt='%Y.%m.%d %H:%M:%S', format='%(asctime)s - %(levelname)8s - %(message)s', ) logging.raiseExceptions = False # Disable requests/urllib3 logging logging.getLogger("requests").setLevel(logging.WARNING) logging.getLogger("urllib3").setLevel(logging.WARNING) # Disable qualysapi requests logging logging.getLogger("qualysapi.connector").setLevel(logging.WARNING) logging.getLogger("qualysapi.config").setLevel(logging.WARNING) logging.getLogger("qualysapi.util").setLevel(logging.WARNING) start_time = time() global_results = [] global_other_results = [] global_errors = dict() default_config, test_configs = config_from_yaml(args) # Enable Loki logging enable_loki_logging(default_config) for key in test_configs: results = [] other_results = [] config = test_configs[key] if key in constants.SASTY_SCANNERS_CONFIG_KEYS: if key == "scan_opts": continue attr_name = config[key] if 'language' in key else key try: results = getattr(SastyWrapper, attr_name)(config) except BaseException as e: logging.error("Exception during %s Scanning" % attr_name) global_errors[attr_name] = str(e) logging.debug(format_exc()) else: try: tool_name, result = getattr(DustyWrapper, key)(config) results, other_results = common_post_processing( config, result, tool_name, need_other_results=True, global_errors=global_errors) except BaseException as e: logging.error("Exception during %s Scanning" % key) global_errors[key] = str(e) logging.debug(format_exc()) if default_config.get('jira_service', None) and config.get('jira_service', None) \ and config.get('jira_service').valid: default_config['jira_service'].created_jira_tickets.extend( config.get('jira_service').get_created_tickets()) if default_config.get('generate_html', None) or default_config.get( 'generate_junit', None): global_results.extend(results) global_other_results.extend(other_results) process_results(default_config, start_time, global_results, other_results=global_other_results, global_errors=global_errors) flush_logs()
def sslyze(config): exec_cmd = f'sslyze --regular --json_out=/tmp/sslyze.json --quiet {config["host"]}:{config["port"]}' execute(exec_cmd) result = SslyzeJSONParser("/tmp/sslyze.json", "SSlyze").items common_post_processing(config, result, "SSlyze") return result