class Wmap::PortScanner

Port scanner class for the web application discovery and tracking

Constants

File_discovery_ports

Use default common web service port list for the discovery

Max_socket_timeout

set hard limit of socket time-out to 3 seconds to avoid performance penalty

Attributes

discovered_urls[R]
discovery_tcp_ports[RW]
http_timeout[RW]
max_parallel[RW]
socket_timeout[RW]
verbose[RW]

Public Class Methods

new(params = {}) click to toggle source

Set default instance variables

# File lib/wmap/port_scanner.rb, line 24
def initialize (params = {})
        @verbose=params.fetch(:verbose, false)
        @socket_timeout=params.fetch(:socket_timeout, 1500)
        @http_timeout=params.fetch(:http_timeout, 5000)
        @max_parallel=params.fetch(:max_parallel, 40)
        # Initialize the instance variables
        @discovery_tcp_ports=params.fetch(:discovery_tcp_ports, file_2_list(File_discovery_ports).map!{|x| x.to_i} )
        @discovered_urls=Hash.new
end

Public Instance Methods

count() click to toggle source

Count number of new found sites

# File lib/wmap/port_scanner.rb, line 189
def count
        return @discovered_urls.size
end
file_scan(file,num=@max_parallel)
Alias for: scan_file
load(file)
Alias for: load_target_file
pre_scan(host) click to toggle source

Pre-scan worker, to be used for network profiling to maximum the scan performance, for instance.

# File lib/wmap/port_scanner.rb, line 35
def pre_scan(host)
        puts "Perform pre-scan works on host: #{host}" if @verbose
        begin
                # Use the following formula to 'guess' the right network time-out threshold for the scanner
                nwk_to=Wmap::NetworkProfiler.new.profile(host)
                if (100 + nwk_to*2).to_i > Max_socket_timeout
                        @socket_timeout=Max_socket_timeout
                else
                        @socket_timeout=(100 + nwk_to*2).to_i
                end
                puts "Done with the pre-scan works: reset @socket_timeout to: #{@socket_timeout}" if @verbose
        rescue Exception => ee
                puts "Exception on method #{__method__} for #{host}: #{ee}" if @verbose
                return nil
        end
end
print()
print_discovered_urls() click to toggle source

Print out the summary report of discovered sites

Also aliased as: print
query(host)
Alias for: scan
scan(host) click to toggle source

Main worker method that run through the discovery ports list, check if any response to the HTTP request on the open ports, and finally return the findings in the URL format as an array

# File lib/wmap/port_scanner.rb, line 53
def scan (host)
        puts "Perform web service discovery on host: #{host}"
        begin
                pre_scan(host)
                urls=Array.new
                @discovery_tcp_ports.map do |port|
                        if tcp_port_open?(host,port)
                                url=host_2_url(host,port)
                                urls.push(url) unless url.nil?
                        end
                end
                if urls.empty?
                        puts "No web service detected. "
                else
                        urls.map do |url|
                                unless @discovered_urls.key?(url)
                                        @discovered_urls[url]=true
                                end
                        end
                        puts "Detected web service on host #{host}: #{urls}"
                end
                return urls
        rescue Exception => ee
                puts "Exception on method #{__method__}  for #{host}: #{ee}" if @verbose
                return nil
        end
end
Also aliased as: query
scan_file(file,num=@max_parallel) click to toggle source

Parallel scans on a list of CIDRs from the input file, return the findings as the website construct within an array

# File lib/wmap/port_scanner.rb, line 114
def scan_file(file,num=@max_parallel)
        puts "Start the parallel scans on the target file: #{file}"
        begin
                list=load_target_file(file)
                urls=scans(list,num)
        rescue Exception => ee
                puts "Error on method #{__method__}: #{ee}" if @verbose
                return nil
        end
        return urls
end
Also aliased as: file_scan
scans(targets,num=@max_parallel) click to toggle source

Parallel scanner - by utilizing fork manager 'parallel' to spawn numbers of child processes on multiple hosts/IPs simultaneously

# File lib/wmap/port_scanner.rb, line 83
def scans (targets,num=@max_parallel)
        all_urls=Array.new
        # 10/5/2013 add additional logic to eliminate invalid /duplicate target(s)
        targets = targets - ["", nil]
        if targets.size > 0
                puts "Start the parallel port scan on the target list:\n #{targets}"
                Parallel.map(targets.shuffle, :in_processes => num) { |target|
                        scan(target)
                }.each do |process|
                        if process.nil?
                                next
                        elsif process.empty?
                                #do nothing
                        else
                                process.map do |url|
                                        unless @discovered_urls.key?(url)
                                                @discovered_urls[url]=true
                                        end
                                end
                                all_urls+=process
                        end
                end
        end
        puts "Port scanning done successfully with the found web services: #{all_urls}"
        return all_urls
rescue Exception => ee
        puts "Exception on method #{__method__}: #{ee}" if @verbose
        return nil
end
tcp_port_open?(host,port) click to toggle source

A simple TCP port scanner. This is the basic element of the port scanner. Notice the default time-out is set by the default instance variable @socket_timeout

# File lib/wmap/port_scanner.rb, line 161
def tcp_port_open? (host,port)
        puts "Perform open port detection on: #{host}:#{port}, time-out: #{@socket_timeout} ms" if @verbose
        #@socket_timeout = socket_timeout
        timeo = @socket_timeout/1000.0                                                # change time-out unit from sec to ms
        begin
    if Net::Ping::TCP.new(host,port,timeo).ping
                        puts "Port open!" if @verbose
        return true
    else
                        puts "Port down." if @verbose
        return false
    end
        rescue Exception => ee
                puts "Exception on method #{__method__} for #{host}: #{ee}" if @verbose
                return false
        end
end

Private Instance Methods

load_target_file(file) click to toggle source

Prepare and load the target list from a target file

# File lib/wmap/port_scanner.rb, line 128
def load_target_file (file)
        puts "Preparing the discovery target file: #{file}" if @verbose
        begin
                targets=Array.new
                f=File.open(file,'r')
                f.each do |line|
                        line=line.chomp.strip
                        next if line.nil?
                        next if line.empty?
                        next if line =~ /^\s*#/
                        line=line.split(',')[0]
                        if is_cidr?(line)
                                ips=cidr_2_ips(line)
                                targets+=ips
                        elsif is_ip?(line) or is_fqdn?(line)
                                targets.push(line)
                        elsif is_url?(line)
                                host=url_2_host(line)
                                targets.push(host)
                        else
                                puts "Unknown entry in the seed file: #{line}"
                        end
                end
                f.close
                return targets
        rescue Exception => ee
                puts "Error on method #{__method__} on file #{file} exception: #{ee}" if @verbose
                return nil
        end
end
Also aliased as: load