ruby-nmap 0.10.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.document +1 -0
- data/.editorconfig +11 -0
- data/.github/workflows/ruby.yml +31 -0
- data/ChangeLog.md +118 -71
- data/Gemfile +11 -5
- data/LICENSE.txt +1 -1
- data/README.md +88 -50
- data/Rakefile +5 -0
- data/UPGRADING.md +47 -0
- data/gemspec.yml +5 -5
- data/lib/nmap/command.rb +765 -0
- data/lib/nmap/version.rb +1 -1
- data/lib/nmap/xml/address.rb +38 -0
- data/lib/nmap/xml/cpe/url.rb +80 -0
- data/lib/nmap/xml/cpe.rb +47 -0
- data/lib/nmap/xml/hop.rb +22 -0
- data/lib/nmap/xml/host.rb +546 -0
- data/lib/nmap/xml/host_script.rb +26 -0
- data/lib/nmap/xml/hostname.rb +44 -0
- data/lib/nmap/xml/ip_id_sequence.rb +26 -0
- data/lib/nmap/xml/os.rb +131 -0
- data/lib/nmap/xml/os_class.rb +86 -0
- data/lib/nmap/xml/os_match.rb +22 -0
- data/lib/nmap/xml/port.rb +114 -0
- data/lib/nmap/xml/postscript.rb +26 -0
- data/lib/nmap/xml/prescript.rb +26 -0
- data/lib/nmap/xml/run_stat.rb +22 -0
- data/lib/nmap/xml/scan.rb +38 -0
- data/lib/nmap/xml/scan_task.rb +55 -0
- data/lib/nmap/xml/scanner.rb +22 -0
- data/lib/nmap/xml/script.rb +110 -0
- data/lib/nmap/xml/scripts.rb +33 -0
- data/lib/nmap/xml/sequence.rb +52 -0
- data/lib/nmap/xml/service.rb +172 -0
- data/lib/nmap/xml/status.rb +22 -0
- data/lib/nmap/xml/tcp_sequence.rb +48 -0
- data/lib/nmap/xml/tcp_ts_sequence.rb +26 -0
- data/lib/nmap/xml/traceroute.rb +73 -0
- data/lib/nmap/xml/uptime.rb +22 -0
- data/lib/nmap/xml.rb +31 -44
- data/spec/command_spec.rb +726 -0
- data/spec/fixtures/down_host_scan.xml +16 -0
- data/spec/{address_spec.rb → xml/address_spec.rb} +2 -2
- data/spec/{cpe → xml/cpe}/url_spec.rb +1 -1
- data/spec/{cpe_examples.rb → xml/cpe_examples.rb} +1 -1
- data/spec/{hop_spec.rb → xml/hop_spec.rb} +2 -2
- data/spec/{host_script_spec.rb → xml/host_script_spec.rb} +2 -2
- data/spec/{host_spec.rb → xml/host_spec.rb} +8 -8
- data/spec/{hostname_spec.rb → xml/hostname_spec.rb} +2 -2
- data/spec/{ip_id_sequence_spec.rb → xml/ip_id_sequence_spec.rb} +3 -3
- data/spec/{os_class_spec.rb → xml/os_class_spec.rb} +3 -3
- data/spec/{os_match_spec.rb → xml/os_match_spec.rb} +2 -2
- data/spec/{os_spec.rb → xml/os_spec.rb} +3 -3
- data/spec/{port_spec.rb → xml/port_spec.rb} +4 -5
- data/spec/{postscript_spec.rb → xml/postscript_spec.rb} +2 -2
- data/spec/{prescript_spec.rb → xml/prescript_spec.rb} +2 -2
- data/spec/{run_stat_spec.rb → xml/run_stat_spec.rb} +2 -2
- data/spec/{scan_spec.rb → xml/scan_spec.rb} +2 -2
- data/spec/{scan_task_spec.rb → xml/scan_task_spec.rb} +6 -6
- data/spec/{scanner_spec.rb → xml/scanner_spec.rb} +3 -3
- data/spec/xml/script_spec.rb +137 -0
- data/spec/xml/scripts_examples.rb +19 -0
- data/spec/{sequence_examples.rb → xml/sequence_examples.rb} +1 -0
- data/spec/{service_spec.rb → xml/service_spec.rb} +31 -5
- data/spec/{status_spec.rb → xml/status_spec.rb} +2 -2
- data/spec/{tcp_sequence_spec.rb → xml/tcp_sequence_spec.rb} +3 -3
- data/spec/{tcp_ts_sequence_spec.rb → xml/tcp_ts_sequence_spec.rb} +3 -3
- data/spec/{traceroute_spec.rb → xml/traceroute_spec.rb} +3 -3
- data/spec/{uptime_spec.rb → xml/uptime_spec.rb} +2 -2
- data/spec/xml_spec.rb +73 -44
- metadata +72 -66
- data/.travis.yml +0 -16
- data/lib/nmap/address.rb +0 -34
- data/lib/nmap/cpe/url.rb +0 -78
- data/lib/nmap/cpe.rb +0 -45
- data/lib/nmap/hop.rb +0 -20
- data/lib/nmap/host.rb +0 -587
- data/lib/nmap/host_script.rb +0 -18
- data/lib/nmap/hostname.rb +0 -42
- data/lib/nmap/ip_id_sequence.rb +0 -24
- data/lib/nmap/os.rb +0 -127
- data/lib/nmap/os_class.rb +0 -82
- data/lib/nmap/os_match.rb +0 -18
- data/lib/nmap/port.rb +0 -110
- data/lib/nmap/postscript.rb +0 -16
- data/lib/nmap/prescript.rb +0 -16
- data/lib/nmap/program.rb +0 -102
- data/lib/nmap/run_stat.rb +0 -20
- data/lib/nmap/scan.rb +0 -34
- data/lib/nmap/scan_task.rb +0 -53
- data/lib/nmap/scanner.rb +0 -18
- data/lib/nmap/scripts.rb +0 -71
- data/lib/nmap/sequence.rb +0 -50
- data/lib/nmap/service.rb +0 -170
- data/lib/nmap/status.rb +0 -18
- data/lib/nmap/task.rb +0 -387
- data/lib/nmap/tcp_sequence.rb +0 -46
- data/lib/nmap/tcp_ts_sequence.rb +0 -22
- data/lib/nmap/traceroute.rb +0 -71
- data/lib/nmap/uptime.rb +0 -20
- data/spec/scripts_examples.rb +0 -35
- data/spec/task_spec.rb +0 -150
data/lib/nmap/command.rb
ADDED
@@ -0,0 +1,765 @@
|
|
1
|
+
require 'command_mapper/command'
|
2
|
+
|
3
|
+
module Nmap
|
4
|
+
#
|
5
|
+
# ## Nmap options:
|
6
|
+
#
|
7
|
+
# ### Target Specifications:
|
8
|
+
#
|
9
|
+
# * `-iL path/to/file` - `nmap.target_file = "path/to/file"`
|
10
|
+
# * `-iR 10` - `nmap.random_targets = 10`
|
11
|
+
# * `--exclude host1 --exclude host2` - `nmap.exclude = ["host1", "host2"`
|
12
|
+
# * `--excludefile path/to/file` - `nmap.exclude_file = "path/to/file"`
|
13
|
+
#
|
14
|
+
# ### Host Discovery:
|
15
|
+
#
|
16
|
+
# * `-sL` - `nmap.list = true`
|
17
|
+
# * `-sn` - `nmap.ping = true`
|
18
|
+
# * `-Pn` - `nmap.skip_discovery = true`
|
19
|
+
# * `-PS` - `nmap.syn_discovery = [20..80, 443]`
|
20
|
+
# * `-PA` - `nmap.ack_discovery = [20..80, 443]`
|
21
|
+
# * `-PU` - `nmap.udp_discovery = [20..80, 443]`
|
22
|
+
# * '-PY' - `nmap.sctp_init_ping = [20..80, 443]`
|
23
|
+
# * `-PE` - `nmap.icmp_echo_discovery = true`
|
24
|
+
# * `-PP` - `nmap.icmp_timestamp_discovery = true`
|
25
|
+
# * `-PM` - `nmap.icmp_netmask_discovery = true`
|
26
|
+
# * `-PO` - `nmap.ip_ping = [1, 2, 3, 4, ...]`
|
27
|
+
# * `-PR` - `nmap.arp_ping = true`
|
28
|
+
# * `--traceroute` - `nmap.traceroute = true`
|
29
|
+
# * `-n` - `nmap.disable_dns = true`
|
30
|
+
# * `-R` - `nmap.enable_dns = true`
|
31
|
+
# * `--resolve-all` - `nmap.resolve_all = true`
|
32
|
+
# * `--unique` - `nmap.unique = true`
|
33
|
+
# * `--dns-servers nameserver1,nameserver2` - `nmap.dns_servers = ["nameserver1", "nameserver2"]`
|
34
|
+
# * `--systems-dns` - `nmap.systems_dns = true`
|
35
|
+
#
|
36
|
+
# ### Port Scanning Techniques:
|
37
|
+
#
|
38
|
+
# * `-sS` - `nmap.syn_scan = true`
|
39
|
+
# * `-sT` - `nmap.connect_scan = true`
|
40
|
+
# * `-sU` - `nmap.udp_scan = true`
|
41
|
+
# * `-sY` - `nmap.sctp_init_scan = true`
|
42
|
+
# * `-sN` - `nmap.null_scan = true`
|
43
|
+
# * `-sF` - `nmap.fin_scan = true`
|
44
|
+
# * `-sX` - `nmap.xmas_scan = true`
|
45
|
+
# * `-sA` - `nmap.ack_scan = true`
|
46
|
+
# * `-sW` - `nmap.window_scan = true`
|
47
|
+
# * `-sM` - `nmap.maimon_scan = true`
|
48
|
+
# * `--scanflags` - `nmap.scan_flags = {syn: true, ack: true, rst: true}` / `nmap.scan_flags = [:syn, :ack, :rst]` / `nmap.scan_flags = 9` / `nmap.scan_flags = "SYNACKRST"`
|
49
|
+
# * `-sZ` - `nmap.sctp_cookie_echo_scan = true`
|
50
|
+
# * `-sI zombiehost:probeport` - `nmap.idle_scan = "zombiehost:probeport"`
|
51
|
+
# * `-sO` - `nmap.ip_scan = true`
|
52
|
+
# * `-b ftp.relay-host.com` - `nmap.ftp_bounce_scan = "ftp.relay-host.com"`
|
53
|
+
#
|
54
|
+
# ### Port Specification and Scan Order:
|
55
|
+
#
|
56
|
+
# * `-p 22,80,443,8000-9000` - `nmap.ports = [22, 80, 443, 8000..9000]`
|
57
|
+
# * `--exclude-ports 1-20,1024-2000` - `nmap.exclude_ports = [1..20, 1024..2000]`
|
58
|
+
# * `-F` - `nmap.fast = true`
|
59
|
+
# * `-r` - `nmap.consecutively = true`
|
60
|
+
# * `--top-ports 10` - `nmap.top_ports = 10`
|
61
|
+
# * `--port-ratio 0.5` - `nmap.port_ratio = 0.5`
|
62
|
+
#
|
63
|
+
# ### Service/Version Detection:
|
64
|
+
#
|
65
|
+
# * `-sV` - `nmap.service_scan = true`
|
66
|
+
# * `--allports` - `nmap.all_ports = true`
|
67
|
+
# * `--version-intensity 9` - `nmap.version_intensity = 9`
|
68
|
+
# * `--version-light` - `nmap.version_light = true`
|
69
|
+
# * `--version-all` - `nmap.version_all = true`
|
70
|
+
# * `--version-trace` - `nmap.version_trace = true`
|
71
|
+
# * `-sR` - `nmap.rpc_scan = true`
|
72
|
+
#
|
73
|
+
# ### Script Scan:
|
74
|
+
#
|
75
|
+
# * `-sC` - `nmap.default_script = true`
|
76
|
+
# * `--script script1,script2,script3` - `nmap.script = ["script1", "script2", "script3"]`
|
77
|
+
# * `--script-args=arg1=value,arg2=value2` - `nmap.script_args = {arg1: `value1", arg2: "value2"}`
|
78
|
+
# * `--script-args-file path/to/file` - `nmap.script_args_file = "path/to/file"`
|
79
|
+
# * `--script-help script1,script2,script3` - `nmap.script_help = ["script1", "script2", "script3"]`
|
80
|
+
# * `--script-trace` - `nmap.script_trace = true`
|
81
|
+
# * `--script-updatedb` - `nmap.update_scriptdb = treu`
|
82
|
+
#
|
83
|
+
# ### OS Detection:
|
84
|
+
#
|
85
|
+
# * `-O` - `nmap.os_fingerprint = true`
|
86
|
+
# * `--osscan-limit` - `nmap.limit_os_scan = true`
|
87
|
+
# * `--osscan-guess` - `nmap.max_os_scan = true`
|
88
|
+
#
|
89
|
+
# ### Timing and Performance:
|
90
|
+
#
|
91
|
+
# * `--min-hostgroup 42` - `nmap.min_host_group = 42`
|
92
|
+
# * `--max-hostgroup 42` - `nmap.max_host_group = 42`
|
93
|
+
# * `--min-parallelism 42` - `nmap.min_parallelism = 42`
|
94
|
+
# * `--max-parallelism 42` - `nmap.max_parallelism = 42`
|
95
|
+
# * `--min-rtt-timeout 100ms` - `nmap.min_rtt_timeout = "100ms"`
|
96
|
+
# * `--max-rtt-timeout 500ms` - `nmap.max_rtt_timeout = "500ms"`
|
97
|
+
# * `--initial-rtt-timeout 100ms` - `nmap.initial_rtt_timeout = "100ms"`
|
98
|
+
# * `--max-retries 4` - `nmap.max_retries = 4`
|
99
|
+
# * `--host-timeout 10s` - `nmap.host_timeout = "10s"`
|
100
|
+
# * `--script-timeout 10s` - `nmap.script_timeout = "10s"`
|
101
|
+
# * `--scan-delay 1s` - `nmap.scan_delay = "1s"`
|
102
|
+
# * `--max-scan-delay 42s` - `nmap.max_scan_delay = "42s"`
|
103
|
+
# * `--min-rate 10` - `nmap.min_rate = 10`
|
104
|
+
# * `--max-rate 100` - `nmap.max_rate = 100`
|
105
|
+
# * `--defeat-rst-ratelimit` - `nmap.defeat_rst_ratelimit = true`
|
106
|
+
# * `--defeat-icmp-ratelimit` - `nmap.defeat_icmp_ratelimit = true`
|
107
|
+
# * `--nsock-engine kqueue` - `nmap.nsock_engine = :kqueue`
|
108
|
+
# * `-T polite` - `nmap.timing_template = :polite`
|
109
|
+
# * `-T0` - `nmap.paranoid_timing = true`
|
110
|
+
# * `-T1` - `nmap.sneaky_timing = true`
|
111
|
+
# * `-T2` - `nmap.polite_timing = true`
|
112
|
+
# * `-T3` - `nmap.normal_timing = true`
|
113
|
+
# * `-T4` - `nmap.aggressive_timing = true`
|
114
|
+
# * `-T5` - `nmap.insane_timing = true`
|
115
|
+
#
|
116
|
+
# ### Firewall/IDS Evasion and Spoofing:
|
117
|
+
#
|
118
|
+
# * `-f` - `nmap.packet_fragments = true`
|
119
|
+
# * `--mtu` - `nmap.mtu = true`
|
120
|
+
# * `-D decoy1,decoy2` - `nmap.decoys = ["decoy1", "decoy2"]`
|
121
|
+
# * `-S 8.8.8.8` - `nmap.spoof = "8.8.8.8"`
|
122
|
+
# * `-e eth0` - `nmap.interface = "eth0"`
|
123
|
+
# * `-g 1024` - `nmap.source_port = 1024`
|
124
|
+
# * `--proxies proxy1,proxy2` - `nmap.proxies = ["proxy1", "proxy2"]`
|
125
|
+
# * `--data AABBCCDDEEFF` - `nmap.data = "AABBCCDDEEFF"`
|
126
|
+
# * `--data-string foobar` - `nmap.data_string = "foobar"`
|
127
|
+
# * `--data-length 42` - `nmap.data_length = 42`
|
128
|
+
# * `--ip-options T` - `nmap.ip_options = 'T'`
|
129
|
+
# * `--ttl 42` - `nmap.ttl = 42`
|
130
|
+
# * `--randomize-hosts` - `nmap.randomize_hosts = true`
|
131
|
+
# * `--spoof-mac XX:XX:XX:XX:XX:XX` - `nmap.spoof_mac = "XX:XX:XX:XX:XX:XX"`
|
132
|
+
# * `--badsum` - `nmap.bad_checksum = true`
|
133
|
+
# * `--adler32` - `nmap.sctp_adler32 = true`
|
134
|
+
#
|
135
|
+
# ### Output:
|
136
|
+
#
|
137
|
+
# * `-oN path/to/file` - `nmap.output_normal = "path/to/file"`
|
138
|
+
# * `-oX path/to/file` - `nmap.output_xml = "path/to/file"`
|
139
|
+
# * `-oS path/to/file` - `nmap.output_skiddie = "path/to/file"`
|
140
|
+
# * `-oG path/to/file` - `nmap.output_grepable = "path/to/file"`
|
141
|
+
# * `-oA path/to/basename` - `nmap.output_all = "path/to/basename"`
|
142
|
+
#
|
143
|
+
# ### Verbosity and Debugging:
|
144
|
+
#
|
145
|
+
# * `-v` - `nmap.verbose = true`
|
146
|
+
# * `-v3` - `nmap.verbose = 3`
|
147
|
+
# * `-vv` - `nmap.extra_verbose = true`
|
148
|
+
# * `-v0` - `nmap.quiet = true`
|
149
|
+
# * `-d` - `nmap.debug = true`
|
150
|
+
# * `-d9` - `nmap.debug = 9`
|
151
|
+
# * `--reason` - `nmap.show_reason = true`
|
152
|
+
# * `--stats-every 2s` - `nmap.stats_every = "2s"`
|
153
|
+
# * `--packet-trace` - `nmap.show_packets = true`
|
154
|
+
# * `--open` - `nmap.show_open_ports = true`
|
155
|
+
# * `--iflist` - `nmap.show_interfaces = true`
|
156
|
+
# * `--log-errors` - `nmap.show_log_errors = true`
|
157
|
+
#
|
158
|
+
# ### Miscellaneous Output:
|
159
|
+
#
|
160
|
+
# * `--append-output` - `nmap.append_output = true`
|
161
|
+
# * `--resume` - `nmap.resume = true`
|
162
|
+
# * `--stylesheet path/to/stylesheet.xsl` - `nmap.stylesheet = "path/to/stylesheet.xsl"`
|
163
|
+
# * `--webxml` - `nmap.webxml = true`
|
164
|
+
# * `--no-stylesheet` - `nmap.no_stylesheet = true`
|
165
|
+
#
|
166
|
+
# ### Misc:
|
167
|
+
#
|
168
|
+
# * `-6` - `nmap.ipv6 = true`
|
169
|
+
# * `-A` - `nmap.all = true`
|
170
|
+
# * `--datadir path/to/nmap/dir` - `nmap.nmap_datadir = "path/to/nmap/dir"`
|
171
|
+
# * `--servicedb path/to/services.txt` - `nmap.servicedb = "path/to/services.txt"`
|
172
|
+
# * `--versiondb path/to/versions.txt` - `nmap.versiondb = "path/to/versions.txt"`
|
173
|
+
# * `--send-eth` - `nmap.send_eth = true`
|
174
|
+
# * `--send-ip` - `nmap.send_ip = true`
|
175
|
+
# * `--privileged` - `nmap.privileged = true`
|
176
|
+
# * `--unprivileged` - `nmap.unprivileged = true`
|
177
|
+
# * `--release-memory` - `nmap.release_memory = true`
|
178
|
+
# * `--noninteractive` - `nmap.non_interactive = true`
|
179
|
+
# * `-V` - `nmap.version = true`
|
180
|
+
# * `-h` - `nmap.help = true`
|
181
|
+
#
|
182
|
+
# * `google.com 1.1.1.1 192.168.1-2.*` - `nmap.targets = ["google.com", "1.1.1.1", "192.168.1-2.*"]`
|
183
|
+
#
|
184
|
+
# @see http://nmap.org/book/man.html
|
185
|
+
#
|
186
|
+
class Command < CommandMapper::Command
|
187
|
+
|
188
|
+
#
|
189
|
+
# @api private
|
190
|
+
#
|
191
|
+
class Port < CommandMapper::Types::Num
|
192
|
+
|
193
|
+
PORT_NUMBER_REGEXP = /\d{1,5}/
|
194
|
+
|
195
|
+
SERVICE_NAME_REGEXP = /[A-Za-z0-9]+(?:[\/_-][A-Za-z0-9]+)*\*?/
|
196
|
+
|
197
|
+
PORT_REGEXP = /(?:#{PORT_NUMBER_REGEXP}|#{SERVICE_NAME_REGEXP})/
|
198
|
+
|
199
|
+
REGEXP = /\A#{PORT_REGEXP}\z/
|
200
|
+
|
201
|
+
#
|
202
|
+
# Initializes the port type.
|
203
|
+
#
|
204
|
+
def initialize
|
205
|
+
super(range: 1..65535)
|
206
|
+
end
|
207
|
+
|
208
|
+
#
|
209
|
+
# Validates the given value.
|
210
|
+
#
|
211
|
+
# @param [Object] value
|
212
|
+
#
|
213
|
+
# @return [true, (false, String)]
|
214
|
+
#
|
215
|
+
def validate(value)
|
216
|
+
case value
|
217
|
+
when String
|
218
|
+
case value
|
219
|
+
when /\A#{PORT_NUMBER_REGEXP}\z/
|
220
|
+
super(value)
|
221
|
+
when /\A#{SERVICE_NAME_REGEXP}\z/
|
222
|
+
return true
|
223
|
+
else
|
224
|
+
return [false, "must be a port number or service name (#{value.inspect})"]
|
225
|
+
end
|
226
|
+
else
|
227
|
+
super(value)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
#
|
232
|
+
# Formats the given value.
|
233
|
+
#
|
234
|
+
# @param [Integer, String] value
|
235
|
+
#
|
236
|
+
# @return [String]
|
237
|
+
#
|
238
|
+
def format(value)
|
239
|
+
case value
|
240
|
+
when String
|
241
|
+
value
|
242
|
+
else
|
243
|
+
super(value)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
#
|
250
|
+
# @api private
|
251
|
+
#
|
252
|
+
class PortRange < Port
|
253
|
+
|
254
|
+
PORT_RANGE_REGEXP = /(?:#{PORT_REGEXP}|#{PORT_REGEXP}?-#{PORT_REGEXP}?)/
|
255
|
+
|
256
|
+
REGEXP = /\A#{PORT_RANGE_REGEXP}\z/
|
257
|
+
|
258
|
+
#
|
259
|
+
# Validates the given value.
|
260
|
+
#
|
261
|
+
# @param [Object] value
|
262
|
+
#
|
263
|
+
# @return [true, (false, String)]
|
264
|
+
#
|
265
|
+
def validate(value)
|
266
|
+
case value
|
267
|
+
when Range
|
268
|
+
valid, message = super(value.begin)
|
269
|
+
|
270
|
+
unless valid
|
271
|
+
return [valid, message]
|
272
|
+
end
|
273
|
+
|
274
|
+
valid, message = super(value.end)
|
275
|
+
|
276
|
+
unless valid
|
277
|
+
return [valid, message]
|
278
|
+
end
|
279
|
+
|
280
|
+
return true
|
281
|
+
when String
|
282
|
+
unless value =~ REGEXP
|
283
|
+
return [false, "not a valid port range (#{value.inspect})"]
|
284
|
+
end
|
285
|
+
|
286
|
+
return true
|
287
|
+
else
|
288
|
+
super(value)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
#
|
293
|
+
# Formats the given value.
|
294
|
+
#
|
295
|
+
# @param [Range, Integer, String] value
|
296
|
+
#
|
297
|
+
# @return [String]
|
298
|
+
#
|
299
|
+
def format(value)
|
300
|
+
case value
|
301
|
+
when Range
|
302
|
+
"#{value.begin}-#{value.end}"
|
303
|
+
else
|
304
|
+
super(value)
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
end
|
309
|
+
|
310
|
+
#
|
311
|
+
# @api private
|
312
|
+
#
|
313
|
+
class PortRangeList < CommandMapper::Types::List
|
314
|
+
|
315
|
+
PORT_RANGE_REGEXP = PortRange::PORT_RANGE_REGEXP
|
316
|
+
|
317
|
+
REGEXP = /\A(?:[TUS]:)?#{PORT_RANGE_REGEXP}(?:,(?:[TUS]:)?#{PORT_RANGE_REGEXP})*\z/
|
318
|
+
|
319
|
+
#
|
320
|
+
# Initializes the port range list type.
|
321
|
+
#
|
322
|
+
def initialize
|
323
|
+
super(type: PortRange.new)
|
324
|
+
end
|
325
|
+
|
326
|
+
#
|
327
|
+
# Validates the given port range list value.
|
328
|
+
#
|
329
|
+
# @param [Object] value
|
330
|
+
#
|
331
|
+
# @return [true, (false, String)]
|
332
|
+
#
|
333
|
+
def validate(value)
|
334
|
+
case value
|
335
|
+
when Hash
|
336
|
+
if value.empty?
|
337
|
+
return [false, "cannot be empty"]
|
338
|
+
end
|
339
|
+
|
340
|
+
value.each do |protocol,ports|
|
341
|
+
unless PROTOCOL_LETTERS.has_key?(protocol)
|
342
|
+
return [false, "unknown protocol (#{protocol.inspect}) must be :tcp, :udp, or :sctp"]
|
343
|
+
end
|
344
|
+
|
345
|
+
valid, message = validate(ports)
|
346
|
+
|
347
|
+
unless valid
|
348
|
+
return [valid, message]
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
return true
|
353
|
+
when Range
|
354
|
+
@type.validate(value)
|
355
|
+
when String
|
356
|
+
unless value =~ REGEXP
|
357
|
+
return [false, "not a valid port range list (#{value.inspect})"]
|
358
|
+
end
|
359
|
+
|
360
|
+
return true
|
361
|
+
else
|
362
|
+
super(value)
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
# Mapping of protocol names to single letters used in port range syntax.
|
367
|
+
PROTOCOL_LETTERS = {
|
368
|
+
tcp: 'T',
|
369
|
+
udp: 'U',
|
370
|
+
sctp: 'S'
|
371
|
+
}
|
372
|
+
|
373
|
+
#
|
374
|
+
# Formats the given value.
|
375
|
+
#
|
376
|
+
# @param [Hash, Range, String, Integer] value
|
377
|
+
#
|
378
|
+
# @return [String]
|
379
|
+
#
|
380
|
+
def format(value)
|
381
|
+
case value
|
382
|
+
when Hash
|
383
|
+
# format a hash of protocols and port ranges
|
384
|
+
value.map { |protocol,ports|
|
385
|
+
letter = PROTOCOL_LETTERS.fetch(protocol)
|
386
|
+
|
387
|
+
"#{letter}:#{format(ports)}"
|
388
|
+
}.join(',')
|
389
|
+
when Range
|
390
|
+
# format an individual port range
|
391
|
+
@type.format(value)
|
392
|
+
when String
|
393
|
+
# pass strings directly through
|
394
|
+
value
|
395
|
+
else
|
396
|
+
super(value)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
end
|
401
|
+
|
402
|
+
#
|
403
|
+
# @api private
|
404
|
+
#
|
405
|
+
ProtocolList = PortRangeList
|
406
|
+
|
407
|
+
#
|
408
|
+
# @api private
|
409
|
+
#
|
410
|
+
class Time < CommandMapper::Types::Str
|
411
|
+
|
412
|
+
REGEXP = /\A\d+(?:h|m|s|ms)?\z/
|
413
|
+
|
414
|
+
#
|
415
|
+
# Validates a time value.
|
416
|
+
#
|
417
|
+
# @param [String, Integer] value
|
418
|
+
# The time value to validate.
|
419
|
+
#
|
420
|
+
# @return [true, (false, String)]
|
421
|
+
# Returns true if the value is considered valid, or false and a
|
422
|
+
# validation message if the value is not valid.
|
423
|
+
#
|
424
|
+
def validate(value)
|
425
|
+
case value
|
426
|
+
when Integer then true
|
427
|
+
else
|
428
|
+
valid, message = super(value)
|
429
|
+
|
430
|
+
unless valid
|
431
|
+
return [valid, message]
|
432
|
+
end
|
433
|
+
|
434
|
+
value = value.to_s
|
435
|
+
|
436
|
+
unless value =~ REGEXP
|
437
|
+
return [false, "must be a number and end with 'ms', 's', 'm', or 'h'"]
|
438
|
+
end
|
439
|
+
|
440
|
+
return true
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
end
|
445
|
+
|
446
|
+
#
|
447
|
+
# @api private
|
448
|
+
#
|
449
|
+
class HexString < CommandMapper::Types::Str
|
450
|
+
|
451
|
+
REGEXP = /\A(?:(?:0x)?[0-9A-F]+|(?:\\x[0-9A-F]{2})+)\z/
|
452
|
+
|
453
|
+
#
|
454
|
+
# Validates a hex string value.
|
455
|
+
#
|
456
|
+
# @param [String, #to_s] value
|
457
|
+
# The hex string value to validate.
|
458
|
+
#
|
459
|
+
# @return [true, (false, String)]
|
460
|
+
# Returns true if the value is considered valid, or false and a
|
461
|
+
# validation message if the value is not valid.
|
462
|
+
#
|
463
|
+
def validate(value)
|
464
|
+
valid, message = super(value)
|
465
|
+
|
466
|
+
unless valid
|
467
|
+
return [valid, message]
|
468
|
+
end
|
469
|
+
|
470
|
+
value = value.to_s
|
471
|
+
|
472
|
+
unless value =~ REGEXP
|
473
|
+
return [false, "must be of the format 0xAABBCCDDEEFF..., AABBCCDDEEFF..., or \\xAA\\xBB\\xCC\\xDD\\xEE\\xFF..."]
|
474
|
+
end
|
475
|
+
|
476
|
+
return true
|
477
|
+
end
|
478
|
+
|
479
|
+
end
|
480
|
+
|
481
|
+
#
|
482
|
+
# @api private
|
483
|
+
#
|
484
|
+
class ScanFlags < CommandMapper::Types::Str
|
485
|
+
|
486
|
+
FLAGS = {
|
487
|
+
urg: 'URG',
|
488
|
+
ack: 'ACK',
|
489
|
+
psh: 'PSH',
|
490
|
+
rst: 'RST',
|
491
|
+
syn: 'SYN',
|
492
|
+
fin: 'FIN'
|
493
|
+
}
|
494
|
+
|
495
|
+
REGEXP = /\A(?:\d+|(?:URG|ACK|PSH|RST|SYN|FIN)+)\z/
|
496
|
+
|
497
|
+
#
|
498
|
+
# Validates a scanflags value.
|
499
|
+
#
|
500
|
+
# @param [String, Hash{Symbol => Boolean}, #to_s] value
|
501
|
+
# The scanflags value to validate.
|
502
|
+
#
|
503
|
+
# @return [true, (false, String)]
|
504
|
+
# Returns true if the value is considered valid, or false and a
|
505
|
+
# validation message if the value is not valid.
|
506
|
+
#
|
507
|
+
def validate(value)
|
508
|
+
case value
|
509
|
+
when Hash
|
510
|
+
if value.empty?
|
511
|
+
return [false, "Hash value cannot be empty"]
|
512
|
+
end
|
513
|
+
|
514
|
+
unless value.keys.all? { |key| FLAGS.has_key?(key) }
|
515
|
+
return [false, "Hash must only contain the keys :urg, :ack, :psh, :rst, :syn, or :fin"]
|
516
|
+
end
|
517
|
+
|
518
|
+
unless value.values.all? { |value| value == nil || value == false || value == true }
|
519
|
+
return [false, "Hash must only contain the values true, false, or nil"]
|
520
|
+
end
|
521
|
+
|
522
|
+
return true
|
523
|
+
when Array
|
524
|
+
if value.empty?
|
525
|
+
return [false, "Array value cannot be empty"]
|
526
|
+
end
|
527
|
+
|
528
|
+
unless value.all? { |flag| FLAGS.has_key?(flag) }
|
529
|
+
return [false, "Array must only contain the values :urg, :ack, :psh, :rst, :syn, or :fin"]
|
530
|
+
end
|
531
|
+
|
532
|
+
return true
|
533
|
+
else
|
534
|
+
valid, message = super(value)
|
535
|
+
|
536
|
+
unless valid
|
537
|
+
return [valid, message]
|
538
|
+
end
|
539
|
+
|
540
|
+
value = value.to_s
|
541
|
+
|
542
|
+
unless value =~ REGEXP
|
543
|
+
return [false, "must only contain URG, ACK, PSH, RST, SYN, or FIN"]
|
544
|
+
end
|
545
|
+
|
546
|
+
return true
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
550
|
+
#
|
551
|
+
# Formats a scanflags value.
|
552
|
+
#
|
553
|
+
# @param [Hash{Symbol => Boolean}, Array<String>, #to_s] value
|
554
|
+
# The scanflags value to format.
|
555
|
+
#
|
556
|
+
# @return [String]
|
557
|
+
# The formatted scanflags value.
|
558
|
+
#
|
559
|
+
def format(value)
|
560
|
+
case value
|
561
|
+
when Hash
|
562
|
+
string = String.new
|
563
|
+
|
564
|
+
value.each do |key,value|
|
565
|
+
string << FLAGS[key] if value
|
566
|
+
end
|
567
|
+
|
568
|
+
return string
|
569
|
+
when Array
|
570
|
+
string = String.new
|
571
|
+
|
572
|
+
value.each do |flag|
|
573
|
+
string << FLAGS[flag]
|
574
|
+
end
|
575
|
+
|
576
|
+
return string
|
577
|
+
else
|
578
|
+
super(value)
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
582
|
+
end
|
583
|
+
|
584
|
+
command 'nmap' do
|
585
|
+
# TARGET SPECIFICATIONS:
|
586
|
+
option '-iL', name: :target_file, value: {type: InputFile.new}
|
587
|
+
option '-iR', name: :random_targets, value: {type: Num.new}
|
588
|
+
option '--exclude', name: :exclude, value: {type: List.new}
|
589
|
+
option '--excludefile', name: :exclude_file, value: {type: InputFile.new}
|
590
|
+
|
591
|
+
# HOST DISCOVERY:
|
592
|
+
option '-sL', name: :list
|
593
|
+
option '-sn', name: :ping
|
594
|
+
option '-Pn', name: :skip_discovery
|
595
|
+
option '-PS', name: :syn_discovery,
|
596
|
+
value_in_flag: true,
|
597
|
+
value: {type: PortRangeList.new, required: false}
|
598
|
+
option '-PA', name: :ack_discovery,
|
599
|
+
value_in_flag: true,
|
600
|
+
value: {type: PortRangeList.new, required: false}
|
601
|
+
option '-PU', name: :udp_discovery,
|
602
|
+
value_in_flag: true,
|
603
|
+
value: {type: PortRangeList.new, required: false}
|
604
|
+
option '-PY', name: :sctp_init_ping,
|
605
|
+
value_in_flag: true,
|
606
|
+
value: {type: PortRangeList.new, required: false}
|
607
|
+
option '-PE', name: :icmp_echo_discovery
|
608
|
+
option '-PP', name: :icmp_timestamp_discovery
|
609
|
+
option '-PM', name: :icmp_netmask_discovery
|
610
|
+
option '-PO', name: :ip_ping,
|
611
|
+
value_in_flag: true,
|
612
|
+
value: {type: ProtocolList.new, required: false}
|
613
|
+
option '-PR', name: :arp_ping
|
614
|
+
option '--traceroute', name: :traceroute
|
615
|
+
option '-n', name: :disable_dns
|
616
|
+
option '-R', name: :enable_dns
|
617
|
+
option '--resolve-all'
|
618
|
+
option '--unique'
|
619
|
+
option '--dns-servers', value: {type: List.new}
|
620
|
+
option '--system-dns'
|
621
|
+
|
622
|
+
# PORT SCANNING TECHNIQUES:
|
623
|
+
option '-sS', name: :syn_scan
|
624
|
+
option '-sT', name: :connect_scan
|
625
|
+
option '-sU', name: :udp_scan
|
626
|
+
option '-sY', name: :sctp_init_scan
|
627
|
+
option '-sN', name: :null_scan
|
628
|
+
option '-sF', name: :fin_scan
|
629
|
+
option '-sX', name: :xmas_scan
|
630
|
+
option '-sA', name: :ack_scan
|
631
|
+
option '-sW', name: :window_scan
|
632
|
+
option '-sM', name: :maimon_scan
|
633
|
+
option '--scanflags', name: :scan_flags, value: {type: ScanFlags.new}
|
634
|
+
option '-sZ', name: :sctp_cookie_echo_scan
|
635
|
+
option '-sI', name: :idle_scan, value: true
|
636
|
+
option '-sO', name: :ip_scan
|
637
|
+
option '-b', name: :ftp_bounce_scan, value: true
|
638
|
+
|
639
|
+
# PORT SPECIFICATION AND SCAN ORDER:
|
640
|
+
option '-p', name: :ports, value: {type: PortRangeList.new}
|
641
|
+
option '--exclude-ports', value: {type: PortRangeList.new}
|
642
|
+
option '-F', name: :fast
|
643
|
+
option '-r', name: :consecutively
|
644
|
+
option '--top-ports', value: {type: Num.new}
|
645
|
+
option '--port-ratio', value: {type: Dec.new(range: 0.0..1.0)}
|
646
|
+
|
647
|
+
# SERVICE/VERSION DETECTION:
|
648
|
+
option '-sV', name: :service_scan
|
649
|
+
option '--allports', name: :all_ports
|
650
|
+
option '--version-intensity', value: {type: Num.new(range: 0..9)}
|
651
|
+
option '--version-light'
|
652
|
+
option '--version-all'
|
653
|
+
option '--version-trace'
|
654
|
+
option '-sR', name: :rpc_scan
|
655
|
+
|
656
|
+
# SCRIPT SCAN:
|
657
|
+
option '-sC', name: :default_script
|
658
|
+
option '--script', value: {type: List.new}
|
659
|
+
option '--script-args', value: {type: KeyValueList.new}
|
660
|
+
option '--script-args-file', value: {type: InputFile.new}
|
661
|
+
option '--script-help', value: {type: List.new}
|
662
|
+
option '--script-trace'
|
663
|
+
option '--script-updatedb', name: :update_scriptdb
|
664
|
+
|
665
|
+
# OS DETECTION:
|
666
|
+
option '-O', name: :os_fingerprint
|
667
|
+
option '--osscan-limit', name: :limit_os_scan
|
668
|
+
option '--osscan-guess', name: :max_os_scan
|
669
|
+
option '--max-os-tries', name: :max_os_tries
|
670
|
+
|
671
|
+
# TIMING AND PERFORMANCE:
|
672
|
+
option '--min-hostgroup', name: :min_host_group, value: {type: Num.new}
|
673
|
+
option '--max-hostgroup', name: :max_host_group, value: {type: Num.new}
|
674
|
+
option '--min-parallelism', value: {type: Num.new}
|
675
|
+
option '--max-parallelism', value: {type: Num.new}
|
676
|
+
option '--min-rtt-timeout', value: {type: Time.new}
|
677
|
+
option '--max-rtt-timeout', value: {type: Time.new}
|
678
|
+
option '--initial-rtt-timeout', value: {type: Time.new}
|
679
|
+
option '--max-retries', value: {type: Num.new}
|
680
|
+
option '--host-timeout', value: {type: Time.new}
|
681
|
+
option '--script-timeout', value: {type: Time.new}
|
682
|
+
option '--scan-delay', value: {type: Time.new}
|
683
|
+
option '--max-scan-delay', value: {type: Time.new}
|
684
|
+
option '--min-rate', value: {type: Num.new}
|
685
|
+
option '--max-rate', value: {type: Num.new}
|
686
|
+
option '--defeat-rst-ratelimit'
|
687
|
+
option '--defeat-icmp-ratelimit'
|
688
|
+
option '--nsock-engine', value: {type: Enum[:iocp, :epoll, :kqueue, :poll, :select]}
|
689
|
+
option '-T', name: :timing_template,
|
690
|
+
value: {type: Enum[:paranoid, :sneaky, :polite, :normal, :aggressive, :insane]}
|
691
|
+
option '-T0', name: :paranoid_timing
|
692
|
+
option '-T1', name: :sneaky_timing
|
693
|
+
option '-T2', name: :polite_timing
|
694
|
+
option '-T3', name: :normal_timing
|
695
|
+
option '-T4', name: :aggressive_timing
|
696
|
+
option '-T5', name: :insane_timing
|
697
|
+
|
698
|
+
# FIREWALL/IDS EVASION AND SPOOFING:
|
699
|
+
option '-f', name: :packet_fragments
|
700
|
+
option '--mtu'
|
701
|
+
option '-D', name: :decoys, value: {type: List.new}
|
702
|
+
option '-S', name: :spoof, value: true
|
703
|
+
option '-e', name: :interface, value: true
|
704
|
+
option '-g', name: :source_port, value: {type: Port.new}
|
705
|
+
option '--proxies', value: {type: List.new}
|
706
|
+
option '--data', value: {type: HexString.new}
|
707
|
+
option '--data-string', value: true
|
708
|
+
option '--data-length', value: {type: Num.new}
|
709
|
+
option '--ip-options', value: true
|
710
|
+
option '--ttl', value: {type: Num.new}
|
711
|
+
option '--randomize-hosts'
|
712
|
+
option '--spoof-mac', value: true
|
713
|
+
option '--badsum', name: :bad_checksum
|
714
|
+
option '--adler32', name: :sctp_adler32
|
715
|
+
|
716
|
+
# OUTPUT:
|
717
|
+
option '-oN', name: :output_normal, value: true
|
718
|
+
option '-oX', name: :output_xml, value: true
|
719
|
+
option '-oS', name: :output_skiddie, value: true
|
720
|
+
option '-oG', name: :output_grepable, value: true
|
721
|
+
option '-oA', name: :output_all, value: true
|
722
|
+
|
723
|
+
# Verbosity and Debugging:
|
724
|
+
option '-v', name: :verbose,
|
725
|
+
value_in_flag: true,
|
726
|
+
value: {type: Num.new, required: false}
|
727
|
+
option '-vv', name: :extra_verbose
|
728
|
+
option '-v0', name: :quiet
|
729
|
+
option '-d', name: :debug,
|
730
|
+
value_in_flag: true,
|
731
|
+
value: {type: Num.new, required: false}
|
732
|
+
option '--reason', name: :show_reason
|
733
|
+
option '--stats-every', value: {type: Time.new}
|
734
|
+
option '--packet-trace', name: :show_packets
|
735
|
+
option '--open', name: :show_open_ports
|
736
|
+
option '--iflist', name: :show_interfaces
|
737
|
+
option '--log-errors', name: :show_log_errors
|
738
|
+
|
739
|
+
# Miscellaneous output:
|
740
|
+
option '--append-output'
|
741
|
+
option '--resume', value: true
|
742
|
+
option '--stylesheet', value: true
|
743
|
+
option '--webxml', name: :nmap_stylesheet
|
744
|
+
option '--no-stylesheet'
|
745
|
+
|
746
|
+
# MISC:
|
747
|
+
option '-6', name: :ipv6
|
748
|
+
option '-A', name: :all
|
749
|
+
option '--datadir', name: :nmap_datadir, value: {type: InputDir.new}
|
750
|
+
option '--servicedb', value: {type: InputFile.new}
|
751
|
+
option '--versiondb', value: {type: InputFile.new}
|
752
|
+
option '--send-eth'
|
753
|
+
option '--send-ip'
|
754
|
+
option '--privileged'
|
755
|
+
option '--unprivleged'
|
756
|
+
option '--release-memory'
|
757
|
+
option '--noninteractive', name: :non_interactive
|
758
|
+
option '-V', name: :version
|
759
|
+
option '-h', name: :help
|
760
|
+
|
761
|
+
argument :targets, required: false, repeats: true
|
762
|
+
end
|
763
|
+
|
764
|
+
end
|
765
|
+
end
|