#!/usr/bin/env ruby # frozen_string_literal: true require 'pwn' require 'optparse' require 'yaml' opts = {} OptionParser.new do |options| options.banner = "USAGE: #{$PROGRAM_NAME} [opts] " options.on('-cYPATH', '--yaml-config=YPATH', '') do |c| opts[:yaml_config] = c end options.on('-nNAME', '--scan-name=NAME', '') do |n| opts[:scan_name] = n end options.on('-TTARGETS', '--text-targets=TARGETS', '') do |t| opts[:text_targets] = t end options.on('-dDESC', '--scan-description=DESC', '') do |d| opts[:scan_desc] = d end options.on('-eEMAILS', '--emails=EMAILS', '') do |e| opts[:emails] = e end options.on('-tVALUE', '--scan-template=VALUE', '') do |t| opts[:scan_template_name] = t end options.on('-pPOLICY', '--policy-name=POLICY', '') do |p| opts[:policy_name] = p end options.on('-fFOLDER', '--folder-name=FOLDER', '') do |f| opts[:folder_name] = f end options.on('-sSCANNER', '--scanner-name=SCANNER', '') do |s| opts[:scanner_name] = s end options.on('-D', '--disable-scan', '') do |d| opts[:disabled] = d end options.on('-NTARGET', '--target-network-name=TARGET', '') do |n| opts[:target_network_name] = n end options.on('-lWHEN', '--launch=WHEN', '') do |l| opts[:launch] = l end options.on('-wTIMEWINDOW', '--scan-time-window=TIMEWINDOW', '') do |t| opts[:scan_time_window] = t end options.on('-STIME', '--start-time=TIME', '') do |t| opts[:starttime] = t end options.on('-rRRULES', '--rrules=RRULES', '') do |r| opts[:rrules] = r end options.on('-xTAGS', '--tag-targets=TAGS', '') do |x| opts[:tag_targets] = x end options.on('-yCATEGORY', '--tag-category-name=CATEGORY', '') do |y| opts[:tag_category_name] = y end options.on('-zTIMEZONE', '--timezone=TIMEZONE', '') do |t| opts[:timezone] = t end options.on('-gGROUPS', '--target-groups=GROUPS', '') do |t| opts[:timezone] = t end end.parse! if opts.empty? puts `#{$PROGRAM_NAME} --help` exit 1 end begin # Get Options Passed to pwn_nessus_cloud_create_scan # Required Arguments yaml_config = opts[:yaml_config] raise "YAML Config Not Found: #{yaml_config}" unless File.exist?(yaml_config) yaml = YAML.load_file( yaml_config, symbolize_names: true ) access_key = yaml[:access_key] secret_key = yaml[:secret_key] scan_name = opts[:scan_name] text_targets = opts[:text_targets] raise 'ERROR: --text-targets (i.e. List of targets to scan) is required.' unless text_targets # Optional Arguments scan_desc = opts[:scan_desc] scan_template_name = opts[:scan_template_name] scan_template_name ||= 'Basic Network Scan' policy_name = opts[:policy_name] policy_name ||= '' folder_name = opts[:folder_name] folder_name ||= 'My Scans' scanner_name = opts[:scanner_name] scanner_name ||= 'AUTO-ROUTED' target_network_name = opts[:target_network_name] target_network_name ||= 'Default' disabled = true if opts[:disabled] disabled ||= false enabled = true enabled = false if disabled launch = opts[:launch] launch ||= 'ON_DEMAND' scan_time_window = opts[:scan_time_window].to_i scan_time_window ||= 0 starttime = opts[:starttime] starttime ||= Time.now.strftime('%Y%m%dT%H%M%S') rrules = opts[:rrules] rrules ||= 'FREQ=null;INTERVAL=0;BYDAY=null' timezone = opts[:timezone] timezone ||= 'UTC' target_groups = opts[:target_groups] file_targets = opts[:file_targets] tag_targets = opts[:tag_targets] tag_targets_arr = [] tag_targets_arr = tag_targets.split(',') if tag_targets tag_category_name = opts[:tag_category_name] raise 'ERROR: --tag-category-name Required as --tag-targets is Populated' if tag_targets && !tag_category_name agent_group_name = opts[:agent_group_name] agent_group_id_arr = [] agent_scan_launch_type = opts[:agent_scan_launch_type] agent_scan_launch_type ||= 'triggered' triggers_arr = [] triggers = {} triggers[:type] = agent_scan_launch_type triggers[:type] ||= 'periodic' triggers[:options] = {} case agent_scan_launch_type when 'periodic' triggers[:options][:periodic_hourly_interval] = opts[:periodic_hourly_interval] triggers[:options][:periodic_hourly_interval] ||= 0 when 'file-exists' triggers[:options][:filename] = opts[:filename] end triggers_arr.push(triggers) emails = opts[:emails] acls = {} acls[:permissions] = opts[:acl_permissions] acls[:owner] = opts[:acl_owner] acls[:display_name] = opts[:acl_display_name] acls[:name] = opts[:acl_name] acls[:id] = opts[:acl_id] acls[:type] = opts[:acl_type] credential_category = opts[:credential_category] credential_type = opts[:credential_type] # Begin Here nessus_obj = PWN::Plugins::NessusCloud.login( access_key: access_key, secret_key: secret_key ) # Requirements to update / create a scan: # Part 1: Populate uuid # Part 2: Populate settings object from options passed to driver # Part 3: Populate credentials object from YAML config (optional) # Part 4: Populate plugins object from YAML config (optional) # Part 5: Update Scan if it exists, or create it. # Part 1: Populate uuid # TODO: add --list-canned-scan-templates option scan_template = PWN::Plugins::NessusCloud.get_canned_scan_templates( nessus_obj: nessus_obj, name: scan_template_name ) scan_template_uuid = scan_template[:uuid] # Part 2: Populate settings object from options passed to driver settings = {} settings[:name] = scan_name settings[:description] = scan_desc if scan_desc policy = PWN::Plugins::NessusCloud.get_policies( nessus_obj: nessus_obj, name: policy_name ) settings[:policy_id] = policy[:id] folder = PWN::Plugins::NessusCloud.get_folders( nessus_obj: nessus_obj, name: folder_name ) settings[:folder_id] = folder[:id] scanner = PWN::Plugins::NessusCloud.get_scanners( nessus_obj: nessus_obj, name: scanner_name ) settings[:scanner_id] = scanner[:id] target_network = PWN::Plugins::NessusCloud.get_target_networks( nessus_obj: nessus_obj, name: target_network_name ) settings[:target_network_uuid] = target_network[:uuid] settings[:enabled] = enabled settings[:launch] = launch settings[:scan_time_window] = scan_time_window settings[:starttime] = starttime settings[:rrules] = rrules settings[:timezone] = timezone settings[:text_targets] = text_targets # Example array on https://developer.tenable.com/reference/scans-create is really just a string. settings[:target_groups] = "[#{target_groups}]" if target_groups settings[:file_targets] = file_targets if file_targets if tag_targets_arr.any? tag_uuids_arr = [] tag_targets_arr.each do |tag_name| # Lookup tag and create if does not exist tag = PWN::Plugins::NessusCloud.get_tag_values( nessus_obj: nessus_obj, name: tag_name ) tag_uuid = tag[:uuid] if tag.any? tag_uuids_arr.push(tag_uuid) if tag.any? next if tag.any? new_tag = PWN::Plugins::NessusCloud.create_tag( nessus_obj: nessus_obj, category: tag_category_name, value: tag_name ) tag_uuid = new_tag[:uuid] tag_uuids_arr.push(tag_uuid) end settings[:tag_targets] = tag_uuids_arr end settings[:agent_group_id] = agent_group_id_arr if agent_group_id_arr.any? settings[:agent_scan_launch_type] = agent_scan_launch_type if agent_scan_launch_type settings[:triggers] = triggers_arr if triggers_arr.any? settings[:emails] = emails if emails # settings[:acls] = acls if acls # Part 3: Populate credentials object from YAML config (optional) credentials = yaml[:credentials] if yaml[:credentials] # Part 4: Populate plugins object from YAML config (optional) plugins = yaml[:plugins] if yaml[:plugins] # Part 5: Update Scan if it exists, or create it. scan = PWN::Plugins::NessusCloud.get_scans( nessus_obj: nessus_obj, name: scan_name ) if scan.any? scan_id = scan[:id] update_scan_resp = PWN::Plugins::NessusCloud.update_scan( nessus_obj: nessus_obj, scan_id: scan_id, scan_template_uuid: scan_template_uuid, settings: settings, credentials: credentials, plugins: plugins ) puts update_scan_resp.inspect else create_scan_resp = PWN::Plugins::NessusCloud.create_scan( nessus_obj: nessus_obj, scan_template_uuid: scan_template_uuid, settings: settings, credentials: credentials, plugins: plugins ) puts create_scan_resp.inspect end rescue Interrupt puts 'CTRL+C detected...goodbye.' rescue StandardError => e raise e end