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.
- checksums.yaml +5 -5
- data/.document +1 -0
- data/.editorconfig +11 -0
- data/.github/workflows/ruby.yml +31 -0
- data/ChangeLog.md +122 -67
- data/Gemfile +11 -5
- data/LICENSE.txt +1 -1
- data/README.md +88 -50
- data/Rakefile +8 -3
- data/UPGRADING.md +47 -0
- data/gemspec.yml +6 -6
- 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 +46 -44
- data/ruby-nmap.gemspec +38 -83
- data/spec/command_spec.rb +726 -0
- data/spec/fixtures/down_host_scan.xml +16 -0
- data/spec/{local_scan.xml → fixtures/local_scan.xml} +1 -1
- data/spec/{scan.xml → fixtures/scan.xml} +1 -1
- data/spec/spec_helper.rb +2 -2
- 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} +12 -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} +10 -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} +4 -3
- 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 +93 -45
- metadata +78 -99
- data/.travis.yml +0 -14
- 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 -586
- 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 -99
- 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 -50
- 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 -381
- 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
|