ruby-nmap 0.9.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. checksums.yaml +5 -5
  2. data/.document +1 -0
  3. data/.editorconfig +11 -0
  4. data/.github/workflows/ruby.yml +31 -0
  5. data/ChangeLog.md +122 -67
  6. data/Gemfile +11 -5
  7. data/LICENSE.txt +1 -1
  8. data/README.md +88 -50
  9. data/Rakefile +8 -3
  10. data/UPGRADING.md +47 -0
  11. data/gemspec.yml +6 -6
  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 +46 -44
  42. data/ruby-nmap.gemspec +38 -83
  43. data/spec/command_spec.rb +726 -0
  44. data/spec/fixtures/down_host_scan.xml +16 -0
  45. data/spec/{local_scan.xml → fixtures/local_scan.xml} +1 -1
  46. data/spec/{scan.xml → fixtures/scan.xml} +1 -1
  47. data/spec/spec_helper.rb +2 -2
  48. data/spec/{address_spec.rb → xml/address_spec.rb} +2 -2
  49. data/spec/{cpe → xml/cpe}/url_spec.rb +1 -1
  50. data/spec/{cpe_examples.rb → xml/cpe_examples.rb} +1 -1
  51. data/spec/{hop_spec.rb → xml/hop_spec.rb} +2 -2
  52. data/spec/{host_script_spec.rb → xml/host_script_spec.rb} +2 -2
  53. data/spec/{host_spec.rb → xml/host_spec.rb} +12 -8
  54. data/spec/{hostname_spec.rb → xml/hostname_spec.rb} +2 -2
  55. data/spec/{ip_id_sequence_spec.rb → xml/ip_id_sequence_spec.rb} +3 -3
  56. data/spec/{os_class_spec.rb → xml/os_class_spec.rb} +3 -3
  57. data/spec/{os_match_spec.rb → xml/os_match_spec.rb} +2 -2
  58. data/spec/{os_spec.rb → xml/os_spec.rb} +3 -3
  59. data/spec/{port_spec.rb → xml/port_spec.rb} +10 -5
  60. data/spec/{postscript_spec.rb → xml/postscript_spec.rb} +2 -2
  61. data/spec/{prescript_spec.rb → xml/prescript_spec.rb} +2 -2
  62. data/spec/{run_stat_spec.rb → xml/run_stat_spec.rb} +2 -2
  63. data/spec/{scan_spec.rb → xml/scan_spec.rb} +2 -2
  64. data/spec/{scan_task_spec.rb → xml/scan_task_spec.rb} +6 -6
  65. data/spec/{scanner_spec.rb → xml/scanner_spec.rb} +3 -3
  66. data/spec/xml/script_spec.rb +137 -0
  67. data/spec/xml/scripts_examples.rb +19 -0
  68. data/spec/{sequence_examples.rb → xml/sequence_examples.rb} +1 -0
  69. data/spec/{service_spec.rb → xml/service_spec.rb} +31 -5
  70. data/spec/{status_spec.rb → xml/status_spec.rb} +4 -3
  71. data/spec/{tcp_sequence_spec.rb → xml/tcp_sequence_spec.rb} +3 -3
  72. data/spec/{tcp_ts_sequence_spec.rb → xml/tcp_ts_sequence_spec.rb} +3 -3
  73. data/spec/{traceroute_spec.rb → xml/traceroute_spec.rb} +3 -3
  74. data/spec/{uptime_spec.rb → xml/uptime_spec.rb} +2 -2
  75. data/spec/xml_spec.rb +93 -45
  76. metadata +78 -99
  77. data/.travis.yml +0 -14
  78. data/lib/nmap/address.rb +0 -34
  79. data/lib/nmap/cpe/url.rb +0 -78
  80. data/lib/nmap/cpe.rb +0 -45
  81. data/lib/nmap/hop.rb +0 -20
  82. data/lib/nmap/host.rb +0 -586
  83. data/lib/nmap/host_script.rb +0 -18
  84. data/lib/nmap/hostname.rb +0 -42
  85. data/lib/nmap/ip_id_sequence.rb +0 -24
  86. data/lib/nmap/os.rb +0 -127
  87. data/lib/nmap/os_class.rb +0 -82
  88. data/lib/nmap/os_match.rb +0 -18
  89. data/lib/nmap/port.rb +0 -99
  90. data/lib/nmap/postscript.rb +0 -16
  91. data/lib/nmap/prescript.rb +0 -16
  92. data/lib/nmap/program.rb +0 -102
  93. data/lib/nmap/run_stat.rb +0 -20
  94. data/lib/nmap/scan.rb +0 -34
  95. data/lib/nmap/scan_task.rb +0 -50
  96. data/lib/nmap/scanner.rb +0 -18
  97. data/lib/nmap/scripts.rb +0 -71
  98. data/lib/nmap/sequence.rb +0 -50
  99. data/lib/nmap/service.rb +0 -170
  100. data/lib/nmap/status.rb +0 -18
  101. data/lib/nmap/task.rb +0 -381
  102. data/lib/nmap/tcp_sequence.rb +0 -46
  103. data/lib/nmap/tcp_ts_sequence.rb +0 -22
  104. data/lib/nmap/traceroute.rb +0 -71
  105. data/lib/nmap/uptime.rb +0 -20
  106. data/spec/scripts_examples.rb +0 -35
  107. 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