Nessus API客户端提取扫描的开始和结束时间- Ruby脚本



我下载了一个ruby脚本,它连接到API,可以一次下载所有的报告。但是,当我下载这些报告时,在实际文件名中包含开始和结束时间对我来说至关重要。我能够修改我的脚本,以删除它自动附加到文件名的6个垃圾字符,并且为了测试,我能够在csv扩展之前添加"2x"(我计划只下载csv格式)。

问题是Nessus API没有提供一个变量来提取这个开始和结束时间。我唯一的其他选择是从网站本身抓取它。实际的报告位于https://nessus-scanner-ip/#/scans/<id>/hosts。当作为内容访问该链接时,会列出开始和结束时间。如何提取此时间并将其附加到军事时间的报告文件名?

谢谢你的帮助。

#!/usr/bin/env ruby
#################################################################################################
# Name: Nessus 6 Report Downloader
# Author: Travis Lee
#
# Version: 1.0
# Last Updated: 2/28/2016
#
# Description:  Interactive script that connects to a specified Nessus 6 server using the
#               Nessus REST API to automate mass report downloads. It has the ability to download
#               multiple or all reports/file types/chapters and save them to a folder of
#               your choosing. This has been tested with Nessus 6.5.5 and *should* work with
#               Nessus 6+, YMMV.
#
#               File types include: NESSUS, HTML, PDF, CSV, and DB.
#
#               Chapter types include: Vulnerabilities By Plugin, Vulnerabilities By Host,
#               Hosts Summary (Executive), Suggested Remediations, Compliance Check (Executive),
#               and Compliance Check.
#
# Usage: ruby ./nessus6-report-downloader.rb
#
# Reference: https://<nessus-server>:8834/api
#
#################################################################################################
require 'net/http'
require 'fileutils'
require 'io/console'
require 'date'
require 'json'
require 'openssl'
# This method will download the specified file type from specified reports
def report_download(http, headers, reports, reports_to_dl, filetypes_to_dl, chapters_to_dl, rpath, db_export_pw)
        begin
                puts "nDownloading report(s). Please wait..."
                # if all reports are selected
                if reports_to_dl[0].eql?("all")
                        reports_to_dl.clear
                        # re-init array with all the scan ids
                        reports["scans"].each do |scan|
                                reports_to_dl.push(scan["id"].to_s)
                        end
                end
                # iterate through all the indexes and download the reports
                reports_to_dl.each do |rep|
                        rep = rep.strip
                        filetypes_to_dl.each do |ft|
                                # export report
                                puts "n[+] Exporting scan report, scan id: " + rep + ", type: " + ft
                                path = "/scans/" + rep + "/export"
                                data = {'format' => ft, 'chapters' => chapters_to_dl, 'password' => db_export_pw}
                                resp = http.post(path, data.to_json, headers)
                                fileid = JSON.parse(resp.body)
                                # check export status
                                status_path = "/scans/" + rep + "/export/" + fileid["file"].to_s + "/status"
                                loop do
                                        sleep(5)
                                        puts "[+] Checking export status..."
                                        status_resp = http.get(status_path, headers)
                                        status_result = JSON.parse(status_resp.body)
                                        break if status_result["status"] == "ready"
                                        puts "[-] Export not ready yet, checking again in 5 secs."
                                end
                                # download report
                                puts "[+] Report ready for download..."
                                dl_path = "/scans/" + rep + "/export/" + fileid["file"].to_s + "/download"
                                dl_resp = http.get(dl_path, headers)
                                # create final path/filename and write to file
                                fname_temp = dl_resp.response["Content-Disposition"].split('"')
                                fname = "#{rpath}/#{fname_temp[1]}"
                                # save ext, then remove last 10 chars (6 garbage plus ext; we'll add ext next
                                ext = File.extname(fname)
                                ff = fname[0..-11]
                                f = ff + ext
                                # append start and end time to filename
                                f2x = f.gsub(ext, "2x"+ext)
                                # write file
                                open(f2x, 'w') { |f|
                                        f.puts dl_resp.body
                                }
                                puts "[+] Downloading report to: #{fname}"
                                #puts reports.scan["starttime"]
                                #reports["scans"].each do |scan|
                                #       printf("%sn", scan["starttime"])
                                #end
                        end
                end
        rescue StandardError => download_report_error
                puts "nnError downloading report: #{download_report_error}nn"
                exit
        end
end
# This method will return a list of all the reports on the server
def get_report_list(http, headers)
        begin
                # Try and do stuff
                path = "/scans"
                resp = http.get(path, headers)
                #puts "Number of reports found: #{reports.count}nn"
                results = JSON.parse(resp.body)
                printf("%-7s %-50s %-30s %-15s %-15s %-3sn", "Scan ID", "Name", "Last Modified", "Status", "Start", "End")
                printf("%-7s %-50s %-30s %-15s %-15s %-3sn", "-------", "----", "-------------", "------", "-----", "---")
                # print out all the reports
                results["scans"].each do |scan|
                #d = DateTime.parse(scan["starttime"])
                #year, month, day, t, hour, min, sec = scan["starttime"].unpack("A4A2A2c1A2A2A2")
                        printf("%-7s %-50s %-30s %-15s %-15s %-3sn", scan["id"], scan["name"], DateTime.strptime(scan["last_modification_date"].to_s,'%s').strftime('%b %e, %Y %H:%M %Z'), scan["status"], scan["starttime"], scan["not-being-used"])
                #       printf("%-7s %-50s %-30s %-15s %-5s %-3sn", scan["id"], scan["name"], DateTime.strptime(scan["last_modification_date"].to_s,'%s').strftime('%b %e, %Y %H:%M %Z'), scan["status"], DateTime.parse(scan["starttime"].to_s,'%s').strftime('%2H:%2M:%2s'), scan["starttime"])
                end
                return results
        rescue StandardError => get_scanlist_error
                puts "nnError getting scan list: #{get_scanlist_error}nn"
                exit
        end
