Object
This library provides a Ruby interface to the Nmap Security Scanner and its XML formatted scan data. It can run Nmap and parse its XML output directly from the scan, parse a file or string of XML scan data, or parse XML scan data from an object via its read() method. This information is presented in an easy-to-use and intuitive fashion for further storage and manipulation.
Note that while Anthony Persaud’s Perl Nmap::Parser was certainly an inspiration when designing this library, there are a number of distinguishing characteristics. Very briefly, this library contains more classes, many more methods, and has blocks extensively available.
The Nmap Security Scanner is an awesome utility written and maintained by Fyodor (fyodor(a)insecure.org). Its main function is port scanning, but it also has service and operating system detection, its own scripting engine and a whole lot more. One of its many available output formats is XML, which allows machines to handle all of the information instead of us slowly sifting through tons of output.
Depending on the data type, unavailable information is presented differently:
All information available as arrays are presented via methods. These methods not only return the array, but they also yield each element to a block if one is given.
Nmap::Parser | + Session <- Scan session information | + Host <- General host information | + ExtraPorts <- Ports consolidated in an "ignored" state | + Port <- General port information | | | + Service <- Port Service information | + Script <- NSE Script information (both host and port) | + Times <- Timimg information (round-trip time, etc) | + Traceroute <- General Traceroute information | | | + Hop <- Individual Hop information | + OS <- OS Detection information | + OSClass <- OS Class information | + OSMatch <- OS Match information
There are two ways to go about getting a new Parser object and actually parsing Nmap’s XML output:
This method is not limited to only String objects, but rather any object which responsds to to_str().
require 'nmap/parser' parser = Nmap::Parser.new parser.parsestring(xml)
or
parser = Nmap::Parser.parsestring(xml)
require 'nmap/parser' parser = Nmap::Parser.parsefile("log.xml")
This method can read from any object responding to a read() method that returns a String (or something else responding to to_str())
require 'nmap/parser' parser = Nmap::Parser.parseread($stdin)
This is the only Parser method that requires Nmap to be available.
require 'nmap/parser' parser = Nmap::Parser.parsescan("sudo nmap", "-sVC 192.168.1.0/24")
To use a callback you create a new Parser object and register a proc or method to call each time a new host is parsed, as soon as it’s parsed. The callback is then run in a new thread and is passed the newly created Nmap::Parser::Host object.
require 'nmap/parser' callback = proc do |host| return if host.status != "up" puts "Found #{host.addr}" end parser = Nmap::Parser.new(:callback => callback) parser.parsefile("nmaplog.xml") # Found 192.168.10.1 # Found 192.168.10.2 # Found 192.168.10.7 # [...]
After printing a little session information, this example will cycle through all of the up hosts, printing state and service information on the open TCP and UDP ports. See the examples directory that comes with this library for more examples.
puts "Nmap args: #{parser.session.scan_args}" puts "Runtime: #{parser.session.scan_time} seconds" puts parser.hosts("up") do |host| puts "#{host.addr} is up:" puts [:tcp, :udp].each do |type| host.getports(type, "open") do |port| srv = port.service puts "Port ##{port.num}/#{port.proto} is open (#{port.reason})" puts "\tService: #{srv.name}" if srv.name puts "\tProduct: #{srv.product}" if srv.product puts "\tVersion: #{srv.version}" if srv.version puts end end puts end
Author & Maintainer:
Contributors (in chronological order of first contribution):
Thanks a lot for taking the time and helping out, everybody!
For information on what each contributor actually did, please take a look at the project’s ChangeLog and Subversion logs.
Creates a fresh Parser object, taking a hash of options as an optional argument. Use the instance parsing methods to read in the XML and parse the data into the available classes.
Returns the new Nmap::Parser object and yields it to a block if one is given
# File lib/nmap/parser.rb, line 538 def initialize(opts = {}) # :yields: parser @hosts = [] @fresh = true opts.keys.each do |key| begin send("option_#{key}", opts[key]) rescue NoMethodError end end yield self if block_given? end
Returns a new Parser object with the following characteristics:
* rawxml = nil * session = nil * contains hosts from both operands. If any of the hosts in the first operand are also in the second (as determined by comparing host.addr information), the duplicate hosts from the second one are not available.
# File lib/nmap/parser.rb, line 446 def +(pa) return nil unless self.class == pa.class n = Nmap::Parser.new n.rawxml = nil n.session = nil [ self.hosts, pa.hosts ].each do |h| n.addhosts(h) end n end
This operator simply compares the rawxml members
# File lib/nmap/parser.rb, line 435 def ==(pa) @rawxml == pa.rawxml end
Returns a boolean value depending on whether this object is just a combination of others (e.g. using +)
# File lib/nmap/parser.rb, line 459 def combination? rawxml.nil? and session.nil? and not @fresh end
Deletes host with the specified IP address or hostname hostip
Calling this method from inside of a block given to a method like hosts() or get_ips() may lead to adverse effects.
# File lib/nmap/parser.rb, line 409 def del_host(hostip) @hosts.delete_if do |host| host.addr == hostip or host.hostname == hostip end end
Returns an array of IPs scanned and yields them each to a block if one is given
If an argument is given, only hosts matching status are given
NOTE: Calling parser.get_ips(status).size can be very different than running parser.session.numhosts(status) because the information there and here are coming from different places in the XML. Nmap will not typically list individual hosts which it doesn’t know or assume are “up”.
# File lib/nmap/parser.rb, line 427 def get_ips(status = "") # :yields: host.addr hosts(status).map do |host| yield host.addr if block_given? host.addr end end
Returns a Host object for the host with the specified IP address or hostname hostip
# File lib/nmap/parser.rb, line 397 def host(hostip) @hosts.find do |host| host.addr == hostip or host.hostname == hostip end end
Returns an array of Host objects and yields them each to a block if one is given
If an argument is given, only hosts matching status are given
NOTE: Calling parser.hosts(status).size can be very different than running parser.session.numhosts(status) because the information there and here are coming from different places in the XML. Nmap will not typically list individual hosts which it doesn’t know or assume are “up”.
# File lib/nmap/parser.rb, line 386 def hosts(status = "") # :yields: host @hosts.map { |host| if status.empty? or host.status == status yield host if block_given? host end }.compact end
Read and parse the contents of the Nmap XML file filename
# File lib/nmap/parser.rb, line 320 def parsefile(filename) File.open(filename) { |f| parseread(f) } rescue raise $!.class, "Error parsing \"#{filename}\": #{$!}" end
Read and parse XML from obj. obj can be any object responding to a read() method that returns a String (or something else responding to to_str()). IO and File are just a couple of examples.
# File lib/nmap/parser.rb, line 311 def parseread(obj) if not obj.respond_to?(:read) raise TypeError, "Passed object must respond to read()" end parsestring(obj.read) end
Essentially runs “nmap -d args targets“
nmap is here to allow you to do things like:
parser.parsescan(“sudo ./nmap”, arguments, targets)
and still make it easy for me to inject the options for XML output and debugging.
args can’t contain arguments like -oA, -oX, etc. as these could interfere with Parser’s processing. If you need that other output, you could run Nmap yourself and just pass the -oX output to Parser. Or you could use rawxml to grab the XML from the scan and write it to a file, for example.
targets is an optional array of target specifications. It’s here only for convenience because you can also put any targets you want scanned in args (which is what I tend to do unless I happen to already have a collection of targets as an array).
# File lib/nmap/parser.rb, line 355 def parsescan(nmap, args, targets = []) if args =~ /\s-o|^-o/ raise ArgumentError, "Output option (-o*) passed to parsescan()" end # Enable debugging and XML; pass args and targets command = "#{nmap} -d -oX - #{args} #{targets.join(" ")}" begin # First try popen3() if it loaded successfully.. Open3.popen3(command) do |sin, sout, serr| parseread(sout) end rescue NameError # ..but fall back to popen() if not IO.popen(command) do |io| parseread(io) end end end
Read and parse a String (or something else responding to to_str()) of XML
# File lib/nmap/parser.rb, line 328 def parsestring(str) if not str.respond_to?(:to_str) raise TypeError, "XML data should be a String, or must respond to to_str()" end parse(str.to_str) end
Wrapper around the instance method’s functionality
Returns a new Nmap::Parser object and yields it to a block if one is given
# File lib/nmap/parser.rb, line 277
Wrapper around the instance method’s functionality
Returns a new Nmap::Parser object and yields it to a block if one is given
# File lib/nmap/parser.rb, line 283
Wrapper around the instance method’s functionality
Returns a new Nmap::Parser object and yields it to a block if one is given
# File lib/nmap/parser.rb, line 289
Wrapper around the instance method’s functionality
Returns a new Nmap::Parser object and yields it to a block if one is given
# File lib/nmap/parser.rb, line 295
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.