ronin-nmap 0.1.0.rc1
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 +7 -0
- data/.document +4 -0
- data/.github/workflows/ruby.yml +47 -0
- data/.gitignore +14 -0
- data/.rspec +1 -0
- data/.rubocop.yml +15 -0
- data/.ruby-version +1 -0
- data/.yardopts +1 -0
- data/COPYING.txt +165 -0
- data/ChangeLog.md +10 -0
- data/Gemfile +42 -0
- data/README.md +238 -0
- data/Rakefile +43 -0
- data/bin/ronin-nmap +32 -0
- data/data/completions/ronin-nmap +79 -0
- data/data/templates/script.rb.erb +58 -0
- data/gemspec.yml +42 -0
- data/lib/ronin/nmap/cli/command.rb +40 -0
- data/lib/ronin/nmap/cli/commands/completion.rb +61 -0
- data/lib/ronin/nmap/cli/commands/convert.rb +108 -0
- data/lib/ronin/nmap/cli/commands/dump.rb +293 -0
- data/lib/ronin/nmap/cli/commands/grep.rb +378 -0
- data/lib/ronin/nmap/cli/commands/import.rb +79 -0
- data/lib/ronin/nmap/cli/commands/new.rb +226 -0
- data/lib/ronin/nmap/cli/commands/print.rb +133 -0
- data/lib/ronin/nmap/cli/commands/scan.rb +233 -0
- data/lib/ronin/nmap/cli/filtering_options.rb +355 -0
- data/lib/ronin/nmap/cli/importable.rb +68 -0
- data/lib/ronin/nmap/cli/port_list.rb +102 -0
- data/lib/ronin/nmap/cli.rb +50 -0
- data/lib/ronin/nmap/converter.rb +114 -0
- data/lib/ronin/nmap/converters/csv.rb +162 -0
- data/lib/ronin/nmap/converters/json.rb +562 -0
- data/lib/ronin/nmap/converters.rb +54 -0
- data/lib/ronin/nmap/exceptions.rb +47 -0
- data/lib/ronin/nmap/importer.rb +369 -0
- data/lib/ronin/nmap/root.rb +28 -0
- data/lib/ronin/nmap/version.rb +26 -0
- data/lib/ronin/nmap.rb +223 -0
- data/man/ronin-nmap-completion.1 +76 -0
- data/man/ronin-nmap-completion.1.md +78 -0
- data/man/ronin-nmap-convert.1 +33 -0
- data/man/ronin-nmap-convert.1.md +36 -0
- data/man/ronin-nmap-dump.1 +141 -0
- data/man/ronin-nmap-dump.1.md +119 -0
- data/man/ronin-nmap-grep.1 +33 -0
- data/man/ronin-nmap-grep.1.md +36 -0
- data/man/ronin-nmap-import.1 +52 -0
- data/man/ronin-nmap-import.1.md +57 -0
- data/man/ronin-nmap-new.1 +81 -0
- data/man/ronin-nmap-new.1.md +73 -0
- data/man/ronin-nmap-print.1 +61 -0
- data/man/ronin-nmap-print.1.md +63 -0
- data/man/ronin-nmap-scan.1 +86 -0
- data/man/ronin-nmap-scan.1.md +84 -0
- data/man/ronin-nmap.1 +58 -0
- data/man/ronin-nmap.1.md +57 -0
- data/ronin-nmap.gemspec +62 -0
- data/scripts/setup +161 -0
- metadata +168 -0
@@ -0,0 +1,355 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-nmap - A Ruby library for automating nmap and importing nmap scans.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-nmap is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-nmap is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-nmap. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'ronin/nmap/cli/port_list'
|
22
|
+
|
23
|
+
module Ronin
|
24
|
+
module Nmap
|
25
|
+
class CLI
|
26
|
+
#
|
27
|
+
# Mixin which adds nmap target filtering options to commands.
|
28
|
+
#
|
29
|
+
module FilteringOptions
|
30
|
+
#
|
31
|
+
# Adds filtering options to the command class including
|
32
|
+
# {FilteringOptions}.
|
33
|
+
#
|
34
|
+
# @param [Class<Command>] command
|
35
|
+
# The command class including {FilteringOptions}.
|
36
|
+
#
|
37
|
+
def self.included(command)
|
38
|
+
command.option :ip, value: {
|
39
|
+
type: String,
|
40
|
+
usage: 'IP'
|
41
|
+
},
|
42
|
+
desc: 'Filters the targets by IP' do |ip|
|
43
|
+
@with_ips << ip
|
44
|
+
end
|
45
|
+
|
46
|
+
command.option :ip_range, value: {
|
47
|
+
type: String,
|
48
|
+
usage: 'CIDR'
|
49
|
+
},
|
50
|
+
desc: 'Filter the targets by IP range' do |ip_range|
|
51
|
+
@with_ip_ranges << IPAddr.new(ip_range)
|
52
|
+
end
|
53
|
+
|
54
|
+
command.option :domain, value: {
|
55
|
+
type: String,
|
56
|
+
usage: 'DOMAIN'
|
57
|
+
},
|
58
|
+
desc: 'Filters the targets by domain' do |domain|
|
59
|
+
@with_domains << domain
|
60
|
+
end
|
61
|
+
|
62
|
+
command.option :with_os, value: {
|
63
|
+
type: String,
|
64
|
+
usage: 'OS'
|
65
|
+
},
|
66
|
+
desc: 'Filters the targets by OS' do |os|
|
67
|
+
@with_oses << os.to_sym
|
68
|
+
end
|
69
|
+
|
70
|
+
command.option :with_ports, value: {
|
71
|
+
type: /\A(?:\d+|\d+-\d+)(?:,(?:\d+|\d+-\d+))*\z/,
|
72
|
+
usage: '{PORT | PORT1-PORT2},...'
|
73
|
+
},
|
74
|
+
desc: 'Filter targets by port numbers' do |ports|
|
75
|
+
@with_ports << PortList.parse(ports)
|
76
|
+
end
|
77
|
+
|
78
|
+
command.option :with_service, value: {
|
79
|
+
type: /\A[a-z]+[a-z0-9_+-]*\z/,
|
80
|
+
usage: 'SERVICE[,...]'
|
81
|
+
},
|
82
|
+
desc: 'Filters targets by service' do |service|
|
83
|
+
@with_services << service
|
84
|
+
end
|
85
|
+
|
86
|
+
command.option :with_script, value: {
|
87
|
+
type: /\A[a-z][a-z0-9-]*\z/,
|
88
|
+
usage: 'SCRIPT[,...]'
|
89
|
+
},
|
90
|
+
desc: 'Filters targets with the script' do |script|
|
91
|
+
@with_scripts << script
|
92
|
+
end
|
93
|
+
|
94
|
+
command.option :with_script_output, value: {
|
95
|
+
type: String,
|
96
|
+
usage: 'STRING'
|
97
|
+
},
|
98
|
+
desc: 'Filters targets containing the script output' do |string|
|
99
|
+
@with_script_output << string
|
100
|
+
end
|
101
|
+
|
102
|
+
command.option :with_script_regex, value: {
|
103
|
+
type: Regexp,
|
104
|
+
usage: '/REGEX/'
|
105
|
+
},
|
106
|
+
desc: 'Filters targets containing the script output' do |regexp|
|
107
|
+
@with_script_output << regexp
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [Set<String>]
|
112
|
+
attr_reader :with_ips
|
113
|
+
|
114
|
+
# @return [Set<IPAddr>]
|
115
|
+
attr_reader :with_ip_ranges
|
116
|
+
|
117
|
+
# @return [Set<String>]
|
118
|
+
attr_reader :with_domains
|
119
|
+
|
120
|
+
# @return [Set<String>]
|
121
|
+
attr_reader :with_oses
|
122
|
+
|
123
|
+
# @return [Set<PortList>]
|
124
|
+
attr_reader :with_ports
|
125
|
+
|
126
|
+
# @return [Set<String>]
|
127
|
+
attr_reader :with_services
|
128
|
+
|
129
|
+
# @return [Set<String>]
|
130
|
+
attr_reader :with_scripts
|
131
|
+
|
132
|
+
# @return [Set<String, Regexp>]
|
133
|
+
attr_reader :with_script_output
|
134
|
+
|
135
|
+
#
|
136
|
+
# Initializes the command.
|
137
|
+
#
|
138
|
+
# @param [Hash{Symbol => String}] kwargs
|
139
|
+
# Additional keywords for the command.
|
140
|
+
#
|
141
|
+
def initialize(**kwargs)
|
142
|
+
super(**kwargs)
|
143
|
+
|
144
|
+
@with_ips = Set.new
|
145
|
+
@with_ip_ranges = Set.new
|
146
|
+
@with_domains = Set.new
|
147
|
+
@with_oses = Set.new
|
148
|
+
@with_ports = Set.new
|
149
|
+
@with_services = Set.new
|
150
|
+
@with_scripts = Set.new
|
151
|
+
@with_script_output = Set.new
|
152
|
+
end
|
153
|
+
|
154
|
+
#
|
155
|
+
# Filters the nmap scan targets.
|
156
|
+
#
|
157
|
+
# @param [::Nmap::XML] xml
|
158
|
+
# The parsed nmap xml data to filter.
|
159
|
+
#
|
160
|
+
# @return [Enumerator::Lazy]
|
161
|
+
# A lazy enumerator of the filtered targets.
|
162
|
+
#
|
163
|
+
def filter_targets(xml)
|
164
|
+
targets = xml.each_up_host.lazy
|
165
|
+
|
166
|
+
unless @with_ips.empty?
|
167
|
+
targets = filter_targets_by_ip(targets)
|
168
|
+
end
|
169
|
+
|
170
|
+
unless @with_ip_ranges.empty?
|
171
|
+
targets = filter_targets_by_ip_range(targets)
|
172
|
+
end
|
173
|
+
|
174
|
+
unless @with_domains.empty?
|
175
|
+
targets = filter_targets_by_domain(targets)
|
176
|
+
end
|
177
|
+
|
178
|
+
unless @with_oses.empty?
|
179
|
+
targets = filter_targets_by_os(targets)
|
180
|
+
end
|
181
|
+
|
182
|
+
unless @with_ports.empty?
|
183
|
+
targets = filter_targets_by_port(targets)
|
184
|
+
end
|
185
|
+
|
186
|
+
unless @with_services.empty?
|
187
|
+
targets = filter_targets_by_scripts(targets)
|
188
|
+
end
|
189
|
+
|
190
|
+
unless @with_scripts.empty?
|
191
|
+
targets = filter_targets_by_script(targets)
|
192
|
+
end
|
193
|
+
|
194
|
+
unless @with_script_output.empty?
|
195
|
+
targets = filter_targets_by_script_output(targets)
|
196
|
+
end
|
197
|
+
|
198
|
+
return targets
|
199
|
+
end
|
200
|
+
|
201
|
+
#
|
202
|
+
# Filters the targets by IP address.
|
203
|
+
#
|
204
|
+
# @param [Enumerator::Lazy] targets
|
205
|
+
# The targets to filter.
|
206
|
+
#
|
207
|
+
# @return [Enumerator::Lazy]
|
208
|
+
# A lazy enumerator of the filtered targets.
|
209
|
+
#
|
210
|
+
def filter_targets_by_ip(targets)
|
211
|
+
targets.filter do |host|
|
212
|
+
@with_ips.include?(host.address)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
#
|
217
|
+
# Filters the targets by an IP rangeo.
|
218
|
+
#
|
219
|
+
# @param [Enumerator::Lazy] targets
|
220
|
+
# The targets to filter.
|
221
|
+
#
|
222
|
+
# @return [Enumerator::Lazy]
|
223
|
+
# A lazy enumerator of the filtered targets.
|
224
|
+
#
|
225
|
+
def filter_targets_by_ip_range(targets)
|
226
|
+
targets.filter do |host|
|
227
|
+
@with_ip_ranges.any? do |ip_range|
|
228
|
+
ip_range.include?(host.address)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
#
|
234
|
+
# Filters the targets by a domain.
|
235
|
+
#
|
236
|
+
# @param [Enumerator::Lazy] targets
|
237
|
+
# The targets to filter.
|
238
|
+
#
|
239
|
+
# @return [Enumerator::Lazy]
|
240
|
+
# A lazy enumerator of the filtered targets.
|
241
|
+
#
|
242
|
+
def filter_targets_by_domain(targets)
|
243
|
+
regexp = Regexp.union(
|
244
|
+
@with_domains.map { |domain|
|
245
|
+
escaped_domain = Regexp.escape(domain)
|
246
|
+
|
247
|
+
/\.#{escaped_domain}\z|\A#{escaped_domain}\z/
|
248
|
+
}
|
249
|
+
)
|
250
|
+
|
251
|
+
targets.filter do |host|
|
252
|
+
if (hostname = host.hostname)
|
253
|
+
hostname.name =~ regexp
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
#
|
259
|
+
# Filters the targets by OS.
|
260
|
+
#
|
261
|
+
# @param [Enumerator::Lazy] targets
|
262
|
+
# The targets to filter.
|
263
|
+
#
|
264
|
+
# @return [Enumerator::Lazy]
|
265
|
+
# A lazy enumerator of the filtered targets.
|
266
|
+
#
|
267
|
+
def filter_targets_by_os(targets)
|
268
|
+
targets.filter do |host|
|
269
|
+
if (os = host.os)
|
270
|
+
os.each_class.any? do |os_class|
|
271
|
+
@with_oses.include?(os_class.family)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
#
|
278
|
+
# Filters the targets by port number.
|
279
|
+
#
|
280
|
+
# @param [Enumerator::Lazy] targets
|
281
|
+
# The targets to filter.
|
282
|
+
#
|
283
|
+
# @return [Enumerator::Lazy]
|
284
|
+
# A lazy enumerator of the filtered targets.
|
285
|
+
#
|
286
|
+
def filter_targets_by_port(targets)
|
287
|
+
targets.filter do |host|
|
288
|
+
host.each_open_port.any? do |port|
|
289
|
+
@with_ports.any? do |port_list|
|
290
|
+
port_list.include?(port.number)
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
#
|
297
|
+
# Filters the targets by service name.
|
298
|
+
#
|
299
|
+
# @param [Enumerator::Lazy] targets
|
300
|
+
# The targets to filter.
|
301
|
+
#
|
302
|
+
# @return [Enumerator::Lazy]
|
303
|
+
# A lazy enumerator of the filtered targets.
|
304
|
+
#
|
305
|
+
def filter_targets_by_service(targets)
|
306
|
+
targets.filter do |host|
|
307
|
+
host.each_open_port.any? do |port|
|
308
|
+
if (service = port.service)
|
309
|
+
@with_services.include?(service.name)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
#
|
316
|
+
# Filters the targets by script IDs.
|
317
|
+
#
|
318
|
+
# @param [Enumerator::Lazy] targets
|
319
|
+
# The targets to filter.
|
320
|
+
#
|
321
|
+
# @return [Enumerator::Lazy]
|
322
|
+
# A lazy enumerator of the filtered targets.
|
323
|
+
#
|
324
|
+
def filter_targets_by_script(targets)
|
325
|
+
targets.filter do |host|
|
326
|
+
host.each_open_port.any? do |port|
|
327
|
+
@with_scripts.intersect?(port.scripts.keys)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
#
|
333
|
+
# Filters the targets by script output.
|
334
|
+
#
|
335
|
+
# @param [Enumerator::Lazy] targets
|
336
|
+
# The targets to filter.
|
337
|
+
#
|
338
|
+
# @return [Enumerator::Lazy]
|
339
|
+
# A lazy enumerator of the filtered targets.
|
340
|
+
#
|
341
|
+
def filter_targets_by_script_output(targets)
|
342
|
+
regexp = Regexp.union(@with_script_output.to_a)
|
343
|
+
|
344
|
+
targets.filter do |host|
|
345
|
+
host.each_open_port.any? do |port|
|
346
|
+
port.scripts.each_value.any? do |script|
|
347
|
+
script.output =~ regexp
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-nmap - A Ruby library for automating nmap and importing nmap scans.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-nmap is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-nmap is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-nmap. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'ronin/nmap/importer'
|
22
|
+
require 'ronin/db/cli/database_options'
|
23
|
+
require 'ronin/db/cli/printing'
|
24
|
+
require 'ronin/core/cli/logging'
|
25
|
+
|
26
|
+
module Ronin
|
27
|
+
module Nmap
|
28
|
+
class CLI
|
29
|
+
#
|
30
|
+
# Mixin module which adds the ability to import nmap XML into the
|
31
|
+
# [ronin-db] database.
|
32
|
+
#
|
33
|
+
# [ronin-db]: https://github.com/ronin-rb/ronin-db#readme
|
34
|
+
#
|
35
|
+
module Importable
|
36
|
+
include DB::CLI::Printing
|
37
|
+
include Core::CLI::Logging
|
38
|
+
|
39
|
+
#
|
40
|
+
# Includes `Ronin::DB::CLI::DatabaseOptions` into the including command
|
41
|
+
# class.
|
42
|
+
#
|
43
|
+
# @param [Class<Command>] command
|
44
|
+
# The command class including {Importable}.
|
45
|
+
#
|
46
|
+
def self.included(command)
|
47
|
+
command.include DB::CLI::DatabaseOptions
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Imports an nmap XML file into the [ronin-db] database.
|
52
|
+
#
|
53
|
+
# [ronin-db]: https://github.com/ronin-rb/ronin-db#readme
|
54
|
+
#
|
55
|
+
# @param [String] xml_file
|
56
|
+
# The path to the nmap XML file to import.
|
57
|
+
#
|
58
|
+
def import_file(xml_file)
|
59
|
+
Importer.import_file(xml_file) do |record|
|
60
|
+
if (type = record_type(record))
|
61
|
+
log_info "Imported #{type}: #{record}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-nmap - A Ruby library for automating nmap and importing nmap scans.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-nmap is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-nmap is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-nmap. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'set'
|
22
|
+
|
23
|
+
module Ronin
|
24
|
+
module Nmap
|
25
|
+
class CLI
|
26
|
+
#
|
27
|
+
# Represents a list of port numbers and port ranges.
|
28
|
+
#
|
29
|
+
class PortList
|
30
|
+
|
31
|
+
# Port numbers.
|
32
|
+
#
|
33
|
+
# @return [Array<Integer>]
|
34
|
+
attr_reader :numbers
|
35
|
+
|
36
|
+
# Port ranges.
|
37
|
+
#
|
38
|
+
# @return [Array<Range>]
|
39
|
+
attr_reader :ranges
|
40
|
+
|
41
|
+
#
|
42
|
+
# Initialize the port list.
|
43
|
+
#
|
44
|
+
# @param [Array<Integer, Range>] ports
|
45
|
+
# The port numbers and ranges.
|
46
|
+
#
|
47
|
+
# @raise [ArgumentError]
|
48
|
+
# One of the ports was not an Integer or Range object.
|
49
|
+
#
|
50
|
+
def initialize(ports)
|
51
|
+
@numbers = Set.new
|
52
|
+
@ranges = Set.new
|
53
|
+
|
54
|
+
ports.each do |port|
|
55
|
+
case port
|
56
|
+
when Integer then @numbers << port
|
57
|
+
when Range then @ranges << port
|
58
|
+
else
|
59
|
+
raise(ArgumentError,"port must be an Integer or Range: #{port.inspect}")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Parses the port list.
|
66
|
+
#
|
67
|
+
# @param [String] ports
|
68
|
+
# The port list to parse.
|
69
|
+
#
|
70
|
+
# @return [PortList]
|
71
|
+
# The port numbers and port ranges.
|
72
|
+
#
|
73
|
+
def self.parse(ports)
|
74
|
+
new(
|
75
|
+
ports.split(',').map do |port|
|
76
|
+
if port.include?('-')
|
77
|
+
start, stop = port.split('-',2)
|
78
|
+
|
79
|
+
Range.new(start.to_i,stop.to_i)
|
80
|
+
else
|
81
|
+
port.to_i
|
82
|
+
end
|
83
|
+
end
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Determines if the port is in the port list.
|
89
|
+
#
|
90
|
+
# @param [Integer] port
|
91
|
+
#
|
92
|
+
# @return [Boolean]
|
93
|
+
#
|
94
|
+
def include?(port)
|
95
|
+
@numbers.include?(port) ||
|
96
|
+
@ranges.any? { |range| range.include?(port) }
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-nmap - A Ruby library for automating nmap and importing nmap scans.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-nmap is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-nmap is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-nmap. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'ronin/nmap/version'
|
22
|
+
require 'ronin/core/cli/help/banner'
|
23
|
+
|
24
|
+
require 'command_kit/commands'
|
25
|
+
require 'command_kit/commands/auto_load'
|
26
|
+
require 'command_kit/options/version'
|
27
|
+
|
28
|
+
module Ronin
|
29
|
+
module Nmap
|
30
|
+
#
|
31
|
+
# The `ronin-nmap` command-line interface (CLI).
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
#
|
35
|
+
class CLI
|
36
|
+
|
37
|
+
include CommandKit::Commands
|
38
|
+
include CommandKit::Commands::AutoLoad.new(
|
39
|
+
dir: "#{__dir__}/cli/commands",
|
40
|
+
namespace: "#{self}::Commands"
|
41
|
+
)
|
42
|
+
include CommandKit::Options::Version
|
43
|
+
include Core::CLI::Help::Banner
|
44
|
+
|
45
|
+
command_name 'ronin-nmap'
|
46
|
+
version Ronin::Nmap::VERSION
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-nmap - A Ruby library for automating nmap and importing nmap scans.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-nmap is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-nmap is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-nmap. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'ronin/nmap/converters'
|
22
|
+
|
23
|
+
require 'nmap/xml'
|
24
|
+
|
25
|
+
module Ronin
|
26
|
+
module Nmap
|
27
|
+
#
|
28
|
+
# Handles converting nmap XML into other formats.
|
29
|
+
#
|
30
|
+
# Supports the following formats:
|
31
|
+
#
|
32
|
+
# * JSON
|
33
|
+
# * CSV
|
34
|
+
#
|
35
|
+
# @api public
|
36
|
+
#
|
37
|
+
module Converter
|
38
|
+
# Mapping of file extension names to formats.
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
FILE_FORMATS = {
|
42
|
+
'.json' => :json,
|
43
|
+
'.csv' => :csv
|
44
|
+
}
|
45
|
+
|
46
|
+
#
|
47
|
+
# Converts an nmap XML scan file into another format.
|
48
|
+
#
|
49
|
+
# @param [String] src
|
50
|
+
# The input XML file path.
|
51
|
+
#
|
52
|
+
# @param [String] dest
|
53
|
+
# The output file path.
|
54
|
+
#
|
55
|
+
# @api public
|
56
|
+
#
|
57
|
+
def self.convert_file(src,dest, format: infer_format_for(dest))
|
58
|
+
xml = ::Nmap::XML.open(src)
|
59
|
+
converter = Converters[format]
|
60
|
+
|
61
|
+
File.open(dest,'w') do |output|
|
62
|
+
converter.convert(xml,output)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Converts parsed nmap XML into the desired format.
|
68
|
+
#
|
69
|
+
# @param [::Nmap::XML] xml
|
70
|
+
# The nmap XML to convert.
|
71
|
+
#
|
72
|
+
# @param [IO, nil] output
|
73
|
+
# Optional output to write the converted output to.
|
74
|
+
#
|
75
|
+
# @param [:json, :csv] format
|
76
|
+
# The desired convert to convert the parsed nmap XML to.
|
77
|
+
#
|
78
|
+
# @return [String]
|
79
|
+
# The converted nmap XML.
|
80
|
+
#
|
81
|
+
# @api public
|
82
|
+
#
|
83
|
+
def self.convert(xml,output=nil, format: )
|
84
|
+
if output
|
85
|
+
Converters[format].convert(xml,output)
|
86
|
+
else
|
87
|
+
output = StringIO.new
|
88
|
+
convert(xml,output, format: format)
|
89
|
+
output.string
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# Infers the output format from the output file's extension.
|
95
|
+
#
|
96
|
+
# @param [String] path
|
97
|
+
# The output file name.
|
98
|
+
#
|
99
|
+
# @return [:json, :csv]
|
100
|
+
# The conversion format.
|
101
|
+
#
|
102
|
+
# @raise [ArgumentError]
|
103
|
+
# The format could not be inferred from the path's file extension.
|
104
|
+
#
|
105
|
+
# @api private
|
106
|
+
#
|
107
|
+
def self.infer_format_for(path)
|
108
|
+
FILE_FORMATS.fetch(File.extname(path)) do
|
109
|
+
raise(ArgumentError,"cannot infer output format from path: #{path.inspect}")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|