NeXpose XML API 1.1 - Ruby Code

Document created by techeditor on Apr 9, 2011Last modified by techeditor on Oct 28, 2013
Version 24Show Document
  • View in full screen mode

Note - I'm not a Ruby expert, but I hope this is an adequate stab to get the ball rolling. Appologies if the code is poorly structured.

 

 

The external project r7api11-r on GitHub has been contributed by Ben Hamilton.

 

 

Straight into it then...

 

 

Include the libraries you will need

 

 

 1 # You will need to be able to utilize rubygems or have access to methods for performing a post/get to a secure website.
2 class Nexpose
3   require 'rubygems'
4   require 'cgi' # used to change html into text - handy on the irb command line.
5   #require 'net/http'
6   require 'net/https'
7   require 'libxml'
8   require 'pdf/writer' # optional but is handy for outputting your own reports.
9 end

 

 

Within the class define the location and credentials needed to access the api

 

 

1   def initialize(config_file=nil)
2     config_file = "config/nexpose.yml" if config_file.nil?
3     if File.exist?(config_file)
4       config = YAML.load(File.open(config_file))["server_config"]
5       #host = config["host"]
6       port = config["port"]
7       uri = config["uri"]
8       @username = config["username"]
9       @password = config["password"]
10       @host = config["host"].nil? ? "locahost" : h(config["host"])
11       @port = port.nil? ? "3780" : h(port.to_s).to_i
12       @uri = uri.nil? ? "/api/1.1/xml" : uri.split("/").inject([]) {|arr,x| arr << h(x)}.join("/")
13       @proto = config["protocol"].nil? ? "https" : h(config["protocol"])
14       @session_id = nil
15       @cookie = nil
16       @last_action = nil
17       @login_at = nil
18       @useragent = "XML API 1.1 for Ruby by Ben Hamilton v0.1"
19       @config = config_file
20     else
21       @session_id = nil
22       @config = Exception.new(%Q{Missing Configuration File.})
23     end
24   end
25 end

 

 

Config File

 

 

1 ---
2 server_config:
3   host: mynexposeserver.example.com
4   port: 3780
5   username: nancyboy
6   password: Tr@shT@!kNG
7   uri: /api/1.1/xml
8   target_engine: 1

 

 

Within the class create a method for sending XML to the service

 

 

1   def send_xml_request(xml)
2     xml_doc =  LibXML::XML::Document.string(xml)
3       connection = Net::HTTP.new(@host, @port)
4      if @proto == "https"
5         connection.use_ssl = true
6         connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
7       end
8
9       connection.start do |http|
10         headers = {
11           'Cookie' => @cookie || "",
12           'Content-Type' => 'text/xml',
13           'User-Agent' => @useragent
14         }
15         resp,data = http.post(%Q{#{@uri}},%Q{#{xml_doc}},headers)
16
17         @cookie = resp.response['set-cookie']
18         @last_action = Time.now
19         retval = LibXML::XML::Document.string(data)
20         return retval
21       end
22   end

 

 

Create a method to generate a sync-id

 

 

1   def sync_id
2     @login_time ||= DateTime.now.to_s
3     retval = "#{@login_time}-#{rand(100000)}"
4     return retval
5   end

 

 

Create a Login method

 

 

 1   def login
2     return Exception.new("Username and Passowrd Required") if (@username.nil? || @password.nil?)
3     retval = false
4     unless retval
5       xml = %Q{}{<LoginRequest sync-id="#{sync_id}" user-id="#{@username}" password="#{@password}" />}


6       puts "Logging In"
7       result = send_xml_request(xml) rescue Exception.new("Failed to send request")
8       return result unless result.is_a?(LibXML::XML::Document) # expect an xml result, but fail quickly if a non xml response is sent.
9       if result.root.attributes["success"].to_i == 1
10         puts "Logged In"
11         @session_id =  result.root.attributes["session-id"] # this is passed with each subsequent request
12         retval = true
13       else
14         puts "Failed to login"
15         retval = Exception.new("Failed: Incorrect Username/Password") # this is a big assumption and needs better error correction.
16       end
17     end
18     return retval
19   end

 

 

Create a method to get a list of sites

 

 

1   def site_listing
2     retval = login unless @session_id # this forces an automatic login and saves a step when calling the method from the command line.
3     return retval if retval.is_a? Exception
4
5     xml = %Q{<SiteListingRequest sync-id="#{sync_id}" session-id="#{@session_id}" />}


6     retval = send_xml_request(xml)
7     return retval
8   end

 

 

 

From here a Nexpose object can be instantiated and used to list all the sites on a specific Nexpose server.

 

 

 

1 scanner = Nexpose.new # the initialize function will pull config details from config/nexpose.yml unless another filename and path is specified
2 scanner.login
3 scanner.site_listing

Attachments

    Outcomes