Parent

Nmap::Parser

What Is This Library For?

This library provides a Ruby interface to Nmap's scan data. It can run Nmap and parse its XML output directly from the scan, parse a file containing the XML data from a separate scan, parse a String of XML data from a scan, or parse XML data from an object via its read() method. This information is presented in an easy-to-use and intuitive fashion for storage and manipulation.

Keep in mind that this is not just some Ruby port of Anthony Persaud's Perl Nmap::Parser! There are more classes, many different methods, and blocks are extensively available.

The Nmap Security Scanner is an awesome program written and maintained by Fyodor <fyodor@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.

Conventions

Depending on the data type, unavailable information is presented differently:

- Arrays are empty
- Non-arrays are nil, unless it's a method that returns the size of one of
  the previously mentioned empty arrays.  In this case they still return the
  size (which would be 0).

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.

Module Hierarchy

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

Parsing XML Data Already Available

require 'nmap/parser'

parser = Nmap::Parser.parsestring(xml) # String of XML
parser = Nmap::Parser.new(xml) # Same thing

Reading and Parsing from a File

require 'nmap/parser'

parser = Nmap::Parser.parsefile("log.xml")

Reading and Parsing from an Object

This method can read from any object that responds to a read() method that returns a String.

require 'nmap/parser'

parser = Nmap::Parser.parseread($stdin)

Scanning and Parsing

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")

Actually Doing Something

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 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

        host.tcp_ports("open") do |port|
                srv = port.service

                puts "Port ##{port.num}/tcp 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

        puts
end

Attributes

rawxml[R]

Holds the raw XML output from Nmap

session[R]

Session object for this scan

Public Class Methods

new(xml) click to toggle source
# File lib/nmap/parser.rb, line 319
def initialize(xml) # :yields: parser
        if not xml.is_a?(String)
                raise "Must be passed a String (got #{xml.class})"
        end

        parse(xml)

        yield self if block_given?
end
parsefile(filename) click to toggle source

Read and parse the contents of the Nmap XML file filename

Returns a new Nmap::Parser object, and passes it to a block if one is given

# File lib/nmap/parser.rb, line 192
def self.parsefile(filename) # :yields: parser
        begin
                File.open(filename) { |f|
                        parseread(f) { |p| yield p if block_given? }
                }
        rescue
                raise "Error parsing \"#{filename}\": #{$!}"
        end
end
parseread(obj) click to toggle source

Read and parse XML from the obj. obj can be any object type that responds to a read() method that returns a String. IO and File are just a couple of examples.

Returns a new Nmap::Parser object, and passes it to a block if one is given

# File lib/nmap/parser.rb, line 174
def self.parseread(obj) # :yields: parser
        if not obj.respond_to?("read")
                raise "Passed object must respond to read()"
        end

        r = obj.read

        if not r.is_a?(String)
                raise "Passed object's read() must return a String (got #{r.class})"
        end

        new(r) { |p| yield p if block_given? }
end
parsescan(nmap, args, targets = []) click to toggle source

Runs "nmap -d args targets"; returns a new Nmap::Parser object, and passes it to a block if one is given.

nmap is here to allow you to do things like:

parser = Nmap::Parser.parsescan("sudo ./nmap", ....)

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 can interfere with Parser's processing. If you need that other output, just run Nmap yourself and pass -oX output to Parser via new. Or, you can use rawxml to grab the whole XML (as a String) and save it to a different file.

targets is an array of targets which will be split and appended to the command. It's optional and only for convenience because you can put any targets you want scanned in args.

# File lib/nmap/parser.rb, line 229
def self.parsescan(nmap, args, targets = []) # :yields: parser
        if args =~ /[^-]-o|^-o/
                raise "Output option (-o*) passed to parsescan()"
        end

        # Enable debugging, give us our XML output, pass args
        command = nmap + " -d -oX - " + args + " "

        command += targets.join(" ") if targets.any?

        p = nil

        begin
                # First try popen3() if it loaded successfully..
                Open3.popen3(command) do |sin, sout, serr|
                        p = parseread(sout)
                end
        rescue NameError
                # ..but fall back to popen() if not
                IO.popen(command) do |io|
                        p = parseread(io)
                end
        end

        yield p if block_given?

        p
end
parsestring(str) click to toggle source

Read and parse the String of XML. Currently an alias for new().

Returns a new Nmap::Parser object, and passes it to a block if one is given

# File lib/nmap/parser.rb, line 206
def self.parsestring(str) # :yields: parser
        new(str) { |p| yield p if block_given? }
end

Public Instance Methods

==(parser) click to toggle source

This operator compares the rawxml members

# File lib/nmap/parser.rb, line 313
def ==(parser)
        @rawxml == parser.rawxml
end
del_host(hostip) click to toggle source

Deletes host with the specified IP address or hostname hostip

Note: From inside of a block given to a method like hosts() or get_ips(), calling this method on a host passed to the block may lead to adverse effects:

parser.hosts { |h| puts h.addr; parser.del_host(h) } # Don't do this!

# File lib/nmap/parser.rb, line 292
def del_host(hostip)
        @hosts.delete_if do |host|
                host.addr == hostip or host.hostname == hostip
        end
end
Also aliased as: delete_host
delete_host(hostip) click to toggle source
Alias for: del_host
get_host(hostip) click to toggle source
Alias for: host
get_ips(status = "") click to toggle source

Returns an array of IPs scanned, and passes them each to a block if one is given

If an argument is given, only hosts matching status are given

# File lib/nmap/parser.rb, line 304
def get_ips(status = "") # :yields: host.addr
        ips = hosts(status).map { |h| h.addr }

        ips.each { |ip| yield host.addr } if block_given?

        ips
end
host(hostip) click to toggle source

Returns a Host object for the host with the specified IP address or hostname hostip

# File lib/nmap/parser.rb, line 277
def host(hostip)
        @hosts.find do |host|
                host.addr == hostip or host.hostname == hostip
        end
end
Also aliased as: get_host
hosts(status = "") click to toggle source

Returns an array of Host objects, and passes them each to a block if one is given

If an argument is given, only hosts matching status are given

# File lib/nmap/parser.rb, line 262
def hosts(status = "") # :yields: host
        shosts = []

        @hosts.each do |host|
                if status.empty? or host.status == status
                        shosts << host
                        yield host if block_given?
                end
        end

        shosts
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.