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.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.document +1 -0
  3. data/.editorconfig +11 -0
  4. data/.github/workflows/ruby.yml +31 -0
  5. data/ChangeLog.md +118 -71
  6. data/Gemfile +11 -5
  7. data/LICENSE.txt +1 -1
  8. data/README.md +88 -50
  9. data/Rakefile +5 -0
  10. data/UPGRADING.md +47 -0
  11. data/gemspec.yml +5 -5
  12. data/lib/nmap/command.rb +765 -0
  13. data/lib/nmap/version.rb +1 -1
  14. data/lib/nmap/xml/address.rb +38 -0
  15. data/lib/nmap/xml/cpe/url.rb +80 -0
  16. data/lib/nmap/xml/cpe.rb +47 -0
  17. data/lib/nmap/xml/hop.rb +22 -0
  18. data/lib/nmap/xml/host.rb +546 -0
  19. data/lib/nmap/xml/host_script.rb +26 -0
  20. data/lib/nmap/xml/hostname.rb +44 -0
  21. data/lib/nmap/xml/ip_id_sequence.rb +26 -0
  22. data/lib/nmap/xml/os.rb +131 -0
  23. data/lib/nmap/xml/os_class.rb +86 -0
  24. data/lib/nmap/xml/os_match.rb +22 -0
  25. data/lib/nmap/xml/port.rb +114 -0
  26. data/lib/nmap/xml/postscript.rb +26 -0
  27. data/lib/nmap/xml/prescript.rb +26 -0
  28. data/lib/nmap/xml/run_stat.rb +22 -0
  29. data/lib/nmap/xml/scan.rb +38 -0
  30. data/lib/nmap/xml/scan_task.rb +55 -0
  31. data/lib/nmap/xml/scanner.rb +22 -0
  32. data/lib/nmap/xml/script.rb +110 -0
  33. data/lib/nmap/xml/scripts.rb +33 -0
  34. data/lib/nmap/xml/sequence.rb +52 -0
  35. data/lib/nmap/xml/service.rb +172 -0
  36. data/lib/nmap/xml/status.rb +22 -0
  37. data/lib/nmap/xml/tcp_sequence.rb +48 -0
  38. data/lib/nmap/xml/tcp_ts_sequence.rb +26 -0
  39. data/lib/nmap/xml/traceroute.rb +73 -0
  40. data/lib/nmap/xml/uptime.rb +22 -0
  41. data/lib/nmap/xml.rb +31 -44
  42. data/spec/command_spec.rb +726 -0
  43. data/spec/fixtures/down_host_scan.xml +16 -0
  44. data/spec/{address_spec.rb → xml/address_spec.rb} +2 -2
  45. data/spec/{cpe → xml/cpe}/url_spec.rb +1 -1
  46. data/spec/{cpe_examples.rb → xml/cpe_examples.rb} +1 -1
  47. data/spec/{hop_spec.rb → xml/hop_spec.rb} +2 -2
  48. data/spec/{host_script_spec.rb → xml/host_script_spec.rb} +2 -2
  49. data/spec/{host_spec.rb → xml/host_spec.rb} +8 -8
  50. data/spec/{hostname_spec.rb → xml/hostname_spec.rb} +2 -2
  51. data/spec/{ip_id_sequence_spec.rb → xml/ip_id_sequence_spec.rb} +3 -3
  52. data/spec/{os_class_spec.rb → xml/os_class_spec.rb} +3 -3
  53. data/spec/{os_match_spec.rb → xml/os_match_spec.rb} +2 -2
  54. data/spec/{os_spec.rb → xml/os_spec.rb} +3 -3
  55. data/spec/{port_spec.rb → xml/port_spec.rb} +4 -5
  56. data/spec/{postscript_spec.rb → xml/postscript_spec.rb} +2 -2
  57. data/spec/{prescript_spec.rb → xml/prescript_spec.rb} +2 -2
  58. data/spec/{run_stat_spec.rb → xml/run_stat_spec.rb} +2 -2
  59. data/spec/{scan_spec.rb → xml/scan_spec.rb} +2 -2
  60. data/spec/{scan_task_spec.rb → xml/scan_task_spec.rb} +6 -6
  61. data/spec/{scanner_spec.rb → xml/scanner_spec.rb} +3 -3
  62. data/spec/xml/script_spec.rb +137 -0
  63. data/spec/xml/scripts_examples.rb +19 -0
  64. data/spec/{sequence_examples.rb → xml/sequence_examples.rb} +1 -0
  65. data/spec/{service_spec.rb → xml/service_spec.rb} +31 -5
  66. data/spec/{status_spec.rb → xml/status_spec.rb} +2 -2
  67. data/spec/{tcp_sequence_spec.rb → xml/tcp_sequence_spec.rb} +3 -3
  68. data/spec/{tcp_ts_sequence_spec.rb → xml/tcp_ts_sequence_spec.rb} +3 -3
  69. data/spec/{traceroute_spec.rb → xml/traceroute_spec.rb} +3 -3
  70. data/spec/{uptime_spec.rb → xml/uptime_spec.rb} +2 -2
  71. data/spec/xml_spec.rb +73 -44
  72. metadata +72 -66
  73. data/.travis.yml +0 -16
  74. data/lib/nmap/address.rb +0 -34
  75. data/lib/nmap/cpe/url.rb +0 -78
  76. data/lib/nmap/cpe.rb +0 -45
  77. data/lib/nmap/hop.rb +0 -20
  78. data/lib/nmap/host.rb +0 -587
  79. data/lib/nmap/host_script.rb +0 -18
  80. data/lib/nmap/hostname.rb +0 -42
  81. data/lib/nmap/ip_id_sequence.rb +0 -24
  82. data/lib/nmap/os.rb +0 -127
  83. data/lib/nmap/os_class.rb +0 -82
  84. data/lib/nmap/os_match.rb +0 -18
  85. data/lib/nmap/port.rb +0 -110
  86. data/lib/nmap/postscript.rb +0 -16
  87. data/lib/nmap/prescript.rb +0 -16
  88. data/lib/nmap/program.rb +0 -102
  89. data/lib/nmap/run_stat.rb +0 -20
  90. data/lib/nmap/scan.rb +0 -34
  91. data/lib/nmap/scan_task.rb +0 -53
  92. data/lib/nmap/scanner.rb +0 -18
  93. data/lib/nmap/scripts.rb +0 -71
  94. data/lib/nmap/sequence.rb +0 -50
  95. data/lib/nmap/service.rb +0 -170
  96. data/lib/nmap/status.rb +0 -18
  97. data/lib/nmap/task.rb +0 -387
  98. data/lib/nmap/tcp_sequence.rb +0 -46
  99. data/lib/nmap/tcp_ts_sequence.rb +0 -22
  100. data/lib/nmap/traceroute.rb +0 -71
  101. data/lib/nmap/uptime.rb +0 -20
  102. data/spec/scripts_examples.rb +0 -35
  103. data/spec/task_spec.rb +0 -150
@@ -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