├── scripts ├── .gitkeep ├── snippets │ ├── README.md │ └── ruby │ │ └── get_password.rb ├── metrics │ ├── README.md │ └── ruby │ │ ├── analyze_load_raw_device_count.rb │ │ ├── analyze_load_by_config.rb │ │ ├── analyze_load_ignore_discovery.rb │ │ └── analyze_average_scan_time.rb ├── discovery_connections │ ├── aws_discovery_connection │ │ ├── Gemfile │ │ ├── README.md │ │ ├── aws_configuration.yml │ │ └── aws_discovery_connection_creator.rb │ └── dhcp_monitor │ │ ├── README.md │ │ └── powershell │ │ └── dhcp_monitor.ps1 ├── sites │ ├── list_sites │ │ ├── README.md │ │ └── powershell │ │ │ └── list_sites.ps1 │ └── export-import-site-scans │ │ └── ruby │ │ ├── export-site-scans.rb │ │ ├── import-site-scans.rb │ │ └── README.md ├── general_api │ └── api_cmdlet │ │ ├── README.md │ │ └── powershell │ │ └── invoke-nexposeapi.psm1 ├── schedules │ └── bulk_modify_schedules │ │ └── ruby │ │ ├── README.md │ │ └── bulk_modify_schedules.rb ├── users │ └── audit_users │ │ ├── ruby │ │ └── audit_users.rb │ │ └── README.md └── asset_groups │ ├── remove_all_assets_from_group │ └── ruby │ │ └── rm_all_assets_from_group.rb │ └── create_asset_group │ └── ruby │ └── create_asset_group.rb ├── sql-queries └── .gitkeep ├── .snyk ├── cortex.yaml ├── .github ├── PULL_REQUEST_TEMPLATE.md └── CONTRIBUTING.md ├── LICENSE ├── README.md └── .gitignore /scripts/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sql-queries/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.snyk: -------------------------------------------------------------------------------- 1 | version: v1.25.0 2 | ignore: {} 3 | patch: {} 4 | exclude: {} 5 | -------------------------------------------------------------------------------- /scripts/snippets/README.md: -------------------------------------------------------------------------------- 1 | Here you'll find snippets of common code that can be re-used in other scripts. -------------------------------------------------------------------------------- /scripts/metrics/README.md: -------------------------------------------------------------------------------- 1 | ### Metrics 2 | 3 | These scripts will provide various statistics about your console. 4 | -------------------------------------------------------------------------------- /scripts/discovery_connections/aws_discovery_connection/Gemfile: -------------------------------------------------------------------------------- 1 | gem 'nexpose', git: 'git://github.com/rapid7/nexpose-client.git' 2 | -------------------------------------------------------------------------------- /scripts/sites/list_sites/README.md: -------------------------------------------------------------------------------- 1 | The list_sites.ps1 script is an example for logging into Nexpose and retrieving a site listing using PowerShell. -------------------------------------------------------------------------------- /scripts/snippets/ruby/get_password.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # An example of securely getting a password input from CLI without extra gems required 4 | 5 | require 'io/console' 6 | 7 | def get_password(prompt="Password: ") 8 | print prompt 9 | STDIN.noecho(&:gets).chomp 10 | end 11 | 12 | @password = get_password 13 | 14 | # just an example, don't actually do this! 15 | puts "\nYou entered #{@password}" -------------------------------------------------------------------------------- /cortex.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.1 2 | info: 3 | title: Nexpose Resources 4 | description: Scripts, SQL queries, and other resources for Nexpose 5 | x-cortex-git: 6 | github: 7 | alias: r7org 8 | repository: rapid7/nexpose-resources 9 | x-cortex-tag: nexpose-resources 10 | x-cortex-type: service 11 | x-cortex-domain-parents: 12 | - tag: vm-console 13 | x-cortex-groups: 14 | - target:not-deployed 15 | - strategy:on-prem 16 | - exposure:external-ship 17 | -------------------------------------------------------------------------------- /scripts/general_api/api_cmdlet/README.md: -------------------------------------------------------------------------------- 1 | Original author: Jeff Martin 2 | 3 | --- 4 | 5 | Here is a short cmdlet I put together to use the API with powershell. You submit the command as a parameter and the required attributes as a hash array. I haven't gone through the bulk of the API yet, but so far it works with the commands I've wanted to use. It returns the output as XML, but once you have that in hand pulling out the data values isn't hard in PS 6 | 7 | Examples: 8 | ```powershell 9 | Invoke-NexposeAPI -APIVersion 1.1 -SessionID ABC123 -Command SiteListingRequest 10 | ``` 11 | 12 | ```powershell 13 | $Fields=@{} 14 | $Fields.Add("site-id","1") 15 | Invoke-NexposeAPI -APIVersion 1.1 -SessionID ABC123 -Fields $Fields -Command SiteDeviceListingRequest 16 | ``` -------------------------------------------------------------------------------- /scripts/metrics/ruby/analyze_load_raw_device_count.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'nexpose' 3 | include Nexpose 4 | 5 | nsc = Connection.new('host', 'user', 'password') 6 | nsc.login 7 | at_exit { nsc.logout } 8 | 9 | asset_count = {} 10 | engine_load = {} 11 | 12 | nsc.sites.each do |site| 13 | asset_count[site.id] = nsc.site_device_listing(site.id).count 14 | last_scan = nsc.last_scan(site.id) 15 | engine_load[last_scan.engine_id] ||= 0 16 | engine_load[last_scan.engine_id] += asset_count[site.id] 17 | end 18 | 19 | total_assets = asset_count.values.reduce(0) { |acc, count| acc += count } 20 | 21 | engines = nsc.engines 22 | engine_load.each do |id, count| 23 | name = engines.find { |eng| eng.id == id }.name 24 | percent = '%.2f' % (count.to_f / total_assets * 100) 25 | puts "#{name} : #{count} (#{percent}%)" 26 | end 27 | -------------------------------------------------------------------------------- /scripts/sites/export-import-site-scans/ruby/export-site-scans.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn ruby 2 | require 'nexpose' 3 | 4 | nsc = Nexpose::Connection.new('localhost-primary', 'nxadmin', 'nxpassword', '3780') 5 | nsc.login 6 | at_exit { nsc.logout } 7 | 8 | # Allow the user to pass in the site ID to the script. 9 | site_id = ARGV[0].to_i 10 | 11 | # Write the site configuration to a file. 12 | site = Nexpose::Site.load(nsc, site_id) 13 | File.write('site.json', site.to_json) 14 | 15 | # Grab scans and sort by scan end time 16 | scans = nsc.site_scan_history(site_id).sort_by { |s| s.end_time }.map { |s| s.scan_id } 17 | 18 | # Scan IDs are not guaranteed to be in order, so use a proxy number to order them. 19 | i = 0 20 | scans.each do |scan_id| 21 | nsc.export_scan(scan_id, "scan-#{i}.zip") 22 | i += 1 23 | end 24 | -------------------------------------------------------------------------------- /scripts/schedules/bulk_modify_schedules/ruby/README.md: -------------------------------------------------------------------------------- 1 | A script to enable, disable, or delete schedules on multiple or all sites at once. 2 | 3 | Usage: 4 | 5 | ``` 6 | Usage: bulk_modify_schedules.rb [options] 7 | 8 | Enable, disable, or delete all scan schedules. Optional: Specify site IDs separated by commas. 9 | Valid actions are: enable, disable, delete. 10 | 11 | Note that this script will always prompt for a connection password. 12 | 13 | Options: 14 | -H, --host [HOST] IP or hostname of Nexpose console. Default: localhost 15 | -p, --port [PORT] Port of Nexpose console. Default: 3780 16 | -u, --user [USER] Username to connect to Nexpose with. Default: nxadmin 17 | -d, --dry-run Output sites to modify, but do not actually modify them. 18 | -h, --help Print this help message. 19 | ``` -------------------------------------------------------------------------------- /scripts/metrics/ruby/analyze_load_by_config.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'nexpose' 3 | include Nexpose 4 | 5 | nsc = Connection.new('host', 'user', 'password') 6 | nsc.login 7 | at_exit { nsc.logout } 8 | 9 | count_by_config = {} 10 | 11 | nsc.sites.each do |site| 12 | config = Site.load(nsc, site.id) 13 | next if config.scan_template =~ /discovery/ 14 | 15 | count_by_config[config.engine] = 0 16 | config.assets.each do |asset| 17 | count = 1 18 | count += (asset.to.to_i - asset.from.to_i) if defined? asset.from and asset.to 19 | count_by_config[config.engine] += count 20 | end 21 | end 22 | 23 | total = count_by_config.values.reduce(0) { |acc, count| acc += count } 24 | 25 | engines = nsc.engines 26 | count_by_config.each do |id, count| 27 | name = engines.find { |eng| eng.id == id }.name 28 | percent = '%.2f' % (count.to_f / total * 100) 29 | puts "#{name} : #{count} (#{percent}%)" 30 | end 31 | -------------------------------------------------------------------------------- /scripts/metrics/ruby/analyze_load_ignore_discovery.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'nexpose' 3 | include Nexpose 4 | 5 | nsc = Connection.new('host', 'user', 'password') 6 | nsc.login 7 | at_exit { nsc.logout } 8 | 9 | asset_count = {} 10 | engine_load = {} 11 | 12 | nsc.sites.each do |site| 13 | config = Site.load(nsc, site.id) 14 | next if config.scan_template =~ /discover/ 15 | 16 | asset_count[site.id] = nsc.site_device_listing(site.id).count 17 | last_scan = nsc.last_scan(site.id) 18 | engine_load[last_scan.engine_id] ||= 0 19 | engine_load[last_scan.engine_id] += asset_count[site.id] 20 | end 21 | 22 | total_assets = asset_count.values.reduce(0) { |acc, count| acc += count } 23 | 24 | engines = nsc.engines 25 | engine_load.each do |id, count| 26 | name = engines.find { |eng| eng.id == id }.name 27 | percent = '%.2f' % (count.to_f / total_assets * 100) 28 | puts "#{name} : #{count} (#{percent}%)" 29 | end 30 | -------------------------------------------------------------------------------- /scripts/discovery_connections/aws_discovery_connection/README.md: -------------------------------------------------------------------------------- 1 | # aws_discovery_connection_creator.rb 2 | This script creates an AWS Asset Sync type discovery connection. It was written for customers setting up many discovery connections, or tearing them down and recreating them frequently. This script was adapted from the internal cucumber testing framework, but stripped of those dependencies other than the nexpose-client ruby gem. 3 | ## Usage 4 | bundle install 5 | export NEXPOSE_PW=redacted NEXPOSE_AWS_ACCESS_KEY_ID=redacted NEXPOSE_AWS_SECRET_ACCESS_KEY=redacted && bundle exec ruby ./aws_discovery_connection_creator.rb 6 | For security's sake, nexpose password and aws keys are kept in env vars rather than a plaintext config file. If you have multiple connections to set up, it may be desireable to keep them in aws_configuration.yml or use some other kind of scheme. 7 | ## aws_configuration.yml 8 | This config file contains two example configurations for an AWS discovery connection. More could be added, but these basically illustrate how to handle multiple regions and/or roles as well as the boolean fields. -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | 7 | ## Motivation and Context 8 | 9 | 10 | 11 | 12 | ## How Has This Been Tested? 13 | 14 | 15 | 16 | 17 | 18 | ## Screenshots (if appropriate): 19 | 20 | 21 | 22 | ## Checklist: 23 | 24 | 25 | 26 | - [ ] I have updated the documentation accordingly (if changes are required). 27 | - [ ] I am the copyright holder or have permission to publish this content. (For new files) 28 | -------------------------------------------------------------------------------- /scripts/metrics/ruby/analyze_average_scan_time.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'nexpose' 3 | include Nexpose 4 | 5 | # Note, this doesn't calculate the desired value across paused scans. 6 | 7 | nsc = Connection.new('host', 'user', 'password') 8 | nsc.login 9 | at_exit { nsc.logout } 10 | 11 | engine_times = {} 12 | engine_assets = {} 13 | 14 | nsc.sites.each do |site| 15 | config = Site.load(nsc, site.id) 16 | next unless config.scan_template =~ /full-audit/ 17 | # puts "Gathering data for site '#{site.name}'." 18 | 19 | scan_history = nsc.site_scan_history(site.id) 20 | 21 | scan_history.each do |scan| 22 | next unless scan.end_time # Skip running scans. 23 | engine = scan.engine_id 24 | live = scan.nodes.live if scan.nodes 25 | start_time = scan.start_time 26 | end_time = scan.end_time 27 | 28 | if live 29 | engine_times[engine] ||= 0 30 | engine_times[engine] += (end_time - start_time) 31 | engine_assets[engine] ||= 0 32 | engine_assets[engine] += live 33 | end 34 | end 35 | end 36 | 37 | engines = nsc.engines 38 | engine_times.each do |id, time| 39 | name = engines.find { |eng| eng.id == id }.name 40 | avg_time = '%.2f' % (time / engine_assets[id] / 60) 41 | puts "#{name} : #{avg_time} minutes / asset" 42 | end 43 | -------------------------------------------------------------------------------- /scripts/sites/export-import-site-scans/ruby/import-site-scans.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn ruby 2 | require 'nexpose' 3 | 4 | nsc = Nexpose::Connection.new('localhost-secondary', 'nxadmin', 'nxpassword', '3780') 5 | nsc.login 6 | at_exit { nsc.logout } 7 | 8 | site_bak = JSON.parse(File.read('site.json'), symbolize_names: true) 9 | site = Nexpose::Site.from_hash(site_bak) 10 | site.id = -1 11 | # Set to use the local scan engine. 12 | site.name = "#{site.name}-import" 13 | site.engine_id = nsc.engines.find { |e| e.name == 'Local scan engine' }.id 14 | site_id = site.save(nsc) 15 | puts "Created Site: #{site.name}" 16 | 17 | # Import scans by numerical ordering 18 | scans = Dir.glob('scan-*.zip').map { |s| s.gsub(/scan-/, '').gsub(/\.zip/, '').to_i }.sort 19 | scans.each do |scan| 20 | zip = "scan-#{scan}.zip" 21 | puts "Importing #{zip}" 22 | nsc.import_scan(site_id, zip) 23 | # Poll until scan is complete before attempting to import the next scan. 24 | last_scan = nsc.site_scan_history(site_id).max_by { |s| s.start_time }.scan_id 25 | puts "...#{nsc.scan_status(last_scan)}" 26 | sleep 60 # Give it plenty of time before importing next 27 | while (%w(running integrating).include?(nsc.scan_status(last_scan))) 28 | puts "...#{nsc.scan_status(last_scan)}" 29 | sleep 60 # Give it plenty of time before importing next 30 | end 31 | puts "Integration of #{zip} complete" 32 | end 33 | -------------------------------------------------------------------------------- /scripts/sites/list_sites/powershell/list_sites.ps1: -------------------------------------------------------------------------------- 1 | add-type @" 2 | using System.Net; 3 | using System.Security.Cryptography.X509Certificates; 4 | public class TrustAllCertsPolicy : ICertificatePolicy { 5 | public bool CheckValidationResult( 6 | ServicePoint srvPoint, X509Certificate certificate, 7 | WebRequest request, int certificateProblem) { 8 | return true; 9 | } 10 | } 11 | "@ 12 | [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy 13 | 14 | # Replace with the server, username and password for your Nexpose install 15 | 16 | $user = 'nxadmin' 17 | $pwd = 'nxadmin' 18 | $server = 'localhost' 19 | $port = '3780' 20 | $api_version = '1.1' 21 | $uri = "https://${server}:${port}/api/${api_version}/xml" 22 | $login_request = "" 23 | 24 | # login and get the session id 25 | $resp = Invoke-WebRequest -URI $uri -Body $login_request -ContentType 'text/xml' -Method post 26 | $session_id = $resp.content | Select-Xml -XPath '//@session-id' | Select-Object -ExpandProperty Node | foreach-object {$_.'#text'} 27 | 28 | # Get a list of Sites 29 | $sites_request = "" 30 | $resp = Invoke-WebRequest -URI $uri -Body $sites_request -ContentType 'text/xml' -Method post 31 | $sites = $resp.content | Select-XMl -XPath '//@name' | Select-Object -ExpandProperty Node | foreach-object {$_.'#text'} 32 | Write-Output $sites 33 | -------------------------------------------------------------------------------- /scripts/sites/export-import-site-scans/ruby/README.md: -------------------------------------------------------------------------------- 1 | ## Site Scan Export/Import Example 2 | These scripts are intended to show how to use the `nexpose` ruby gem in order to export scans from a site and import them 3 | into another site and/or Nexpose console. They will need to be modified more if advanced features are needed. 4 | 5 | #### export-site-scans.rb 6 | Run the script by passing in the site ID where scans should be exported from: 7 | ``` 8 | > ruby export-site-scans.rb 1 9 | ``` 10 | 11 | This script results in a site.json file being generated with details about the site that was exported (eg scan template, 12 | name, etc) in addition to all the zipped scan files for the site. An index is used to keep track of scan order (oldest 13 | to newest) since the import of scans must follow the same order. 14 | 15 | #### import-site-scans.rb 16 | Run the script without passing any arguments: 17 | ``` 18 | > ruby import-site-scans.rb 19 | ``` 20 | 21 | This script results in the site being created in the secondary console (will fail if site name already in use) with a 22 | name appended with '-import'. The import defines `local scan engine` for site use and can be used as an example of how 23 | configurations can be overridden during the site creation. 24 | 25 | In addition, each scan file is imported (oldest to newest) with sleeps added to ensure the import is complete prior to 26 | moving on. 27 | 28 | It is also possible to create the site manually prior to the import, comment out line 14 and 15, and add the following 29 | with proper site ID defined for import to line 16: 30 | ``` 31 | site_id = 2 32 | ``` 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017–2018, Rapid7, Inc. and nexpose-resource contributors 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /scripts/discovery_connections/dhcp_monitor/README.md: -------------------------------------------------------------------------------- 1 | Original author: pavedian 2 | 3 | --- 4 | 5 | I was faced with a challenge recently. We use DHCP Discovery connections and have automated actions set to scan items that have not been scanned in over a week. Also, we scan any assets discovered that unknown to Nexpose. 6 | 7 | Working with Discovery Connections can be frustrating. When a discovery connection disconnects, it will likely time out after some time and won't try to reconnect itself. It also will change the engine being used to 'local engine' if the engine if offline for any reason (especially when updating). You can unknowingly reconnect all of your connections to the 'Local Scan Engine' if you are not careful. This may not be a huge deal to some but for me it was. We have over 30 Discovery Connections configured. Since there is no alerting built in for this I decided to create my own. 8 | 9 | Remember to generate the Secure String password to file prior to using this. Once you have done so, you can schedule this script to run every hour. 10 | The script checks for Engine ID 3 (Local Engine for my Console) and for any connections in a Disconnected State. Feel free to adjust as needed and to make suggestions. I made this quickly to address the issue. 11 | 12 | ```powershell 13 | #Use this to generate the secure string password to keep your password safe 14 | #Remember to generate this with the account you plan to use for your scheduled task 15 | #Only that account can convert it back to use for the scheduled task 16 | 17 | $SecurePassword = Read-Host "Enter Password" -AsSecureString 18 | $SecurePassword | ConvertFrom-SecureString | Out-File c:\scripts\nexpose.txt 19 | ``` -------------------------------------------------------------------------------- /scripts/users/audit_users/ruby/audit_users.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # Original author: jaimie07 4 | 5 | require 'nexpose' 6 | require 'csv' 7 | require 'io/console' 8 | 9 | include Nexpose 10 | 11 | #insert console host ip instead of localhost if you are running from any other machine 12 | host = 'localhost' 13 | 14 | user='' 15 | password='' 16 | 17 | #requests user to provide their Nexpose username 18 | if user == '' 19 | print 'User: ' 20 | user = gets.chomp 21 | end 22 | 23 | #masks the password text 24 | def get_password(prompt='Password: ') 25 | print prompt 26 | STDIN.noecho(&:gets).chomp 27 | end 28 | 29 | #requests user to provide their Nexpose password 30 | if password == '' 31 | password = get_password 32 | end 33 | 34 | #log in to Nexpose and initiate connection 35 | nsc = Connection.new(host, user, password) 36 | nsc.login 37 | at_exit { nsc.logout } 38 | 39 | puts '' 40 | 41 | #pulls user account list from Nexpose console into an array 42 | users = nsc.list_users 43 | 44 | #Creates .csv file named "UserList.csv" in the folder you are running the script 45 | CSV.open("UserList_#{Time.now.strftime('%Y-%m-%d')}.csv", 'wb') do |csv| 46 | 47 | #sets the column headers for the csv 48 | csv<<['UserID', 'FullName', 'Admin', 'Disabled', 'GroupCount', 'SiteCount', 'Role'] 49 | 50 | #loop to iterate through user list array 51 | users.each do |user| 52 | 53 | #creates a value to use the User class attributes 54 | uo = User.load(nsc,user.id) 55 | 56 | #writes user account attributes to rows 57 | csv << ["#{user.name}", "#{user.full_name}", "#{user.is_admin}", "#{user.is_disabled}", "#{user.group_count}", "#{user.site_count}", "#{uo.role_name}"] 58 | end 59 | end 60 | 61 | puts 'File created' -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Nexpose Resources 2 | 3 | Fork the repository, clone your fork to your local system, create a new branch and then start adding or making changes. When it's ready to be reviewed, push your changes up to your fork and then open a pull request. 4 | 5 | Please include the following items in your pull request: 6 | 7 | ### License and Copyright Notice 8 | 9 | The Nexpose Resources project is released under the BSD 3-Clause license (see [LICENSE](../LICENSE)). All contributions will be licensed the same. 10 | 11 | You may include a copyright notice within your resources and/or your readme file. 12 | 13 | ### Readme file 14 | 15 | The readme file can be in any format you like, though we prefer formats that can be rendered on Github. You can see the supported formats here: https://github.com/github/markup#markups 16 | 17 | Please avoid using formats like Microsoft Word, RTF, PDF, or other "heavy" document types. 18 | 19 | Your readme file should describe what your resource is and how to use it, with examples if necessary. 20 | 21 | ### Resource file(s) 22 | 23 | For scripts it is simple enough to ensure the filename has the appropriate extension, such as `.rb` for Ruby, `.py` for Python, etc. 24 | 25 | For SQL queries you can save as `.txt` or `.sql` - the latter will provide nice formatting when viewing on Github. 26 | 27 | If your resource requires users to replace some variables be sure to note that with code comments. Avoid including default usernames, passwords, hostnames, or IP addresses. If an example must be provided they should not resolve to real things on the Internet. You may use `example.com` for a hostname or `127.0.0.1`, `192.168.0.1`, `10.0.0.1`, and similar private ranges for IP addresses. 28 | -------------------------------------------------------------------------------- /scripts/users/audit_users/README.md: -------------------------------------------------------------------------------- 1 | Original author: jaimie07 2 | 3 | --- 4 | 5 | My company performs quarterly access reviews for all applications. Each application "owner" is required to provide a list of user accounts and their roles, submit that for review and remove/modify any user account necessary. 6 | 7 | For this quarter, my security team required the list be generated from the system if possible. We do have a IAM tool that I am hoping I can integrate with eventually. 8 | 9 | Because you can't export the user access list from Nexpose, I threw together the crude API script below to get the job done -- since I was only given a day to do it. I plan on updating it, but it might not happen until closer to the end of next quarter. 10 | 11 | I've seen a few others requesting something like this on the community page. Unfortunately, whether you have custom roles or use default roles, there does not seem to be a way to pull the individual permissions from the roles, only the role titles. I also do not know if there is a way to get a list of the asset groups and sites that a user has permissions to, only the count of those. 12 | 13 | This report returns a .csv file with output for UserID, FullName (first and last name), Admin (True or false, true is a global-admin role), Disabled (true or false), GroupCount (number of asset groups), SiteCount (number of sites), and Role (role title). The file name is UserList+current date and is saved to whatever folder your script is running from. 14 | 15 | I use the User class and the User Summary class. 16 | 17 | Feel free to give any suggestions on making it better. I will try to answer any questions, but I am a beginner myself. 18 | 19 | Advice: 20 | Run from the Nexpose console. Otherwise "host" needs to be changed to the IP of your server that Nexpose is running on 21 | Run with a global admin account. It may not run for lesser privileges. 22 | 23 | Hope this helps! -------------------------------------------------------------------------------- /scripts/general_api/api_cmdlet/powershell/invoke-nexposeapi.psm1: -------------------------------------------------------------------------------- 1 | # Original author: Jeff Martin 2 | 3 | Function Invoke-NexposeAPI 4 | { 5 | 6 | <# 7 | .SYNOPSIS 8 | Run the specified API command, giving the required attributes as a hash array. Returns XML output from Nexpose 9 | #> 10 | 11 | [CmdletBinding()] 12 | Param 13 | ( 14 | [Parameter(Mandatory=$True)] 15 | [String]$Command, 16 | 17 | [Parameter()] 18 | $Fields, 19 | 20 | [Parameter(Mandatory=$True)] 21 | [String]$SessionID, 22 | 23 | [Parameter(Mandatory=$True)] 24 | [ValidateSet("1.1", "1.2")] 25 | [String]$APIVersion, 26 | 27 | [Parameter()] 28 | [String]$Server = "somehost", 29 | 30 | [Parameter()] 31 | [String]$Port = "3780" 32 | 33 | ) 34 | 35 | Write-Debug (Format-Message -StartFunction) 36 | 37 | $URL = "https://${Server}:${Port}/api/${ApiVersion}/xml" 38 | 39 | # Create the base string for the XML, so we can add attributes to it later 40 | # We have to include a dummy attribute so Powershell casts the node as XML not string 41 | [xml]$RequestBody = "<$Command RemoveThis=`"null`" />" 42 | # Add the sessionID Attribute, then remove the dummy placeholder 43 | $RequestBody.$Command.SetAttribute("session-id",$SessionID) 44 | $RequestBody.$Command.RemoveAttribute("RemoveThis") 45 | 46 | 47 | 48 | #Add the rest of the attributes as submitted on cmd line 49 | If ( $Fields ) 50 | { 51 | ForEach ( $Attribute in $Fields.Keys ) 52 | { 53 | $RequestBody.$Command.SetAttribute($Attribute,$Fields.$Attribute) 54 | } 55 | } 56 | 57 | [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } 58 | $Response = Invoke-WebRequest -URI $URL -Body $RequestBody -ContentType 'text/xml' -Method post 59 | 60 | # Should be some sort of error checking here 61 | 62 | 63 | Write-Output $Response 64 | 65 | 66 | Write-Debug (Format-Message -EndFunction) 67 | } # end of function -------------------------------------------------------------------------------- /scripts/discovery_connections/aws_discovery_connection/aws_configuration.yml: -------------------------------------------------------------------------------- 1 | AWS 0: 2 | serviceName: amazon-web-services 3 | configName: AWSAssetSync0 4 | configurationAttributes: 5 | valueClass: Object 6 | objectType: service_configuration 7 | properties: 8 | region: 9 | valueClass: Array 10 | items: 11 | - valueClass: String 12 | value: All regions 13 | consoleInsideAWS: 14 | valueClass: Boolean 15 | value: true 16 | engineInsideAWS: 17 | valueClass: Boolean 18 | value: false 19 | arn: 20 | valueClass: Array 21 | items: 22 | - valueClass: String 23 | value: 'arn:aws:iam::000000000000:role/ExampleTestRole0' 24 | useProxy: 25 | valueClass: Boolean 26 | value: false 27 | AWS 1: 28 | serviceName: amazon-web-services 29 | configName: AWSAssetSync1 30 | configurationAttributes: 31 | valueClass: Object 32 | objectType: service_configuration 33 | properties: 34 | region: 35 | valueClass: Array 36 | items: 37 | - valueClass: String 38 | value: US East (N. Virginia) 39 | consoleInsideAWS: 40 | valueClass: Boolean 41 | value: true 42 | engineInsideAWS: 43 | valueClass: Boolean 44 | value: false 45 | arn: 46 | valueClass: Array 47 | items: 48 | - valueClass: String 49 | value: 'arn:aws:iam::000000000000:role/ExampleTestRole1' 50 | useProxy: 51 | valueClass: Boolean 52 | value: false 53 | AWS 2: 54 | serviceName: amazon-web-services 55 | configName: AWSAssetSync2 56 | configurationAttributes: 57 | valueClass: Object 58 | objectType: service_configuration 59 | properties: 60 | region: 61 | valueClass: Array 62 | items: 63 | - valueClass: String 64 | value: All regions 65 | consoleInsideAWS: 66 | valueClass: Boolean 67 | value: true 68 | engineInsideAWS: 69 | valueClass: Boolean 70 | value: false 71 | arn: 72 | valueClass: Array 73 | items: 74 | - valueClass: String 75 | value: 'arn:aws:iam::000000000000:role/ExampleTestRole2' 76 | useProxy: 77 | valueClass: Boolean 78 | value: false -------------------------------------------------------------------------------- /scripts/asset_groups/remove_all_assets_from_group/ruby/rm_all_assets_from_group.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'optparse' 3 | require 'rubygems' 4 | require 'highline/import' 5 | require 'nexpose' 6 | 7 | @host = 'localhost' 8 | @port = 3780 9 | @user = 'nxadmin' 10 | 11 | OptionParser.new do |opts| 12 | opts.banner = "Usage: ruby #{File::basename($0)} [options] " 13 | opts.separator '' 14 | opts.separator 'Remove all assets from a group.' 15 | opts.separator '' 16 | opts.separator %Q{An asset group must already exist for this script to run against. This script\nwill probably be most useful for removing older assets, for example, when used\nagainst a dynamic asset group defined as\n "last scan date earlier than 90 days ago".} 17 | opts.separator '' 18 | opts.separator 'Note that this script will always prompt for a connection password.' 19 | opts.separator '' 20 | opts.separator 'Options:' 21 | opts.on('-h', '--host HOST', 'IP or hostname of Nexpose console. Defaults to localhost if not provided.') { |host| @host = host } 22 | opts.on('-p', '--port PORT', Integer, 'Port of Nexpose console. Defaults to 3780 if not provided.') { |port| @port = port } 23 | opts.on('-u', '--user USER', 'Username to connect to Nexpose with. Defaults to nxadmin if not provided.') { |user| @user = user } 24 | opts.on('-d', '--dry-run', 'Only print out assets to be deleted, but do not actually delete.') { |d| @dry_run = d } 25 | opts.on_tail('--help', 'Print this help message.') { puts opts; exit } 26 | end.parse! 27 | 28 | # Now grab the group ID from the remaining arguments. 29 | unless ARGV[0] 30 | $stderr.puts 'Asset group ID is required. Use --help for instructions.' 31 | exit(1) 32 | end 33 | group_id = ARGV[0] 34 | 35 | def get_password(prompt = 'Password: ') 36 | ask(prompt) { |query| query.echo = false } 37 | end 38 | puts 'Upon entering a password, deletion will begin.' 39 | puts 'Use --dry-run to ensure only the desired assets will be deleted.' unless @dry_run 40 | @password = get_password 41 | 42 | nsc = Nexpose::Connection.new(@host, @user, @password, @port) 43 | nsc.login 44 | 45 | Nexpose::AssetGroup.load(nsc, group_id).devices.each do |device| 46 | if @dry_run 47 | puts "#{device.address} [ID: #{device.id}] Site: #{device.site_id}" 48 | else 49 | nsc.delete_device(device.id) 50 | end 51 | end 52 | 53 | nsc.logout 54 | -------------------------------------------------------------------------------- /scripts/discovery_connections/dhcp_monitor/powershell/dhcp_monitor.ps1: -------------------------------------------------------------------------------- 1 | # Original author: pavedian 2 | 3 | $style = "" 8 | $server = '' 9 | $api_version = '1.2' 10 | $user = 'nxuser' 11 | $SecurePassword = Get-Content C:\scripts\nexpose.txt | ConvertTo-SecureString 12 | $Marshal = [System.Runtime.InteropServices.Marshal] 13 | $Bstr = $Marshal::SecureStringToBSTR($SecurePassword) 14 | $Password = $Marshal::PtrToStringAuto($Bstr) 15 | $Marshal::ZeroFreeBSTR($Bstr) 16 | $pwd = $Password 17 | $uri = "https://${server}/api/${api_version}/xml" 18 | $login_request = "" 19 | $resp = Invoke-WebRequest -URI $uri -Body $login_request -ContentType 'text/xml' -Method post 20 | [xml]$xmldata = $resp.content 21 | if($xmldata.LoginResponse.success -eq '0'){ 22 | Write-Host 'ERROR: '$xmldata.LoginResponse.Failure.message -ForegroundColor Red 23 | } 24 | Else{ 25 | $SCRIPT:session_id = $xmldata.LoginResponse.'session-id' 26 | Write-Host "Login Successful" -ForegroundColor Green 27 | } 28 | $disc_request = "" 29 | $resp_disc = Invoke-WebRequest -URI $uri -Body $disc_request -ContentType 'text/xml' -Method post 30 | [xml]$xmldata = $resp_disc.content 31 | $HTML = $xmldata.DiscoveryConnectionListingResponse.DiscoveryConnectionSummary | 32 | Where{$_.'connection-status' -eq 'Disconnected' -or $_.'engine-id' -eq 3} | where {$_.'name' -ne 'Sonar'} | 33 | ConvertTo-Html -As Table -Property Name,'Connection-Status','Engine-ID' -PreContent $Style 34 | $HTML2 = $HTML -replace "3", "Using Local Engine" 35 | if ($HTML2 -match 'Disconnected' -or $HTML2 -match "Using Local Engine"){ 36 | [string[]]$recipients = "First Last ", "First Last " 37 | Write-Host 'sending email' 38 | send-mailmessage -to $recipients -from "nexpose@company.com" -subject "Nexpose Discovery Connections Alert!" -BodyAsHtml ($HTML2 | Out-String) -smtpserver 39 | } else { 40 | write-host "Nothing to see here.. move along" 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nexpose Resources 2 | 3 | A collection of scripts, reports, SQL queries, and other resources for use with Nexpose and InsightVM. The goal of this repository is to make it easy to find, use, and contribute to up-to-date resources that improve productivity with Nexpose and InsightVM. 4 | 5 | # Types of Resources 6 | 7 | ## Scripts 8 | 9 | Utility scripts typically built for a specific purpose. Each script may be available in multiple programming languages. 10 | 11 | You will primarily find scripts compatible with [nexpose-client](https://github.com/rapid7/nexpose-client) (Ruby) and [nexpose-client-python](https://github.com/rapid7/nexpose-client-python) (Python) in this repository. 12 | 13 | ## SQL Queries 14 | 15 | Ready to use queries for the SQL Query Export and/or Data Warehouse features for creating custom reports. 16 | 17 | SQL query examples from the old community site have moved to the new knowledge base: https://kb.help.rapid7.com/docs/sql-query-export 18 | 19 | ## Other Repositories 20 | 21 | Links to other Github repositories that contain scripts and other resources for Nexpose. 22 | 23 | ### From Rapid7 24 | 25 | - https://github.com/rapid7/recog Service and system fingerprint matchers, many of which are used by Nexpose 26 | - https://github.com/rapid7/coverage-toolkit A toolkit for creating custom vulnerability content for Nexpose 27 | - https://github.com/rapid7/nexpose-warehouse-jasper-templates Jaspersoft Studio report templates for Nexpose Data Warehouse 28 | - https://github.com/rapid7-cookbooks/nexpose Chef cookbook for automated Nexpose deployment 29 | - https://github.com/rapid7/vm-console-client-python Generated Python library for the Rapid7 InsightVM/Nexpose RESTful API 30 | - https://github.com/rapid7/vm-console-client-ruby Generated Ruby gem for the Rapid7 InsightVM/Nexpose RESTful API 31 | 32 | ### From the Community 33 | 34 | - https://github.com/BrianWGray/nexpose Generic scripts for managing Nexpose 35 | - https://github.com/BrianWGray/cmty-nexpose-checks Custom vulnerabiltiy checks for Nexpose 36 | - https://github.com/mb01r/NexposeCLI.rb A command line interface to perform Nexpose actions 37 | - https://github.com/My-Random-Thoughts/Rapid7Nexpose A PowerShell module to use the Nexpose v3 API 38 | 39 | # Contributing 40 | 41 | See [the contributing file](.github/CONTRIBUTING.md) for information on how to contribute to this repository. 42 | 43 | # License 44 | 45 | The Nexpose Resources project is released under the BSD 3-Clause license (see [LICENSE](./LICENSE)). 46 | -------------------------------------------------------------------------------- /scripts/asset_groups/create_asset_group/ruby/create_asset_group.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'nexpose' 3 | require 'optparse' 4 | require 'highline/import' 5 | 6 | # Default values 7 | @host = 'localhost' 8 | @port = 3780 9 | @user = 'nxadmin' 10 | @name = @desc = nil 11 | 12 | OptionParser.new do |opts| 13 | opts.banner = "Usage: #{File::basename($0)} [options]" 14 | opts.separator '' 15 | opts.separator 'Create an asset group based upon an input file, one IP per line.' 16 | opts.separator '' 17 | opts.separator 'By default, it uses the name of the file as the name of the asset group.' 18 | opts.separator 'As currently written, the script will only asset per IP address.' 19 | opts.separator 'If multiple sites have the same IP, it is non-deterministic which asset it will choose.' 20 | opts.separator '' 21 | opts.separator 'Note that this script will always prompt for a connection password.' 22 | opts.separator '' 23 | opts.separator 'Options:' 24 | opts.on('-n', '--name [NAME]', 'Name to use for new asset group. Must not already exist.') { |name| @name = name } 25 | opts.on('-d', '--desc [DESCRIPTION]', 'Description to use for new asset group.') { |desc| @desc = desc } 26 | opts.on('-h', '--host [HOST]', 'IP or hostname of Nexpose console. Default: localhost') { |host| @host = host } 27 | opts.on('-p', '--port [PORT]', Integer, 'Port of Nexpose console. Default: 3780') { |port| @port = port } 28 | opts.on('-u', '--user [USER]', 'Username to connect to Nexpose with. Default: nxadmin') { |user| @user = user } 29 | opts.on('-x', '--debug', 'Report duplicate IP addresses to STDERR.') { |debug| @debug = debug } 30 | opts.on_tail('--help', 'Print this help message.') { puts opts; exit } 31 | end.parse! 32 | 33 | # Any arguments after flags can be grabbed now." 34 | unless ARGV[0] 35 | $stderr.puts 'Input file is required.' 36 | exit(1) 37 | end 38 | file = ARGV[0] 39 | @name = File.basename(file, File.extname(file)) unless @name 40 | 41 | def get_password(prompt = 'Password: ') 42 | ask(prompt) { |query| query.echo = false } 43 | end 44 | @password = get_password 45 | 46 | # This will fail if the file cannot be read. 47 | ips = File.read(file).split.uniq 48 | 49 | nsc = Nexpose::Connection.new(@host, @user, @password, @port) 50 | nsc.login 51 | 52 | # Create a map of all assets by IP to make them quicker to find. 53 | all_assets = nsc.assets.reduce({}) do |hash, dev| 54 | $stderr.puts("Duplicate asset: #{dev.address}") if @debug and hash.member? dev.address 55 | hash[dev.address] = dev 56 | hash 57 | end 58 | 59 | # Drop the connection, in case group creation takes too long. 60 | nsc.logout 61 | 62 | group = Nexpose::AssetGroup.new(@name, @desc) 63 | 64 | ips.each do |ip| 65 | if all_assets.member? ip 66 | group.devices << all_assets[ip] 67 | elsif @debug 68 | $stderr.puts("No asset with IP #{ip} found.") 69 | end 70 | end 71 | 72 | nsc.login 73 | at_exit { nsc.logout } 74 | group.save(nsc) 75 | puts "Group '#{@name}' saved with #{group.devices.size} assets." 76 | -------------------------------------------------------------------------------- /scripts/schedules/bulk_modify_schedules/ruby/bulk_modify_schedules.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # Copyright (c) 2017 Rapid7, Inc. 4 | # License: BSD 3-Clause 5 | 6 | gem 'nexpose', '>= 5' 7 | require 'nexpose' 8 | require 'optparse' 9 | require 'io/console' 10 | require 'time' 11 | require 'logger' 12 | 13 | ARGV << '--help' if ARGV.empty? 14 | 15 | host = '127.0.0.1' 16 | port = '3780' 17 | user = 'nxadmin' 18 | @dry_run = false 19 | @log = Logger.new($stdout) 20 | actions = ['enable', 'disable', 'delete'] 21 | 22 | OptionParser.new do |opts| 23 | opts.banner = "Usage: #{File::basename($0)} [options] " 24 | opts.separator '' 25 | opts.separator 'Enable, disable, or delete all scan schedules. Optional: Specify site IDs separated by commas.' 26 | opts.separator "Valid actions are: #{actions.join(', ')}." 27 | opts.separator '' 28 | opts.separator 'Note that this script will always prompt for a connection password.' 29 | opts.separator '' 30 | opts.separator 'Options:' 31 | opts.on('-H', '--host [HOST]', 'IP or hostname of Nexpose console. Default: localhost') { |h| host = h } 32 | opts.on('-p', '--port [PORT]', Integer, 'Port of Nexpose console. Default: 3780') { |p| port = p } 33 | opts.on('-u', '--user [USER]', 'Username to connect to Nexpose with. Default: nxadmin') { |u| user = u } 34 | opts.on('-d', '--dry-run', 'Output sites to modify, but do not actually modify them.') { @dry_run = true } 35 | opts.on_tail('-h', '--help', 'Print this help message.') { puts opts; exit } 36 | end.parse! 37 | 38 | unless ARGV[0] 39 | $stderr.puts 'Action is required. Valid actions are: #{actions.join(', ')}. Use --help for instructions.' 40 | exit(1) 41 | end 42 | 43 | unless actions.include?(ARGV[0]) 44 | $stderr.puts "Action is required. Valid actions are: #{actions.join(', ')}. Use --help for instructions." 45 | exit(1) 46 | end 47 | 48 | @action = ARGV[0] 49 | site_ids = [] 50 | 51 | if ARGV[1] 52 | site_ids = ARGV[1].split(',').map(&:to_i) 53 | site_ids.reject! { |id| id < 1 } 54 | @log.info "Site IDs: #{site_ids.join(', ')}" 55 | end 56 | 57 | def get_password(prompt="Password: ") 58 | print prompt 59 | STDIN.noecho(&:gets).chomp 60 | end 61 | 62 | def modify_site_schedule(nsc, site_id) 63 | site = Nexpose::Site.load(nsc, site_id) 64 | return if site.schedules.empty? 65 | case @action 66 | when 'enable' 67 | @log.info "Enabling #{site.schedules.size} schedule(s) for '#{site.name}' (#{site.id})." 68 | site.schedules.each { |sched| sched.enabled = true } 69 | when 'disable' 70 | @log.info "Disabling #{site.schedules.size} schedule(s) for '#{site.name}' (#{site.id})." 71 | site.schedules.each { |sched| sched.enabled = false } 72 | when 'delete' 73 | @log.info "Deleting #{site.schedules.size} schedule(s) for '#{site.name}' (#{site.id})." 74 | site.schedules = [] 75 | else 76 | @log.warn "Invalid action: #{@action}" 77 | return 78 | end 79 | if @dry_run == false 80 | @log.info "Saving changes to '#{site.name}' (#{site.id})." 81 | site.save(nsc) 82 | else 83 | @log.info "*** Dry run *** Not saving changes to '#{site.name}' (#{site.id})." 84 | end 85 | end 86 | 87 | password = get_password 88 | 89 | @log.info "\nConnecting to #{host}:#{port} as #{user}..." 90 | nsc = Nexpose::Connection.new(host, user, password, port) 91 | 92 | if @dry_run == true 93 | @log.info '*** Dry run enabled. No schedules will be modified. ***' 94 | end 95 | 96 | @log.info "Action to perform: #{@action}" 97 | 98 | nsc.login 99 | at_exit { nsc.logout } 100 | 101 | if site_ids.empty? 102 | sites = nsc.list_sites 103 | sites.each do |site| 104 | begin 105 | modify_site_schedule(nsc, site.id) 106 | rescue Nexpose::APIError => e 107 | @log.warn "Site #{site.id} '#{site.name}'' failed: #{e.message}" 108 | next 109 | end 110 | end 111 | else 112 | site_ids.each do |site_id| 113 | begin 114 | modify_site_schedule(nsc, site_id) 115 | rescue Nexpose::APIError => e 116 | @log.warn "Site ID #{site_id} failed: #{e.message}" 117 | next 118 | end 119 | end 120 | end 121 | 122 | @log.info 'Finished.' 123 | exit(0) -------------------------------------------------------------------------------- /scripts/discovery_connections/aws_discovery_connection/aws_discovery_connection_creator.rb: -------------------------------------------------------------------------------- 1 | require 'nexpose' 2 | require 'yaml' 3 | require 'eso' 4 | 5 | # aws_discovery_connection_creator.rb creates a new AWS Asset Sync discovery connection 6 | # USAGE: 7 | # bundle install 8 | # export NEXPOSE_PW=redacted NEXPOSE_AWS_ACCESS_KEY_ID=redacted NEXPOSE_AWS_SECRET_ACCESS_KEY=redacted && bundle exec ruby ./aws_discovery_connection_creator.rb 9 | 10 | # Set up Nexpose and AWS credentials 11 | nexpose_host = 'localhost' 12 | nexpose_username = 'admin' 13 | nexpose_port = 3780 14 | # For security's sake, pull the password from an environment variable rather than a config file. 15 | nexpose_password = ENV['NEXPOSE_PW'] 16 | 17 | # Create connection to nexpose console 18 | @nsc = Nexpose::Connection.new(nexpose_host, nexpose_username, nexpose_password, nexpose_port) 19 | 20 | # Login to Nexpose 21 | @nsc.login 22 | 23 | # Logout of Nexpose when script Exits 24 | at_exit { @nsc.logout } 25 | 26 | # Create the configuration_manager which will post new configurations 27 | configuration_manager = Eso::ConfigurationManager.new(@nsc) 28 | # Create the integration_option_manager which will post new integration options linked to a configuration 29 | integration_option_manager = Eso::IntegrationOptionsManager.new(@nsc) 30 | 31 | # Load the discovery connection configurations from a file. 32 | dc_configurations = YAML.load_file('aws_configuration.yml') 33 | dc_configurations.each { |dc_label, dc_configuration| 34 | puts "Processing #{dc_label}..." 35 | 36 | # Create a site for assets to live in 37 | site = Nexpose::Site.new("#{dc_configuration['configName']} Site") 38 | site_id = site.save(@nsc) 39 | 40 | # If NEXPOSE_AWS_ACCESS_KEY_ID and NEXPOSE_AWS_SECRET_ACCESS_KEY are set in env vars, use them in the config. 41 | if ENV['NEXPOSE_AWS_ACCESS_KEY_ID'] 42 | dc_configuration['configurationAttributes']['properties']['accessKeyID'] = {'valueClass' => 'String', 'value'=> access_key_id} 43 | end 44 | if ENV['NEXPOSE_AWS_SECRET_ACCESS_KEY'] 45 | dc_configuration['configurationAttributes']['properties']['secretAccessKey'] = {'valueClass' => 'String', 'value' => secret_access_key} 46 | end 47 | 48 | # POST the request for a discovery connection configuration. 49 | # If the following fails, make sure that the config is valid (enter it into the UI and `Test Connection`) and that 50 | # it's not a duplicate of a preexisting config. 51 | request_body = JSON.generate(dc_configuration) 52 | config_id = configuration_manager.post_service_configuration(request_body) 53 | 54 | # POST a sync_aws_assets_with_tags integration option. 55 | # Integration options are used to use the configuration bits of a discovery connection to perform 56 | # some type of action -- in this case, syncing the assets from the discovery connection (via config_id) to a site 57 | # (via site_id). Integration options must be created and then started. 58 | sync_integration_option = Eso::IntegrationOptionsManager.build_sync_aws_assets_with_tags_option( 59 | name: "sync-#{config_id}", 60 | # Integration options link a DC config -> site 61 | discovery_conn_id: config_id) 62 | sync_integration_option.site_id = site_id 63 | sync_integration_option.id = integration_option_manager.create(sync_integration_option.to_json) 64 | integration_option_manager.start(sync_integration_option.id) 65 | 66 | # POST a verify_aws_targets integration option. This integration option is needed to do pre-scan verification 67 | # of AWS assets. Pre-scan verification is the process of checking that an AWS ip actually (still) belongs to 68 | # the customer so the customer doesn't scan other companies' assets. 69 | verify_integration_option = Eso::IntegrationOptionsManager.build_verify_aws_targets_option( 70 | name: "verify-#{config_id}", 71 | discovery_conn_id: config_id) 72 | verify_integration_option.site_id = site_id 73 | verify_integration_option.id = integration_option_manager.create(verify_integration_option.to_json) 74 | integration_option_manager.start(verify_integration_option.id) 75 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/go,java,ruby,python,eclipse,intellij,notepadpp,sublimetext,visualstudio,visualstudiocode 3 | 4 | ### Eclipse ### 5 | 6 | .metadata 7 | bin/ 8 | tmp/ 9 | *.tmp 10 | *.bak 11 | *.swp 12 | *~.nib 13 | local.properties 14 | .settings/ 15 | .loadpath 16 | .recommenders 17 | 18 | # External tool builders 19 | .externalToolBuilders/ 20 | 21 | # Locally stored "Eclipse launch configurations" 22 | *.launch 23 | 24 | # PyDev specific (Python IDE for Eclipse) 25 | *.pydevproject 26 | 27 | # CDT-specific (C/C++ Development Tooling) 28 | .cproject 29 | 30 | # Java annotation processor (APT) 31 | .factorypath 32 | 33 | # PDT-specific (PHP Development Tools) 34 | .buildpath 35 | 36 | # sbteclipse plugin 37 | .target 38 | 39 | # Tern plugin 40 | .tern-project 41 | 42 | # TeXlipse plugin 43 | .texlipse 44 | 45 | # STS (Spring Tool Suite) 46 | .springBeans 47 | 48 | # Code Recommenders 49 | .recommenders/ 50 | 51 | # Scala IDE specific (Scala & Java development for Eclipse) 52 | .cache-main 53 | .scala_dependencies 54 | .worksheet 55 | 56 | ### Eclipse Patch ### 57 | # Eclipse Core 58 | .project 59 | 60 | # JDT-specific (Eclipse Java Development Tools) 61 | .classpath 62 | 63 | ### Go ### 64 | # Binaries for programs and plugins 65 | *.exe 66 | *.dll 67 | *.so 68 | *.dylib 69 | 70 | # Test binary, build with `go test -c` 71 | *.test 72 | 73 | # Output of the go coverage tool, specifically when used with LiteIDE 74 | *.out 75 | 76 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 77 | .glide/ 78 | 79 | ### Intellij ### 80 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 81 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 82 | 83 | # User-specific stuff: 84 | .idea/**/workspace.xml 85 | .idea/**/tasks.xml 86 | .idea/dictionaries 87 | 88 | # Sensitive or high-churn files: 89 | .idea/**/dataSources/ 90 | .idea/**/dataSources.ids 91 | .idea/**/dataSources.xml 92 | .idea/**/dataSources.local.xml 93 | .idea/**/sqlDataSources.xml 94 | .idea/**/dynamic.xml 95 | .idea/**/uiDesigner.xml 96 | 97 | # Gradle: 98 | .idea/**/gradle.xml 99 | .idea/**/libraries 100 | 101 | # CMake 102 | cmake-build-debug/ 103 | 104 | # Mongo Explorer plugin: 105 | .idea/**/mongoSettings.xml 106 | 107 | ## File-based project format: 108 | *.iws 109 | 110 | ## Plugin-specific files: 111 | 112 | # IntelliJ 113 | /out/ 114 | 115 | # mpeltonen/sbt-idea plugin 116 | .idea_modules/ 117 | 118 | # JIRA plugin 119 | atlassian-ide-plugin.xml 120 | 121 | # Cursive Clojure plugin 122 | .idea/replstate.xml 123 | 124 | # Crashlytics plugin (for Android Studio and IntelliJ) 125 | com_crashlytics_export_strings.xml 126 | crashlytics.properties 127 | crashlytics-build.properties 128 | fabric.properties 129 | 130 | ### Intellij Patch ### 131 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 132 | 133 | # *.iml 134 | # modules.xml 135 | # .idea/misc.xml 136 | # *.ipr 137 | 138 | # Sonarlint plugin 139 | .idea/sonarlint 140 | 141 | ### Java ### 142 | # Compiled class file 143 | *.class 144 | 145 | # Log file 146 | *.log 147 | 148 | # BlueJ files 149 | *.ctxt 150 | 151 | # Mobile Tools for Java (J2ME) 152 | .mtj.tmp/ 153 | 154 | # Package Files # 155 | *.jar 156 | *.war 157 | *.ear 158 | *.zip 159 | *.tar.gz 160 | *.rar 161 | 162 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 163 | hs_err_pid* 164 | 165 | ### NotepadPP ### 166 | # Notepad++ backups # 167 | 168 | ### Python ### 169 | # Byte-compiled / optimized / DLL files 170 | __pycache__/ 171 | *.py[cod] 172 | *$py.class 173 | 174 | # C extensions 175 | 176 | # Distribution / packaging 177 | .Python 178 | env/ 179 | build/ 180 | develop-eggs/ 181 | dist/ 182 | downloads/ 183 | eggs/ 184 | .eggs/ 185 | lib/ 186 | lib64/ 187 | parts/ 188 | sdist/ 189 | var/ 190 | wheels/ 191 | *.egg-info/ 192 | .installed.cfg 193 | *.egg 194 | 195 | # PyInstaller 196 | # Usually these files are written by a python script from a template 197 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 198 | *.manifest 199 | *.spec 200 | 201 | # Installer logs 202 | pip-log.txt 203 | pip-delete-this-directory.txt 204 | 205 | # Unit test / coverage reports 206 | htmlcov/ 207 | .tox/ 208 | .coverage 209 | .coverage.* 210 | .cache 211 | nosetests.xml 212 | coverage.xml 213 | *,cover 214 | .hypothesis/ 215 | 216 | # Translations 217 | *.mo 218 | *.pot 219 | 220 | # Django stuff: 221 | local_settings.py 222 | 223 | # Flask stuff: 224 | instance/ 225 | .webassets-cache 226 | 227 | # Scrapy stuff: 228 | .scrapy 229 | 230 | # Sphinx documentation 231 | docs/_build/ 232 | 233 | # PyBuilder 234 | target/ 235 | 236 | # Jupyter Notebook 237 | .ipynb_checkpoints 238 | 239 | # pyenv 240 | .python-version 241 | 242 | # celery beat schedule file 243 | celerybeat-schedule 244 | 245 | # SageMath parsed files 246 | *.sage.py 247 | 248 | # dotenv 249 | .env 250 | 251 | # virtualenv 252 | .venv 253 | venv/ 254 | ENV/ 255 | 256 | # Spyder project settings 257 | .spyderproject 258 | .spyproject 259 | 260 | # Rope project settings 261 | .ropeproject 262 | 263 | # mkdocs documentation 264 | /site 265 | 266 | ### Ruby ### 267 | *.gem 268 | *.rbc 269 | /.config 270 | /coverage/ 271 | /InstalledFiles 272 | /pkg/ 273 | /spec/reports/ 274 | /spec/examples.txt 275 | /test/tmp/ 276 | /test/version_tmp/ 277 | /tmp/ 278 | 279 | # Used by dotenv library to load environment variables. 280 | # .env 281 | 282 | ## Specific to RubyMotion: 283 | .dat* 284 | .repl_history 285 | *.bridgesupport 286 | build-iPhoneOS/ 287 | build-iPhoneSimulator/ 288 | 289 | ## Specific to RubyMotion (use of CocoaPods): 290 | # 291 | # We recommend against adding the Pods directory to your .gitignore. However 292 | # you should judge for yourself, the pros and cons are mentioned at: 293 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 294 | # 295 | # vendor/Pods/ 296 | 297 | ## Documentation cache and generated files: 298 | /.yardoc/ 299 | /_yardoc/ 300 | /doc/ 301 | /rdoc/ 302 | 303 | ## Environment normalization: 304 | /.bundle/ 305 | /vendor/bundle 306 | /lib/bundler/man/ 307 | 308 | # for a library or gem, you might want to ignore these files since the code is 309 | # intended to run in multiple environments; otherwise, check them in: 310 | # Gemfile.lock 311 | # .ruby-version 312 | # .ruby-gemset 313 | 314 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 315 | .rvmrc 316 | 317 | ### SublimeText ### 318 | # cache files for sublime text 319 | *.tmlanguage.cache 320 | *.tmPreferences.cache 321 | *.stTheme.cache 322 | 323 | # workspace files are user-specific 324 | *.sublime-workspace 325 | 326 | # project files should be checked into the repository, unless a significant 327 | # proportion of contributors will probably not be using SublimeText 328 | # *.sublime-project 329 | 330 | # sftp configuration file 331 | sftp-config.json 332 | 333 | # Package control specific files 334 | Package Control.last-run 335 | Package Control.ca-list 336 | Package Control.ca-bundle 337 | Package Control.system-ca-bundle 338 | Package Control.cache/ 339 | Package Control.ca-certs/ 340 | Package Control.merged-ca-bundle 341 | Package Control.user-ca-bundle 342 | oscrypto-ca-bundle.crt 343 | bh_unicode_properties.cache 344 | 345 | # Sublime-github package stores a github token in this file 346 | # https://packagecontrol.io/packages/sublime-github 347 | GitHub.sublime-settings 348 | 349 | ### VisualStudioCode ### 350 | .vscode/* 351 | !.vscode/settings.json 352 | !.vscode/tasks.json 353 | !.vscode/launch.json 354 | !.vscode/extensions.json 355 | .history 356 | 357 | ### VisualStudio ### 358 | ## Ignore Visual Studio temporary files, build results, and 359 | ## files generated by popular Visual Studio add-ons. 360 | ## 361 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 362 | 363 | # User-specific files 364 | *.suo 365 | *.user 366 | *.userosscache 367 | *.sln.docstates 368 | 369 | # User-specific files (MonoDevelop/Xamarin Studio) 370 | *.userprefs 371 | 372 | # Build results 373 | [Dd]ebug/ 374 | [Dd]ebugPublic/ 375 | [Rr]elease/ 376 | [Rr]eleases/ 377 | x64/ 378 | x86/ 379 | bld/ 380 | [Bb]in/ 381 | [Oo]bj/ 382 | [Ll]og/ 383 | 384 | # Visual Studio 2015 cache/options directory 385 | .vs/ 386 | # Uncomment if you have tasks that create the project's static files in wwwroot 387 | #wwwroot/ 388 | 389 | # MSTest test Results 390 | [Tt]est[Rr]esult*/ 391 | [Bb]uild[Ll]og.* 392 | 393 | # NUNIT 394 | *.VisualState.xml 395 | TestResult.xml 396 | 397 | # Build Results of an ATL Project 398 | [Dd]ebugPS/ 399 | [Rr]eleasePS/ 400 | dlldata.c 401 | 402 | # .NET Core 403 | project.lock.json 404 | project.fragment.lock.json 405 | artifacts/ 406 | **/Properties/launchSettings.json 407 | 408 | *_i.c 409 | *_p.c 410 | *_i.h 411 | *.ilk 412 | *.meta 413 | *.obj 414 | *.pch 415 | *.pdb 416 | *.pgc 417 | *.pgd 418 | *.rsp 419 | *.sbr 420 | *.tlb 421 | *.tli 422 | *.tlh 423 | *.tmp_proj 424 | *.vspscc 425 | *.vssscc 426 | .builds 427 | *.pidb 428 | *.svclog 429 | *.scc 430 | 431 | # Chutzpah Test files 432 | _Chutzpah* 433 | 434 | # Visual C++ cache files 435 | ipch/ 436 | *.aps 437 | *.ncb 438 | *.opendb 439 | *.opensdf 440 | *.sdf 441 | *.cachefile 442 | *.VC.db 443 | *.VC.VC.opendb 444 | 445 | # Visual Studio profiler 446 | *.psess 447 | *.vsp 448 | *.vspx 449 | *.sap 450 | 451 | # TFS 2012 Local Workspace 452 | $tf/ 453 | 454 | # Guidance Automation Toolkit 455 | *.gpState 456 | 457 | # ReSharper is a .NET coding add-in 458 | _ReSharper*/ 459 | *.[Rr]e[Ss]harper 460 | *.DotSettings.user 461 | 462 | # JustCode is a .NET coding add-in 463 | .JustCode 464 | 465 | # TeamCity is a build add-in 466 | _TeamCity* 467 | 468 | # DotCover is a Code Coverage Tool 469 | *.dotCover 470 | 471 | # Visual Studio code coverage results 472 | *.coverage 473 | *.coveragexml 474 | 475 | # NCrunch 476 | _NCrunch_* 477 | .*crunch*.local.xml 478 | nCrunchTemp_* 479 | 480 | # MightyMoose 481 | *.mm.* 482 | AutoTest.Net/ 483 | 484 | # Web workbench (sass) 485 | .sass-cache/ 486 | 487 | # Installshield output folder 488 | [Ee]xpress/ 489 | 490 | # DocProject is a documentation generator add-in 491 | DocProject/buildhelp/ 492 | DocProject/Help/*.HxT 493 | DocProject/Help/*.HxC 494 | DocProject/Help/*.hhc 495 | DocProject/Help/*.hhk 496 | DocProject/Help/*.hhp 497 | DocProject/Help/Html2 498 | DocProject/Help/html 499 | 500 | # Click-Once directory 501 | publish/ 502 | 503 | # Publish Web Output 504 | *.[Pp]ublish.xml 505 | *.azurePubxml 506 | # TODO: Uncomment the next line to ignore your web deploy settings. 507 | # By default, sensitive information, such as encrypted password 508 | # should be stored in the .pubxml.user file. 509 | #*.pubxml 510 | *.pubxml.user 511 | *.publishproj 512 | 513 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 514 | # checkin your Azure Web App publish settings, but sensitive information contained 515 | # in these scripts will be unencrypted 516 | PublishScripts/ 517 | 518 | # NuGet Packages 519 | *.nupkg 520 | # The packages folder can be ignored because of Package Restore 521 | **/packages/* 522 | # except build/, which is used as an MSBuild target. 523 | !**/packages/build/ 524 | # Uncomment if necessary however generally it will be regenerated when needed 525 | #!**/packages/repositories.config 526 | # NuGet v3's project.json files produces more ignorable files 527 | *.nuget.props 528 | *.nuget.targets 529 | 530 | # Microsoft Azure Build Output 531 | csx/ 532 | *.build.csdef 533 | 534 | # Microsoft Azure Emulator 535 | ecf/ 536 | rcf/ 537 | 538 | # Windows Store app package directories and files 539 | AppPackages/ 540 | BundleArtifacts/ 541 | Package.StoreAssociation.xml 542 | _pkginfo.txt 543 | 544 | # Visual Studio cache files 545 | # files ending in .cache can be ignored 546 | *.[Cc]ache 547 | # but keep track of directories ending in .cache 548 | !*.[Cc]ache/ 549 | 550 | # Others 551 | ClientBin/ 552 | ~$* 553 | *~ 554 | *.dbmdl 555 | *.dbproj.schemaview 556 | *.jfm 557 | *.pfx 558 | *.publishsettings 559 | orleans.codegen.cs 560 | 561 | # Since there are multiple workflows, uncomment next line to ignore bower_components 562 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 563 | #bower_components/ 564 | 565 | # RIA/Silverlight projects 566 | Generated_Code/ 567 | 568 | # Backup & report files from converting an old project file 569 | # to a newer Visual Studio version. Backup files are not needed, 570 | # because we have git ;-) 571 | _UpgradeReport_Files/ 572 | Backup*/ 573 | UpgradeLog*.XML 574 | UpgradeLog*.htm 575 | 576 | # SQL Server files 577 | *.mdf 578 | *.ldf 579 | *.ndf 580 | 581 | # Business Intelligence projects 582 | *.rdl.data 583 | *.bim.layout 584 | *.bim_*.settings 585 | 586 | # Microsoft Fakes 587 | FakesAssemblies/ 588 | 589 | # GhostDoc plugin setting file 590 | *.GhostDoc.xml 591 | 592 | # Node.js Tools for Visual Studio 593 | .ntvs_analysis.dat 594 | node_modules/ 595 | 596 | # Typescript v1 declaration files 597 | typings/ 598 | 599 | # Visual Studio 6 build log 600 | *.plg 601 | 602 | # Visual Studio 6 workspace options file 603 | *.opt 604 | 605 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 606 | *.vbw 607 | 608 | # Visual Studio LightSwitch build output 609 | **/*.HTMLClient/GeneratedArtifacts 610 | **/*.DesktopClient/GeneratedArtifacts 611 | **/*.DesktopClient/ModelManifest.xml 612 | **/*.Server/GeneratedArtifacts 613 | **/*.Server/ModelManifest.xml 614 | _Pvt_Extensions 615 | 616 | # Paket dependency manager 617 | .paket/paket.exe 618 | paket-files/ 619 | 620 | # FAKE - F# Make 621 | .fake/ 622 | 623 | # JetBrains Rider 624 | .idea/ 625 | *.sln.iml 626 | 627 | # CodeRush 628 | .cr/ 629 | 630 | # Python Tools for Visual Studio (PTVS) 631 | *.pyc 632 | 633 | # Cake - Uncomment if you are using it 634 | # tools/** 635 | # !tools/packages.config 636 | 637 | # Telerik's JustMock configuration file 638 | *.jmconfig 639 | 640 | # BizTalk build output 641 | *.btp.cs 642 | *.btm.cs 643 | *.odx.cs 644 | *.xsd.cs 645 | 646 | ### VisualStudio Patch ### 647 | # By default, sensitive information, such as encrypted password 648 | # should be stored in the .pubxml.user file. 649 | 650 | # End of https://www.gitignore.io/api/go,java,ruby,python,eclipse,intellij,notepadpp,sublimetext,visualstudio,visualstudiocode --------------------------------------------------------------------------------