module PWN::Plugins::NexposeVulnScan

def self.authors

def self.authors
st.pentest@0dayinc.com>

def self.delete_site_assets_older_than(opts = {})

def self.delete_site_assets_older_than(opts = {})
c_obj]
site_name]
.to_i
.each do |site|
d if site.name == site_name
emoving the Following Assets from #{site.name} (site id: #{site_id}) Older than #{days} Days:")
expose::Search::Field::SCAN_DATE, Nexpose::Search::Operator::EARLIER_THAN, days).each do |asset|
id == site_id
o("#{asset.id}|#{asset.ip}|#{asset.last_scan}")
te_asset(asset.id)
Site: #{site_name} Not Found.  Please check the spelling and try again.")
 => e

def self.download_recurring_report(opts = {})

def self.download_recurring_report(opts = {})
c_obj]
s[:report_names].to_s.scrub.split(',')
erating #{report_names.count} Report(s): #{report_names.inspect}...")
 opts[:poll_interval].nil?
60
se
opts[:poll_interval].to_i
d
= []
s_arr.count == report_names.count
each do |report|
ach do |requested_report|
name = requested_report.to_s.strip.chomp.delete('"')
report.name == this_report_name
o("Generating Recurring Report: #{report.name} @ #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}..Current Report Status: #{report.status}")
atus == 'Failed'
nfo("Report Generation for #{report.name} failed...re-generating now...")
ate report from pre-existing config.
generate_report_via_existing_config(nsc_obj: nsc_obj, config_id: report.config_id)
= {}
:report_name] = report.name
:report_status] = report.status
:report_uri] = report.uri
ush(report_hash)
s_arr = report_arr.uniq.select { |this_report| this_report[:report_status] == 'Generated' }
eport_names are available within nsc_obj.reports (thus making it worthwhile to loop vs saying report !found).
otal Reports Generated So Far: #{report_status_arr.count}...")
val # Sleep and check the status again...
port_arr.inspect)
port_status_arr.inspect)
each do |report_hash|
ion = File.extname(report_hash[:report_uri])
nDownloading #{report_hash[:report_name]}#{this_file_extention} from #{report_hash[:report_uri]}...")
(report_hash[:report_uri], "#{report_hash[:report_name]}#{this_file_extention}")
plete.')
 => e

def self.generate_report_via_existing_config(opts = {})

def self.generate_report_via_existing_config(opts = {})
c_obj]
config_id].to_i
nfig = Nexpose::ReportConfig.load(nsc_obj, config_id)
nfig.generate(nsc_obj)
 => e

def self.help

def self.help
}.login(
equired host/ip of Nexpose Console (server)',
uired username',
ional password (will prompt if nil)'
lic_methods
ite_assets_arr = #{self}.list_all_individual_site_assets(
ired nsc_obj returned from login method',
quired Nexpose site name to update (case-sensitive)'
}.update_site_assets(
ired nsc_obj returned from login method',
quired Nexpose site name to update (case-sensitive),
red array of hashes containing called :ip => values being IP address (All IPs not included in the :assets parameter will be removed from Nexpose)'
}.delete_site_assets_older_than(
ired nsc_obj returned from login method',
quired Nexpose site name to update (case-sensitive),
d assets to remove older than number of days in this parameter'
}.scan_site_by_name(
ired nsc_obj returned from login method',
quired Nexpose site name to scan (case-sensitive),
 'optional poll interval to check the completion status of the scan (defaults to 60 seconds)
_recurring_report(
ired nsc_obj returned from login method',
'required array of report name/types to generate e.g. ['report.html', 'report.pdf', 'report.xml']',
 'optional poll interval to check the completion status of report generation (defaults to 60 seconds)
sc_obj: 'required nsc_obj returned from login method')

def self.list_all_individual_site_assets(opts = {})

def self.list_all_individual_site_assets(opts = {})
c_obj]
site_name]
.each do |site|
d if site.name == site_name
e_assets_arr = []
isting All Assets from #{site_name} (site id: #{site_id}):")
expose::Search::Field::SITE_ID, Nexpose::Search::Operator::IN, site_id).each do |asset|
"#{asset.id}|#{asset.ip}|#{asset.last_scan}")
_site_assets_arr.push(asset.ip)
Site: #{site_name} Not Found.  Please check the spelling and try again.")
e_assets_arr
 => e

def self.login(opts = {})

def self.login(opts = {})
:console_ip]
sername].to_s
[:password].nil?
Plugins::AuthenticationHelper.mask_password
:password].to_s
:Connection.new(console_ip, username, password)
Console.load(nsc_obj)
eout = 21_600
obj) # This will change the global sesion timeout config in the console
 => e

def self.logout(opts = {})

def self.logout(opts = {})
c_obj]
::Console.load(nsc_obj)
imeout = 600 # This is the default session timeout in the console
obj) # This will change the global sesion timeout config in the console
 => e

def self.scan_site_by_name(opts = {})

def self.scan_site_by_name(opts = {})
c_obj]
site_name].to_s
 opts[:poll_interval].nil?
60
se
opts[:poll_interval].to_i
d
d kick off the scan
.each do |site|
.name == site_name
e(site.id)
can Started for #{site_name} @ #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}")
d
ck the status of the scan
r("Site name: #{site_name} does not exist as a site in Nexpose.  Please check your spelling and try again.") if site_id == ''
o: Checking status for an interval of #{poll_interval} seconds until completion.")
l
ivity.each { |scan| scan_status = scan.status if scan.site_id == site_id }
= 'running'
eing progress is good :)
erval # Sleep and check the status again...
"Scan Completed for #{site_name} @ #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}")
 => e

def self.update_site_assets(opts = {})

def self.update_site_assets(opts = {})
c_obj]
site_name]
ets]
.each do |site|
.name == site_name
d
expose::Site.load(nsc_obj, site_id)
 List of Assets for Given Site & Remove Old List of Assets from Given Site (if applicable)
emoving the Following Assets:')
ets = nsc_obj.filter(Nexpose::Search::Field::SITE_ID, Nexpose::Search::Operator::IN, site_id)
= []
p_host_hash| new_site_assets.push(ip_host_hash[:ip].to_s.scrub.strip.chomp) }
ets.each do |current_site_asset|
te_assets.include?(current_site_asset.ip)
"Removing #{current_site_asset.ip}")
.remove_included_asset(current_asset) # This should work and be less invasive but no worky :(
_asset(current_site_asset.id) # So we completely remove the asset from Nexpose altogether :/
omplete.')
f Assets to Given Site
dding the Following Assets to #{site.name} (site id: #{site_id}):")
ip_host_hash|
PAddr.new(ip_host_hash[:ip].to_s.scrub.strip.chomp)
_ip.to_s.match?('255') # || current_ip =~ /^[224-239]/ # Multicast?
to reverse DNS word to see if an IP s available as well
o("Adding #{current_ip}")
.include_asset(current_ip)
rror
e(nsc_obj)
omplete.')
 => e