end

# This method will make the initial login request and set the token value to use for subsequent requests
def get_token(http, username, password)
        begin
                path = "/session"
                data = {'username' => username, 'password' => password}
                resp = http.post(path, data.to_json, 'Content-Type' => 'application/json')
                token = JSON.parse(resp.body)
                headers = {
                        "User-Agent" => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:25.0) Gecko/20100101 Firefox/25.0',
                        "X-Cookie" => 'token=' + token["token"],
                        "Accept" => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                        "Accept-Language" => 'en-us,en;q=0.5',
                        "Accept-Encoding" => 'text/html;charset=UTF-8',
                        "Cache-Control" => 'max-age=0',
                        "Content-Type" => 'application/json'
                 }
                return headers
        rescue StandardError => get_token_error
                puts "nnError logging in/getting token: #{get_token_error}nn"
                exit
        end
end
### MAIN ###
puts "nNessus 6 Report Downloader 1.0"
# Collect server info
print "nEnter the Nessus Server IP: "
nserver = gets.chomp.to_s
print "Enter the Nessus Server Port [8834]: "
nserverport = gets.chomp.to_s
if nserverport.eql?("")
        nserverport = "8834"
end
# https object
http = Net::HTTP.new(nserver, nserverport)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
# Collect user/pass info
print "Enter your Nessus Username: "
username = gets.chomp.to_s
print "Enter your Nessus Password (will not echo): "
password = STDIN.noecho(&:gets).chomp.to_s
# login and get token cookie
headers = get_token(http, username, password)
# get list of reports
puts "nnGetting report list..."
reports = get_report_list(http, headers)
print "Enter the report(s) your want to download (comma separate list) or 'all': "
reports_to_dl = (gets.chomp.to_s).split(",")
if reports_to_dl.count == 0
        puts "nError! You need to choose at least one report!nn"
        exit
end
# select file types to download
puts "nChoose File Type(s) to Download: "
puts "[0] Nessus (No chapter selection)"
puts "[1] HTML"
puts "[2] PDF"
puts "[3] CSV (No chapter selection)"
puts "[4] DB (No chapter selection)"
print "Enter the file type(s) you want to download (comma separate list) or 'all': "
filetypes_to_dl = (gets.chomp.to_s).split(",")
if filetypes_to_dl.count == 0
        puts "nError! You need to choose at least one file type!nn"
        exit
end
# see which file types to download
formats = []
cSelect = false
dbSelect = false
filetypes_to_dl.each do |ft|
        case ft.strip
        when "all"
          formats.push("nessus")
          formats.push("html")
          formats.push("pdf")
          formats.push("csv")
          formats.push("db")
          cSelect = true
          dbSelect = true
        when "0"
          formats.push("nessus")
        when "1"
          formats.push("html")
          cSelect = true
        when "2"
          formats.push("pdf")
          cSelect = true
        when "3"
          formats.push("csv")
        when "4"
          formats.push("db")
          dbSelect = true
        end
end
# enter password used to encrypt db exports (required)
db_export_pw = ""
if dbSelect
        print "nEnter a Password to encrypt the DB export (will not echo): "
        db_export_pw = STDIN.noecho(&:gets).chomp.to_s
        print "n"
end
# select chapters to include, only show if html or pdf is in file type selection
chapters = ""
if cSelect
        puts "nChoose Chapter(s) to Include: "
        puts "[0] Vulnerabilities By Plugin"
        puts "[1] Vulnerabilities By Host"
        puts "[2] Hosts Summary (Executive)"
        puts "[3] Suggested Remediations"
        puts "[4] Compliance Check (Executive)"
        puts "[5] Compliance Check"
        print "Enter the chapter(s) you want to include (comma separate list) or 'all': "
        chapters_to_dl = (gets.chomp.to_s).split(",")
        if chapters_to_dl.count == 0
                puts "nError! You need to choose at least one chapter!nn"
                exit
        end
        # see which chapters to download
        chapters_to_dl.each do |chap|
                case chap.strip
                when "all"
                  chapters << "vuln_hosts_summary;vuln_by_plugin;vuln_by_host;remediations;compliance_exec;compliance;"
                when "0"
                  chapters << "vuln_by_plugin;"
                when "1"
                  chapters << "vuln_by_host;"
                when "2"
                  chapters << "vuln_hosts_summary;"
                when "3"
                  chapters << "remediations;"
                when "4"
                  chapters << "compliance_exec;"
                when "5"
                  chapters << "compliance;"
                end
        end
end
# create report folder
print "nPath to save reports to (without trailing slash): "
rpath = gets.chomp.to_s
unless File.directory?(rpath)
        FileUtils.mkdir_p(rpath)
end
# run report download
if formats.count > 0
        report_download(http, headers, reports, reports_to_dl, formats, chapters, rpath, db_export_pw)
end
puts "nReport Download Completed!nn"

Nessus API的"details"方法(https://Nessus_scanner:8834/api#/resources/scans/details)将返回给定扫描的起始和结束Epoch时间戳:

  • "scan_start":{字符串}
  • "scan_end":{字符串}

你可以使用:

Time.at(xxxxxxxxxx).strftime("%H%M")

其中"xxxxxxxxxx"是10位Epoch时间戳,以获得军事格式(HHMM)。

相关内容

  • 没有找到相关文章

最新更新