Class: Wmap::PortScanner

Inherits:
Object
  • Object
show all
Includes:
Utils
Defined in:
lib/wmap/port_scanner.rb

Overview

Port scanner class for the web application discovery and tracking

Constant Summary collapse

File_discovery_ports =

Use default common web service port list for the discovery

File.dirname(__FILE__)+'/../../settings/discovery_ports'
Max_socket_timeout =

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

3000

Constants included from Utils::UrlMagic

Utils::UrlMagic::Max_http_timeout, Utils::UrlMagic::User_agent

Constants included from Utils::DomainRoot

Utils::DomainRoot::File_ccsld, Utils::DomainRoot::File_cctld, Utils::DomainRoot::File_gtld, Utils::DomainRoot::File_tld

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Utils

#cidr_2_ips, #file_2_hash, #file_2_list, #get_nameserver, #get_nameservers, #host_2_ip, #host_2_ips, #is_cidr?, #is_fqdn?, #is_ip?, #list_2_file, #reverse_dns_lookup, #sort_ips, #valid_dns_record?, #zone_transferable?

Methods included from Utils::Logger

#wlog

Methods included from Utils::UrlMagic

#create_absolute_url_from_base, #create_absolute_url_from_context, #host_2_url, #is_site?, #is_ssl?, #is_url?, #landing_location, #make_absolute, #normalize_url, #open_page, #redirect_location, #response_code, #response_headers, #url_2_host, #url_2_path, #url_2_port, #url_2_site, #urls_on_same_domain?

Methods included from Utils::DomainRoot

#get_domain_root, #get_domain_root_by_ccsld, #get_domain_root_by_cctld, #get_domain_root_by_tlds, #get_sub_domain, #is_domain_root?, #print_ccsld, #print_cctld, #print_gtld

Constructor Details

#initialize(params = {}) ⇒ PortScanner

Set default instance variables



24
25
26
27
28
29
30
31
32
# 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

Instance Attribute Details

#discovered_urlsObject (readonly)

Returns the value of attribute discovered_urls.



16
17
18
# File 'lib/wmap/port_scanner.rb', line 16

def discovered_urls
  @discovered_urls
end

#discovery_tcp_portsObject

Returns the value of attribute discovery_tcp_ports.



15
16
17
# File 'lib/wmap/port_scanner.rb', line 15

def discovery_tcp_ports
  @discovery_tcp_ports
end

#http_timeoutObject

Returns the value of attribute http_timeout.



15
16
17
# File 'lib/wmap/port_scanner.rb', line 15

def http_timeout
  @http_timeout
end

#max_parallelObject

Returns the value of attribute max_parallel.



15
16
17
# File 'lib/wmap/port_scanner.rb', line 15

def max_parallel
  @max_parallel
end

#socket_timeoutObject

Returns the value of attribute socket_timeout.



15
16
17
# File 'lib/wmap/port_scanner.rb', line 15

def socket_timeout
  @socket_timeout
end

#verboseObject

Returns the value of attribute verbose.



15
16
17
# File 'lib/wmap/port_scanner.rb', line 15

def verbose
  @verbose
end

Instance Method Details

#countObject

Count number of new found sites



189
190
191
# File 'lib/wmap/port_scanner.rb', line 189

def count
	return @discovered_urls.size
end

#pre_scan(host) ⇒ Object

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



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 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



180
181
182
183
184
185
# 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

#scan(host) ⇒ Object Also known as: query

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



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# 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

#scan_file(file, num = @max_parallel) ⇒ Object Also known as: file_scan

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



114
115
116
117
118
119
120
121
122
123
124
# 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

#scans(targets, num = @max_parallel) ⇒ Object

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



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# 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) ⇒ Boolean

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

Returns:

  • (Boolean)


161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# 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