Skip to content

Commit

Permalink
Added the ronin-nmap new command (closes #5).
Browse files Browse the repository at this point in the history
  • Loading branch information
postmodern committed Jun 14, 2024
1 parent f80e842 commit fe512bc
Show file tree
Hide file tree
Showing 6 changed files with 866 additions and 0 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Commands:
grep
help
import
new
print
scan
```
Expand Down Expand Up @@ -95,6 +96,18 @@ Convert an nmap XML scan file to JSON:
$ ronin-nmap convert scan.xml scan.json
```

Generate a new nmap scanner Ruby script:

```shell
$ ronin-nmap new scanner.rb --ports 22,80,443,8000-9000 --target example.com
```

Generate a new nmap XML parser script:

```shell
$ ronin-nmap new parser.rb --parser --xml-file path/to/nmap.xml --printing
```

## Examples

Performing an `nmap` scan and returning the parsed nmap XML data:
Expand Down
56 changes: 56 additions & 0 deletions data/templates/script.rb.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env ruby

require 'ronin/nmap'

<%- if @script_type == :parser -%>
<%- if @xml_file -%>
xml = Ronin::Nmap.parse(<%= @xml_file.inspect %>)
<%- else -%>
xml = Ronin::Nmap.parse(ARGV[0])
<%- end -%>
<%- else -%>
xml = Ronin::Nmap.scan(
<%- case @targets.length -%>
<%- when 0 -%>
ARGV[0],
<%- when 1 -%>
<%= @targets[0].inspect %>,
<%- else -%>
<%= @targets.inspect %>,
<%- end -%>
<%- if @syn_scan -%>
syn_scan: true,
<%- end -%>
<%- if @ports -%>
ports: <%= @ports.inspect %>,
<%- else -%>
# ports: [22, 80, 443, 8000..9000],
<%- end -%>
<%- if @xml_file -%>
xml_file: <%= @xml_file.inspect %>
<%- else -%>
# xml_file: "path/to/file.xml"
<%- end -%>
)
<%- end -%>
<% if @features[:printing] -%>

xml.each_host do |host|
puts "[ #{host.ip} ]"

host.each_port do |port|
puts " #{port.number}/#{port.protocol}\t#{port.state}\t#{port.service}"

port.scripts.each do |id,script|
puts " [ #{id} ]"

script.output.each_line { |line| puts " #{line}" }
end
end
end
<%- end -%>
<%- if @features[:import] -%>

Ronin::DB.connect
Ronin::Nmap::Importer.import(xml)
<%- end -%>
1 change: 1 addition & 0 deletions gemspec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ generated_files:
- man/ronin-nmap-dump.1
- man/ronin-nmap-grep.1
- man/ronin-nmap-import.1
- man/ronin-nmap-new.1
- man/ronin-nmap-print.1
- man/ronin-nmap-scan.1

Expand Down
217 changes: 217 additions & 0 deletions lib/ronin/nmap/cli/commands/new.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
# frozen_string_literal: true
#
# ronin-nmap - A Ruby library for automating nmap and importing nmap scans.
#
# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
#
# ronin-nmap is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ronin-nmap is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with ronin-nmap. If not, see <https://www.gnu.org/licenses/>.
#

require 'ronin/nmap/cli/command'
require 'ronin/nmap/root'

require 'ronin/core/cli/generator'

module Ronin
module Nmap
class CLI
module Commands
#
# Generates a new nmap ruby script.
#
# ## Usage
#
# ronin-nmap new [options] FILE
#
# ## Options
#
# --parser Generate a nmap XML parser script
# --scanner Generate a nmap scanner script
# --printing Adds additional printing of the nmap scan data
# --import Also import the nmap XML scan data
# --xml-file XML_FILE Sets the XML file to write to or parse
# -p {PORT | [PORT1]-[PORT2]},... Sets the port range to scan
# --ports
# --target TARGET Sets the targets to scan (Defaults: ARGV[0])
# -h, --help Print help information
#
# ## Arguments
#
# FILE The path to the new nmap ruby script.
#
# ## Examples
#
# ronin-nmap new scanner.rb --ports 22,80,443,8000-9000 --target example.com
# ronin-nmap new parser.rb --parser --xml-file path/to/nmap.xml --printing
#
class New < Command

include Core::CLI::Generator

template_dir File.join(ROOT,'data','templates')

usage '[options] FILE'

option :parser, desc: 'Generate a nmap XML parser script' do
@script_type = :parser
end

option :scanner, desc: 'Generate a nmap scanner script' do
@script_type = :scanner
end

option :printing, desc: 'Adds additional printing of the nmap scan data' do
@features[:printing] = true
end

option :import, desc: 'Also import the nmap XML scan data' do
@features[:import] = true
end

option :xml_file, value: {
type: String,
usage: 'XML_FILE'
},
desc: 'Sets the XML file to write to or parse' do |file|
@xml_file = file
end

option :ports, short: '-p',
value: {
type: String,
usage: '{PORT | [PORT1]-[PORT2]},...'
},
desc: 'Sets the port range to scan' do |ports|
@ports = parse_port_range(ports)
rescue ArgumentError => error
raise(OptionParser::InvalidArgument,error.message)
end

option :target, value: {
type: String,
usage: 'TARGET'
},
desc: 'Sets the targets to scan (Defaults: ARGV[0])' do |target|
@targets << target
end

argument :path, desc: 'The path to the new nmap ruby script'

description 'Generates a new nmap ruby script'

man_page 'ronin-nmap-new.1'

examples [
"scanner.rb --ports 22,80,443,8000-9000 --target example.com",
"parser.rb --parser --xml-file path/to/nmap.xml --printing"
]

# The script type.
#
# @return [:scan, :parse]
attr_reader :script_type

# The optioanl XML file to write to or parse.
#
# @return [String, nil]
attr_reader :xml_file

# The optional ports to scan.
#
# @return [Array<Integer, Range(Integer,Integer)>, "-", nil]
attr_reader :ports

# The targets to scan.
#
# @return [Array<String>]
attr_reader :targets

# Additional features.
#
# @return [Hash{Symbol => Boolean}]
attr_reader :features

#
# Initializes the `ronin-nmap new` command.
#
# @param [Hash{Symbol => Object}] kwargs
# Additional keyword arguments for the command.
#
def initialize(**kwargs)
super(**kwargs)

@script_type = :scanner
@targets = []
@features = {}
end

#
# Runs the `ronin-nmap new` command.
#
# @param [String] file
# The path to the new nmap ruby script.
#
def run(file)
@directory = File.dirname(file)

mkdir @directory unless File.directory?(@directory)

erb "script.rb.erb", file
chmod '+x', file
end

#
# Parses a port range.
#
# @param [String] ports
# The port range to parse.
#
# @return [Array<Integer, Range(Integer,Integer)>, "-"]
# The parsed port range.
#
# @raise [ArgumentError]
# An invalid port range was given.
#
def parse_port_range(ports)
case ports
when '-' then '-'
else
ports.split(',').map do |port|
case port
when /\A\d+-\d+\z/
start, stop = port.split('-',2)

(start.to_i..stop.to_i)
when /\A\d+-\z/
start = port.chomp('-')

(start.to_i..)
when /\A-\d+\z/
stop = port[1..]

(..stop.to_i)
when /\A\d+\z/
port.to_i
else
raise(ArgumentError,"invalid port range: #{ports.inspect}")
end
end
end
end

end
end
end
end
end
70 changes: 70 additions & 0 deletions man/ronin-nmap-new.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# ronin-nmap-new 1 "2023-03-01" Ronin Nmap "User Manuals"

## NAME

ronin-nmap-new - Generates a new nmap ruby script

## SYNOPSIS

`ronin-nmap new` [options] *FILE*

## DESCRIPTION

Generates a new nmap scanner or parser Ruby script that uses the `ronin-nmap`
library.

## ARGUMENTS

*FILE*
: The path to the new Ruby script to generate.

## OPTIONS

`--parser`
: Generates a new nmap XML parser Ruby script.

`--scanner`
: Generates a new nmap scanner Ruby script.

`--printing`
: Adds additional code to the Ruby script that prints the nmap XML scan data.
Is compatible with both `--parser` and `--scanner`.

`--import`
: Adds additional code to the Ruby script that imports the nmap XML scan data.
Is compatible with both `--parser` and `--scanner`.

`--xml-file` *XML_FILE*
: Parses or writes the scan results to the given XML File.
Is compatible with both `--parser` and `--scanner`.

`-p`, `--port` {*PORT* \| \[*PORT1*\]-\[*PORT2*\]},...
: Specifies the ports to scan. Not compatible with the `--parser` option.

`--target` *TARGET*
: Adds a target to scan. May be a host name, IP, IP CIDR range (ex:
`192.168.1.1/24`), or IP glob range (ex: `192.168.*.1-4`).
Not compatible with the `--parser` option.

`-h`, `--help`
: Print help information

## EXAMPLES

Generates a new nmap scanner Ruby script that scans `example.com`, ports 22, 80,
443, and 8000 through 9000:

$ ronin-nmap new scanner.rb --ports 22,80,443,8000-9000 --target example.com

Generates a new nmap XML parser script that parses `path/to/nmap.xml` and prints
the scan information.

$ ronin-nmap new parser.rb --parser --xml-file path/to/nmap.xml --printing

## AUTHOR

Postmodern <postmodern.mod3@gmail.com>

## SEE ALSO

[ronin-nmap-scan](ronin-nmap-scan.1.md), [ronin-nmap-print](ronin-nmap-print.1.md), [ronin-nmap-import](ronin-nmap-import.1.md)
Loading

0 comments on commit fe512bc

Please sign in to comment.