module PWN::Plugins::IBMAppscan
def self.appscan_rest_call(opts = {})
def self.appscan_rest_call(opts = {}) :appscan_obj] ts[:http_method].nil? t s[:http_method].to_s.scrub.to_sym est_call].to_s.scrub ttp_body].to_s.scrub n_obj[:appscan_ip].to_s.scrub pscan_obj[:cookie] i = "https://#{appscan_ip}/ase/services".to_s.scrub Plugins::TransparentBrowser.open(browser_type: :rest) er_obj[:browser]::Request lient.execute( pscan_api_uri}/#{rest_call}", ie: appscan_cookie }, se lient.execute( pscan_api_uri}/#{rest_call}", ie: appscan_cookie }, ody, se rror("Unsupported HTTP Method #{http_method} for #{self} Plugin") => e 01 Unauthorized') && retry_count.positive? && appscan_obj[:logged_in] k in to refresh the connection t Response: #{e}...Attempting to Re-Authenticate; Retries left #{retry_count}") ogin( scan_obj[:appscan_ip], an_obj[:username], 4.decode64(appscan_obj[:password]) n_appscan_obj[:cookie] app obj over the old app obj key do |k| = n_appscan_obj[k]
def self.authors
def self.authors st.pentest@0dayinc.com>
def self.configure_scan_options(opts = {})
def self.configure_scan_options(opts = {}) [:appscan_obj] pts[:folder_item_id].to_i ion].to_s.scrub e] fStartingUrls .split(',').each_with_index do |url, index| &' unless index.zero? value=#{URI.encode_www_form(url.strip.chomp)}" hentication alue == false alue=0' # Don't require authentication alue=1' # Require authentication r, :esCOTHttpPassword, :elCOTScanLimit ue=#{value.to_s.scrub}" s = '' options( ppscan_obj, : folder_item_id { |url| available_options << "#{File.basename(url)}\n" } info("Valid Options are:\n\n#{available_options}") s = '' options( ppscan_obj, : folder_item_id { |url| available_options << "#{File.basename(url)}\n" } error("Invalid option '#{option}' parameter passed.\nValid Options are:\n\n#{available_options}") Existing Option Values _rest_call( scan_obj, st, eritems/#{folder_item_id}/options/#{option}?put=1", body.to_s esponse] = response esponse] = Nokogiri::XML(response) ns] = scan_config[:xml_response].xpath('//xmlns:option/@value') => e
def self.create_scan_based_on_template(opts = {})
def self.create_scan_based_on_template(opts = {}) [:appscan_obj] [:template_id].to_i scan_name].to_s.scrub scan_desc].to_s.scrub _rest_call( scan_obj, st, eritems?templateId=#{template_id}", =#{scan_name}&description=#{scan_desc}" o Use Data Structure ng it to the End User XML on their own. ] = response ] = Nokogiri::XML(response) = scan[:xml_response].xpath( tems/xmlns:content-scan-job/@href' id] = scan[:xml_response].xpath( tems/xmlns:content-scan-job/xmlns:id' scan[:xml_response].xpath( tems/xmlns:content-scan-job/xmlns:name' scan[:xml_response].xpath( tems/xmlns:content-scan-job/xmlns:description' r_url] = scan[:xml_response].xpath( tems/xmlns:content-scan-job/xmlns:parent/@href' r_id] = scan[:xml_response].xpath( tems/xmlns:content-scan-job/xmlns:parent/xmlns:id' can[:xml_response].xpath( tems/xmlns:content-scan-job/xmlns:contact' scan[:xml_response].xpath( tems/xmlns:content-scan-job/xmlns:state/xmlns:id' = scan[:xml_response].xpath( tems/xmlns:content-scan-job/xmlns:state/xmlns:name' scan[:xml_response].xpath( tems/xmlns:content-scan-job/xmlns:action/xmlns:id' = scan[:xml_response].xpath( tems/xmlns:content-scan-job/xmlns:action/xmlns:name' = scan[:xml_response].xpath( tems/xmlns:content-scan-job/xmlns:options/@href' url] = scan[:xml_response].xpath( tems/xmlns:report-pack/@href' id] = scan[:xml_response].xpath( tems/xmlns:report-pack/xmlns:id' = scan[:xml_response].xpath( tems/xmlns:report-pack/xmlns:reports/@href' t] = scan[:xml_response].xpath( tems/xmlns:report-pack/xmlns:reports/xmlns:count' => e ror #{e}:\nREST response returned:\n#{response}")
def self.folder_item_scan_action(opts = {})
def self.folder_item_scan_action(opts = {}) [:appscan_obj] pts[:folder_item_id].to_i ion].to_s.scrub.to_sym opts[:poll_interval].nil? 60 se opts[:poll_interval].to_i d is in a Ready state = PWN::Plugins::IBMAppscan.get_folder_item_by_id( ppscan_obj, : folder_item_id der_item[:state] error("Scan isn't in a Ready state. Current state: #{state}, abort.") if state != 'Ready' icking Off Scan for Folder Item: #{folder_item_id}") an_rest_call( ppscan_obj, post, lderitems/#{folder_item_id}", tion=2' to Monitor Scan Completion Ready' erval em = PWN::Plugins::IBMAppscan.get_folder_item_by_id( appscan_obj, id: folder_item_id older_item[:state] "Current Scan State: #{state}...") can Completed @ #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}") an_rest_call( ppscan_obj, post, lderitems/#{folder_item_id}", tion=3' an_rest_call( ppscan_obj, post, lderitems/#{folder_item_id}", tion=4' an_rest_call( ppscan_obj, post, lderitems/#{folder_item_id}", tion=5' error("Invalid action. Valid actions are:\n:run\n:suspend\n:cancel\n:end\n") esponse] = response esponse] = Nokogiri::XML(response) => e
def self.generate_scan_report(opts = {})
def self.generate_scan_report(opts = {}) [:appscan_obj] scan_name] [:output_path] an_obj[:appscan_ip].to_s.scrub ://#{appscan_ip}:9443/ase/pages/Login.jsp" "https://#{appscan_ip}/ase/FolderExplorer.aspx" s://#{appscan_ip}/ase/LogOut.aspx" t path actually exists ror("Output directory does not exist: #{output_path}") unless File.directory?(output_path) :Plugins::TransparentBrowser.open( eadless, 27.0.0.1:8080' r_obj[:browser] tem in_uri.to_s.to_s.scrub ld(name: 'j_username').when_present.set(appscan_obj[:username]) ld(name: 'j_password').when_present.set(Base64.decode64(appscan_obj[:password])) ame: 'login').when_present.click reports page and click on the report link e_appscan_uri.to_s.to_s.scrub xt, 'ASE').when_present.click eport link with a matching name and click it ch do |link| k.text == scan_name.to_s) && link.href =~ /^https:.+XReports.+/ t.click ror("Could not find matching scan name for name #{scan_name}") unless clicked utput_path}/#{scan_name.gsub(/[^\w.-]/, '_')}/" tput_path if File.directory?(output_path) utput_path level report _browser.url}&exportformat=pdf&exportdelivery=download" utput_path}Top_Level.pdf" scan_obj, ort_link, put_name => e ror retrieving report for '#{scan_name}': #{e}") ays logout out_uri.to_s.to_s.scrub
def self.get_a_folders_folder_items(opts = {})
def self.get_a_folders_folder_items(opts = {}) [:appscan_obj] folder_item_id].to_i _rest_call(appscan_obj: appscan_obj, rest_call: "folders/#{folder_id}/folderitems") tems = {} tems[:raw_response] = response tems[:xml_response] = Nokogiri::XML(response) tems => e
def self.get_folder_by_id(opts = {})
def self.get_folder_by_id(opts = {}) [:appscan_obj] folder_id].to_i _rest_call(appscan_obj: appscan_obj, rest_call: "folders/#{folder_id}") se] = response se] = Nokogiri::XML(response) => e
def self.get_folder_item_by_id(opts = {})
def self.get_folder_item_by_id(opts = {}) [:appscan_obj] pts[:folder_item_id].to_i _rest_call(appscan_obj: appscan_obj, rest_call: "folderitems/#{folder_item_id}") esponse] = response esponse] = Nokogiri::XML(response) us of a Scan : 10; ] = folder_item[:xml_response].xpath('//xmlns:state/xmlns:name').text => e ror: #{e} | #{e.class}\nResponse Returned: #{folder_item[:raw_response]}")
def self.get_folder_item_options(opts = {})
def self.get_folder_item_options(opts = {}) [:appscan_obj] pts[:folder_item_id].to_i hy not all options are returned ormFillUserNameValue & esCOTAutoFormFillPasswordValue) _rest_call(appscan_obj: appscan_obj, rest_call: "folderitems/#{folder_item_id}/options") s = {} s[:raw_response] = response s[:xml_response] = Nokogiri::XML(response) s[:options] = folder_item_options[:xml_response].xpath( le-option/@href' s => e
def self.get_folder_items(opts = {})
def self.get_folder_items(opts = {}) [:appscan_obj] _rest_call(appscan_obj: appscan_obj, rest_call: 'folderitems') response] = response response] = Nokogiri::XML(response) => e
def self.get_folders(opts = {})
def self.get_folders(opts = {}) [:appscan_obj] _rest_call(appscan_obj: appscan_obj, rest_call: 'folders') nse] = response nse] = Nokogiri::XML(response) => e
def self.get_issue_collection(opts = {})
def self.get_issue_collection(opts = {}) [:appscan_obj] report_id].to_i _rest_call( scan_obj, rts/#{report_id}/issues?mode=all" {} raw_response] = response xml_response] = Nokogiri::XML(response) rieved Issue Collection for Report ID: #{report_id}") => e
def self.get_report_collection(opts = {})
def self.get_report_collection(opts = {}) [:appscan_obj] _id = opts[:report_folder_item_id].to_i rieving Report Collection ID: #{report_folder_item_id} - Available Report Pack Collection:") _rest_call(appscan_obj: appscan_obj, rest_call: "folderitems/#{report_folder_item_id}/reports") = {} :raw_response] = response :xml_response] = Nokogiri::XML(response) rt pack collection :xml_response].xpath('//xmlns:report').each do |r| - #{r.xpath('xmlns:name').text}") => e
def self.get_report_data(opts = {})
def self.get_report_data(opts = {}) :appscan_obj] :report_link] :output_name] ort_link) Plugins::TransparentBrowser.open(browser_type: :rest) rowser] _link, 'Cookie' => appscan_obj[:cookie], :verify_ssl => OpenSSL::SSL::VERIFY_NONE) /#{uri.host}#{res.headers['location']}" ocation}" rt on the server side on, 'Cookie' => appscan_obj[:cookie], :verify_ssl => OpenSSL::SSL::VERIFY_NONE) t_name, 'wb') = 'Stream' 'Cookie' => appscan_obj[:cookie], :verify_ssl => OpenSSL::SSL::VERIFY_NONE) do |resp| do |seg| => e ld not get report data: #{e}")
def self.get_scan_templates(opts = {})
def self.get_scan_templates(opts = {}) [:appscan_obj] _rest_call(appscan_obj: appscan_obj, rest_call: 'templates') ponse] = response ponse] = Nokogiri::XML(response) => e
def self.get_single_report(opts = {})
def self.get_single_report(opts = {}) [:appscan_obj] report_id].to_i _rest_call(appscan_obj: appscan_obj, rest_call: "reports/#{report_id}") se] = response se] = Nokogiri::XML(response) rieved Report ID/Name: #{report_id}/#{report[:xml_response].xpath('//xmlns:report/xmlns:name').text}") => e
def self.get_single_report_data(opts = {})
def self.get_single_report_data(opts = {}) [:appscan_obj] report_id].to_i _rest_call( scan_obj, rts/#{report_id}/data?mode=all" esponse] = response esponse] = Nokogiri::XML(response) rieved Report Data for Report ID: #{report_id}") => e
def self.get_single_report_schema(opts = {})
def self.get_single_report_schema(opts = {}) [:appscan_obj] report_id].to_i _rest_call( scan_obj, rts/#{report_id}/data?metadata=schema" _response] = response _response] = Nokogiri::XML(response) rieved Report Schema for Report ID: #{report_id}") => e
def self.get_subfolders_of_folder(opts = {})
def self.get_subfolders_of_folder(opts = {}) [:appscan_obj] folder_id].to_i _rest_call(appscan_obj: appscan_obj, rest_call: "folders/#{folder_id}/folders") sponse] = response sponse] = Nokogiri::XML(response) => e
def self.help
def self.help self}.login( equired host/ip of Nexpose Console (server)', uired username', ional password (will prompt if nil)' .schema( required appscan_obj returned from login method' }.version( required appscan_obj returned from login method' }.get_folders( required appscan_obj returned from login method' elf}.get_subfolders_of_folder( required appscan_obj returned from login method', quired folder to retrieve' .get_folder_by_id( required appscan_obj returned from login method', quired folder to retrieve' {self}.get_folder_items( required appscan_obj returned from login method' self}.get_folder_item_by_id( required appscan_obj returned from login method', : 'required folder item to retrieve' _items = #{self}.get_a_folders_folder_items( required appscan_obj returned from login method', quired folder to retrieve' ons = #{self}.get_folder_item_options( required appscan_obj returned from login method', : 'required folder item to retrieve' reate_scan_based_on_template( required appscan_obj returned from login method' required template id returned from get_scan_templates method' quired name of scan' quired description of scan' lf}.get_scan_templates( required appscan_obj returned from login method' self}.configure_scan_options( required appscan_obj returned from login method', : 'required folder item id', red option to change within the scan (folder item). Pass :help for a list of options.', ed option value(s)' self}.folder_item_scan_action( required appscan_obj returned from login method', : 'required folder item id', red action for scan to follow. Available actions are: :run, :suspend, :cancel, & :end', 'optional setting to determine length in seconds to poll for scan state (defaults to 60)' n = #{self}.get_report_collection( required appscan_obj returned from login method', item_id: 'required report folder item id' .get_single_report( required appscan_obj returned from login method', quired report id' self}.get_single_report_data( required appscan_obj returned from login method', quired report id' #{self}.get_single_report_schema( required appscan_obj returned from login method', quired report id' = #{self}.get_issue_collection( required appscan_obj returned from login method', quired report id' _scan_report( required appscan_obj returned from login', quired name of scan for which to generate a report', required path to save generated report' required appscan_obj returned from login method'
def self.login(opts = {})
def self.login(opts = {}) :appscan_ip] sername].to_s.scrub ri = "https://#{appscan_ip}/ase/services".to_s.scrub [:password].nil? Plugins::AuthenticationHelper.mask_password :password].to_s.scrub ging into IBM Appscan Enterprise Server: #{appscan_ip}") :Plugins::TransparentBrowser.open(browser_type: :rest) ser_obj[:browser]::Request ient.execute( scan_api_uri}/login", =#{username}&password=#{password}", e taining the Appscan Server host/ip & post-authenticated Appscan REST cookie arse(response.args[:url]).host asc_session_id=#{response.cookies['asc_session_id']}; ASP.NET_SessionId=#{response.cookies['ASP.NET_SessionId']}" an_ip] = appscan_ip e] = appscan_cookie esponse] = response esponse] = Nokogiri::XML(response) ] = appscan_obj[:xml_response].xpath( xmlns:build' sion] = appscan_obj[:xml_response].xpath( xmlns:dbversion' _version] = appscan_obj[:xml_response].xpath( xmlns:rules-version' ame] = appscan_obj[:xml_response].xpath( xmlns:user-name' ord] = Base64.strict_encode64(password) d_in] = true => e
def self.logout(opts = {})
def self.logout(opts = {}) [:appscan_obj] ging out...') _rest_call(appscan_obj: appscan_obj, rest_call: 'logout') ged_in] = false ul' => e
def self.schema(opts = {})
def self.schema(opts = {}) [:appscan_obj] _rest_call(appscan_obj: appscan_obj, rest_call: 'schema') se] = response se] = Nokogiri::XML(response) => e
def self.version(opts = {})
def self.version(opts = {}) [:appscan_obj] _rest_call(appscan_obj: appscan_obj, rest_call: 'version') nse] = response nse] = Nokogiri::XML(response) version[:xml_response].xpath( xmlns:build' ] = version[:xml_response].xpath( xmlns:dbversion' sion] = version[:xml_response].xpath( xmlns:rules-version' = version[:xml_response].xpath( xmlns:user-name' => e