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
Public Class Methods
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 number of new found sites
# File lib/wmap/port_scanner.rb, line 189 def count return @discovered_urls.size end
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 out the summary report of discovered sites
# File lib/wmap/port_scanner.rb, line 180 def print_discovered_urls puts "Print out port discovery results." if @verbose puts "Summary of Discovered Sites:" @discovered_urls.keys.sort.map { |x| puts x } puts "End of Summary." end
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
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
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
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
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