ronin 2.0.5 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +3 -3
- data/.gitignore +1 -0
- data/.rubocop.yml +5 -1
- data/.ruby-version +1 -1
- data/ChangeLog.md +62 -1
- data/Gemfile +66 -29
- data/README.md +165 -20
- data/Rakefile +9 -0
- data/data/completions/ronin +655 -0
- data/data/templates/dns_proxy.rb.erb +35 -0
- data/gemspec.yml +29 -15
- data/lib/ronin/cli/binary_template.rb +124 -0
- data/lib/ronin/cli/commands/archive.rb +104 -0
- data/lib/ronin/cli/commands/banner_grab.rb +2 -0
- data/lib/ronin/cli/commands/bitflip.rb +1 -1
- data/lib/ronin/cli/commands/bitsquat.rb +119 -0
- data/lib/ronin/cli/commands/cert_dump.rb +20 -4
- data/lib/ronin/cli/commands/cert_gen.rb +9 -19
- data/lib/ronin/cli/commands/cert_grab.rb +4 -3
- data/lib/ronin/cli/commands/completion.rb +115 -0
- data/lib/ronin/cli/commands/dns_proxy.rb +239 -0
- data/lib/ronin/cli/commands/http.rb +80 -8
- data/lib/ronin/cli/commands/ip.rb +101 -0
- data/lib/ronin/cli/commands/iprange.rb +25 -8
- data/lib/ronin/cli/commands/netcat.rb +2 -0
- data/lib/ronin/cli/commands/new/dns_listener.rb +37 -0
- data/lib/ronin/cli/commands/new/dns_proxy.rb +99 -0
- data/lib/ronin/cli/commands/new/exploit.rb +34 -0
- data/lib/ronin/cli/commands/new/http_listener.rb +37 -0
- data/lib/ronin/cli/commands/new/nokogiri.rb +33 -0
- data/lib/ronin/cli/commands/new/payload.rb +34 -0
- data/lib/ronin/cli/commands/new/project.rb +1 -1
- data/lib/ronin/cli/commands/new/script.rb +1 -1
- data/lib/ronin/cli/commands/new/web_app.rb +37 -0
- data/lib/ronin/cli/commands/new/web_server.rb +37 -0
- data/lib/ronin/cli/commands/new/web_spider.rb +37 -0
- data/lib/ronin/cli/commands/new.rb +3 -1
- data/lib/ronin/cli/commands/pack.rb +339 -0
- data/lib/ronin/cli/commands/public_suffix_list.rb +2 -0
- data/lib/ronin/cli/commands/tld_list.rb +2 -0
- data/lib/ronin/cli/commands/unarchive.rb +128 -0
- data/lib/ronin/cli/commands/unhexdump.rb +3 -1
- data/lib/ronin/cli/commands/unpack.rb +195 -0
- data/lib/ronin/cli/commands/url.rb +2 -0
- data/lib/ronin/cli/http_shell.rb +25 -0
- data/lib/ronin/cli.rb +10 -0
- data/lib/ronin/version.rb +1 -1
- data/man/ronin-archive.1.md +49 -0
- data/man/ronin-asn.1 +60 -77
- data/man/ronin-asn.1.md +25 -21
- data/man/ronin-banner-grab.1 +10 -21
- data/man/ronin-banner-grab.1.md +9 -5
- data/man/ronin-bitflip.1 +35 -61
- data/man/ronin-bitflip.1.md +30 -26
- data/man/ronin-bitsquat.1 +40 -0
- data/man/ronin-bitsquat.1.md +43 -0
- data/man/ronin-cert-dump.1 +44 -54
- data/man/ronin-cert-dump.1.md +18 -14
- data/man/ronin-cert-gen.1 +73 -94
- data/man/ronin-cert-gen.1.md +38 -34
- data/man/ronin-cert-grab.1 +29 -37
- data/man/ronin-cert-grab.1.md +12 -8
- data/man/ronin-completion.1 +78 -0
- data/man/ronin-completion.1.md +80 -0
- data/man/ronin-decode.1 +32 -63
- data/man/ronin-decode.1.md +29 -25
- data/man/ronin-decrypt.1 +42 -57
- data/man/ronin-decrypt.1.md +20 -16
- data/man/ronin-dns-proxy.1 +100 -0
- data/man/ronin-dns-proxy.1.md +70 -0
- data/man/ronin-dns.1 +10 -21
- data/man/ronin-dns.1.md +9 -5
- data/man/ronin-email-addr.1 +27 -40
- data/man/ronin-email-addr.1.md +15 -11
- data/man/ronin-encode.1 +93 -63
- data/man/ronin-encode.1.md +64 -26
- data/man/ronin-encrypt.1 +42 -57
- data/man/ronin-encrypt.1.md +20 -16
- data/man/ronin-entropy.1 +11 -21
- data/man/ronin-entropy.1.md +8 -4
- data/man/ronin-escape.1 +22 -46
- data/man/ronin-escape.1.md +22 -18
- data/man/ronin-extract.1 +74 -149
- data/man/ronin-extract.1.md +73 -69
- data/man/ronin-grep.1 +77 -155
- data/man/ronin-grep.1.md +76 -72
- data/man/ronin-help.1 +3 -14
- data/man/ronin-help.1.md +2 -2
- data/man/ronin-hexdump.1 +249 -265
- data/man/ronin-hexdump.1.md +93 -89
- data/man/ronin-highlight.1 +8 -18
- data/man/ronin-highlight.1.md +8 -4
- data/man/ronin-hmac.1 +17 -30
- data/man/ronin-hmac.1.md +14 -10
- data/man/ronin-homoglyph.1 +11 -22
- data/man/ronin-homoglyph.1.md +10 -6
- data/man/ronin-host.1 +23 -47
- data/man/ronin-host.1.md +22 -18
- data/man/ronin-http.1 +40 -69
- data/man/ronin-http.1.md +40 -30
- data/man/ronin-ip.1 +70 -80
- data/man/ronin-ip.1.md +44 -28
- data/man/ronin-iprange.1 +14 -22
- data/man/ronin-iprange.1.md +12 -5
- data/man/ronin-irb.1 +9 -17
- data/man/ronin-irb.1.md +7 -3
- data/man/ronin-md5.1 +13 -24
- data/man/ronin-md5.1.md +11 -7
- data/man/ronin-netcat.1 +25 -51
- data/man/ronin-netcat.1.md +25 -21
- data/man/ronin-new-dns-proxy.1 +45 -0
- data/man/ronin-new-dns-proxy.1.md +44 -0
- data/man/ronin-new-project.1 +32 -45
- data/man/ronin-new-project.1.md +11 -11
- data/man/ronin-new-script.1 +10 -22
- data/man/ronin-new-script.1.md +4 -4
- data/man/ronin-new.1 +56 -31
- data/man/ronin-new.1.md +48 -8
- data/man/ronin-pack.1 +979 -0
- data/man/ronin-pack.1.md +929 -0
- data/man/ronin-proxy.1 +37 -63
- data/man/ronin-proxy.1.md +29 -25
- data/man/ronin-public-suffix-list.1 +16 -32
- data/man/ronin-public-suffix-list.1.md +13 -9
- data/man/ronin-quote.1 +17 -36
- data/man/ronin-quote.1.md +17 -13
- data/man/ronin-rot.1 +26 -39
- data/man/ronin-rot.1.md +15 -11
- data/man/ronin-sha1.1 +13 -24
- data/man/ronin-sha1.1.md +11 -7
- data/man/ronin-sha256.1 +13 -24
- data/man/ronin-sha256.1.md +11 -7
- data/man/ronin-sha512.1 +13 -24
- data/man/ronin-sha512.1.md +11 -7
- data/man/ronin-strings.1 +30 -55
- data/man/ronin-strings.1.md +27 -23
- data/man/ronin-tips.1 +8 -16
- data/man/ronin-tips.1.md +7 -3
- data/man/ronin-tld-list.1 +16 -32
- data/man/ronin-tld-list.1.md +13 -9
- data/man/ronin-typo.1 +14 -28
- data/man/ronin-typo.1.md +13 -9
- data/man/ronin-typosquat.1 +15 -32
- data/man/ronin-typosquat.1.md +15 -11
- data/man/ronin-unarchive.1.md +41 -0
- data/man/ronin-unescape.1 +22 -46
- data/man/ronin-unescape.1.md +22 -18
- data/man/ronin-unhexdump.1 +81 -91
- data/man/ronin-unhexdump.1.md +16 -12
- data/man/ronin-unpack.1 +980 -0
- data/man/ronin-unpack.1.md +920 -0
- data/man/ronin-unquote.1 +17 -36
- data/man/ronin-unquote.1.md +17 -13
- data/man/ronin-url.1 +19 -40
- data/man/ronin-url.1.md +19 -15
- data/man/ronin-xor.1 +14 -28
- data/man/ronin-xor.1.md +13 -9
- data/man/ronin.1 +208 -29
- data/man/ronin.1.md +156 -11
- data/scripts/setup +58 -0
- metadata +157 -67
- data/lib/ronin/config.rb +0 -95
- /data/data/{new → templates}/project/.gitignore +0 -0
- /data/data/{new → templates}/project/.ruby-version.erb +0 -0
- /data/data/{new → templates}/project/Dockerfile.erb +0 -0
- /data/data/{new → templates}/project/Gemfile.erb +0 -0
- /data/data/{new → templates}/project/Rakefile +0 -0
- /data/data/{new → templates}/project/project.rb.erb +0 -0
- /data/data/{new → templates}/script.rb.erb +0 -0
@@ -0,0 +1,115 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
|
4
|
+
#
|
5
|
+
# Ronin is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# Ronin is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with Ronin. If not, see <https://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'ronin/core/cli/completion_command'
|
20
|
+
require 'ronin/repos/cli/commands/completion'
|
21
|
+
require 'ronin/wordlists/cli/commands/completion'
|
22
|
+
require 'ronin/db/cli/commands/completion'
|
23
|
+
require 'ronin/fuzzer/cli/commands/completion'
|
24
|
+
require 'ronin/web/cli/commands/completion'
|
25
|
+
require 'ronin/vulns/cli/commands/completion'
|
26
|
+
require 'ronin/payloads/cli/commands/completion'
|
27
|
+
require 'ronin/exploits/cli/commands/completion'
|
28
|
+
require 'ronin/listener/cli/commands/completion'
|
29
|
+
require 'ronin/nmap/cli/commands/completion'
|
30
|
+
require 'ronin/masscan/cli/commands/completion'
|
31
|
+
require 'ronin/recon/cli/commands/completion'
|
32
|
+
require 'ronin/root'
|
33
|
+
|
34
|
+
module Ronin
|
35
|
+
class CLI
|
36
|
+
module Commands
|
37
|
+
#
|
38
|
+
# Manages the shell completion rule for `ronin` and all other `ronin-*`
|
39
|
+
# commands.
|
40
|
+
#
|
41
|
+
# ## Usage
|
42
|
+
#
|
43
|
+
# ronin completion [options]
|
44
|
+
#
|
45
|
+
# ## Options
|
46
|
+
#
|
47
|
+
# --print Prints the shell completion file
|
48
|
+
# --install Installs the shell completion file
|
49
|
+
# --uninstall Uninstalls the shell completion file
|
50
|
+
# -h, --help Print help information
|
51
|
+
#
|
52
|
+
# ## Examples
|
53
|
+
#
|
54
|
+
# ronin completion --print
|
55
|
+
# ronin completion --install
|
56
|
+
# ronin completion --uninstall
|
57
|
+
#
|
58
|
+
# @since 2.1.0
|
59
|
+
#
|
60
|
+
class Completion < Core::CLI::CompletionCommand
|
61
|
+
|
62
|
+
man_dir File.join(ROOT,'man')
|
63
|
+
man_page 'ronin-completion.1'
|
64
|
+
|
65
|
+
description 'Manages the shell completion rules for ronin and all other ronin-* commands'
|
66
|
+
|
67
|
+
# All shell completion files for `ronin` and the other `ronin-*`
|
68
|
+
# commands.
|
69
|
+
COMPLETION_FILES = [
|
70
|
+
File.join(ROOT,'data','completions','ronin'),
|
71
|
+
|
72
|
+
Repos::CLI::Commands::Completion.completion_file,
|
73
|
+
Wordlists::CLI::Commands::Completion.completion_file,
|
74
|
+
DB::CLI::Commands::Completion.completion_file,
|
75
|
+
Fuzzer::CLI::Commands::Completion.completion_file,
|
76
|
+
Web::CLI::Commands::Completion.completion_file,
|
77
|
+
Vulns::CLI::Commands::Completion.completion_file,
|
78
|
+
Payloads::CLI::Commands::Completion.completion_file,
|
79
|
+
Exploits::CLI::Commands::Completion.completion_file,
|
80
|
+
Listener::CLI::Commands::Completion.completion_file,
|
81
|
+
Nmap::CLI::Commands::Completion.completion_file,
|
82
|
+
Masscan::CLI::Commands::Completion.completion_file,
|
83
|
+
Recon::CLI::Commands::Completion.completion_file
|
84
|
+
]
|
85
|
+
|
86
|
+
#
|
87
|
+
# Prints all completion files.
|
88
|
+
#
|
89
|
+
def print_completion_file
|
90
|
+
COMPLETION_FILES.each do |completion_file|
|
91
|
+
super(completion_file)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
# Installs all completion files.
|
97
|
+
#
|
98
|
+
def install_completion_file
|
99
|
+
COMPLETION_FILES.each do |completion_file|
|
100
|
+
super(completion_file)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
#
|
105
|
+
# Uninstall all completion files.
|
106
|
+
#
|
107
|
+
def uninstall_completion_file
|
108
|
+
COMPLETION_FILES.each do |completion_file|
|
109
|
+
super(completion_file)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,239 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
|
4
|
+
#
|
5
|
+
# Ronin is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# Ronin is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with Ronin. If not, see <https://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'ronin/cli/command'
|
20
|
+
require 'ronin/core/cli/logging'
|
21
|
+
require 'ronin/dns/proxy'
|
22
|
+
|
23
|
+
module Ronin
|
24
|
+
class CLI
|
25
|
+
module Commands
|
26
|
+
#
|
27
|
+
# Starts a DNS proxy.
|
28
|
+
#
|
29
|
+
# ## Usage
|
30
|
+
#
|
31
|
+
# ronin dns-proxy [options] [HOST] PORT
|
32
|
+
#
|
33
|
+
# ## Options
|
34
|
+
#
|
35
|
+
# -n, --nameserver IP The upstream nameserver IP to use
|
36
|
+
# -r RECORD_TYPE:NAME:RESULT|RECORD_TYPE:/REGEXP/:RESULT,
|
37
|
+
# --rule Adds a rule to the DNS proxy
|
38
|
+
# -h, --help Print help information
|
39
|
+
#
|
40
|
+
# ## Arguments
|
41
|
+
#
|
42
|
+
# [HOST] The host name to listen on.
|
43
|
+
# PORT The port number to listen on.
|
44
|
+
#
|
45
|
+
# @since 2.1.0
|
46
|
+
#
|
47
|
+
class DnsProxy < Command
|
48
|
+
|
49
|
+
include Core::CLI::Logging
|
50
|
+
|
51
|
+
usage '[options] [HOST] PORT'
|
52
|
+
|
53
|
+
option :nameserver, short: '-n',
|
54
|
+
value: {
|
55
|
+
type: String,
|
56
|
+
usage: 'IP'
|
57
|
+
},
|
58
|
+
desc: 'The upstream nameserver IP to use' do |ip|
|
59
|
+
@nameservers << ip
|
60
|
+
end
|
61
|
+
|
62
|
+
option :rule, short: '-r',
|
63
|
+
value: {
|
64
|
+
type: %r{\A[^:]+:(?:[^:]+|/[^/:]+/):.+\z},
|
65
|
+
usage: 'RECORD_TYPE:NAME:RESULT|RECORD_TYPE:/REGEXP/:RESULT'
|
66
|
+
},
|
67
|
+
desc: 'Adds a rule to the DNS proxy' do |rule|
|
68
|
+
@rules << parse_rule(rule)
|
69
|
+
end
|
70
|
+
|
71
|
+
argument :host, required: false,
|
72
|
+
desc: 'The host to listen on'
|
73
|
+
|
74
|
+
argument :port, required: true,
|
75
|
+
desc: 'The port number to listen on'
|
76
|
+
|
77
|
+
description 'Starts a DNS proxy'
|
78
|
+
|
79
|
+
man_page 'ronin-dns-proxy.1'
|
80
|
+
|
81
|
+
# The upstream nameserver IP addresses to forward DNS queries to.
|
82
|
+
#
|
83
|
+
# @return [Array<String>]
|
84
|
+
attr_reader :nameservers
|
85
|
+
|
86
|
+
# The rules for the DNS proxy server.
|
87
|
+
#
|
88
|
+
# @return [Array<(Symbol, String, String), (Symbol, Regexp, String)>]
|
89
|
+
attr_reader :rules
|
90
|
+
|
91
|
+
#
|
92
|
+
# Initializes the `ronin dns-proxy` command.
|
93
|
+
#
|
94
|
+
# @param [Hash{Symbol => Object}] kwargs
|
95
|
+
# Additional keyword arguments for the command.
|
96
|
+
#
|
97
|
+
def initialize(**kwargs)
|
98
|
+
super(**kwargs)
|
99
|
+
|
100
|
+
@nameservers = []
|
101
|
+
@rules = []
|
102
|
+
end
|
103
|
+
|
104
|
+
#
|
105
|
+
# Runs the `ronin dns-proxy` command.
|
106
|
+
#
|
107
|
+
def run(host='127.0.0.1',port)
|
108
|
+
port = port.to_i
|
109
|
+
|
110
|
+
log_info "Listening on #{host}:#{port} ..."
|
111
|
+
DNS::Proxy.run(host,port,**proxy_kwargs)
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# The keyword arguments for `Ronin::DNS::Proxy.run`.
|
116
|
+
#
|
117
|
+
# @return [Hash{Symbol => Object}]
|
118
|
+
#
|
119
|
+
def proxy_kwargs
|
120
|
+
kwargs = {rules: @rules}
|
121
|
+
|
122
|
+
unless @nameservers.empty?
|
123
|
+
kwargs[:nameservers] = @nameservers
|
124
|
+
end
|
125
|
+
|
126
|
+
return kwargs
|
127
|
+
end
|
128
|
+
|
129
|
+
# Record types.
|
130
|
+
RECORD_TYPES = {
|
131
|
+
'A' => :A,
|
132
|
+
'AAAA' => :AAAA,
|
133
|
+
'ANY' => :ANY,
|
134
|
+
'CNAME' => :CNAME,
|
135
|
+
'HINFO' => :HINFO,
|
136
|
+
'LOC' => :LOC,
|
137
|
+
'MINFO' => :MINFO,
|
138
|
+
'MX' => :MX,
|
139
|
+
'NS' => :NS,
|
140
|
+
'PTR' => :PTR,
|
141
|
+
'SOA' => :SOA,
|
142
|
+
'SRV' => :SRV,
|
143
|
+
'TXT' => :TXT,
|
144
|
+
'WKS' => :WKS
|
145
|
+
}
|
146
|
+
|
147
|
+
#
|
148
|
+
# Parses a record type name.
|
149
|
+
#
|
150
|
+
# @param [String] record_type
|
151
|
+
# The record type to parse.
|
152
|
+
#
|
153
|
+
# @return [:A, :AAAA, :ANY, :CNAME, :HINFO, :LOC, :MINFO, :MX, :NS, :PTR, :SOA, :SRV, :TXT, :WKS]
|
154
|
+
# The parsed record type.
|
155
|
+
#
|
156
|
+
# @raise [OptionParser::InvalidArgument]
|
157
|
+
# The record type was unknown.
|
158
|
+
#
|
159
|
+
def parse_record_type(record_type)
|
160
|
+
RECORD_TYPES.fetch(record_type) do
|
161
|
+
raise(OptionParser::InvalidArgument,"invalid record type: #{record_type.inspect}")
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
#
|
166
|
+
# Parses the name field of a record.
|
167
|
+
#
|
168
|
+
# @param [String] name
|
169
|
+
# The name field to parse.
|
170
|
+
#
|
171
|
+
# @return [String, Regex]
|
172
|
+
# The parsed name. If the name field starts with a `/` and ends with a
|
173
|
+
# `/`, then a Regexp will be returned.
|
174
|
+
#
|
175
|
+
# @raise [OptionParser::InvalidArgument]
|
176
|
+
# The name field regex could not be parsed.
|
177
|
+
#
|
178
|
+
def parse_record_name(name)
|
179
|
+
if name.start_with?('/') && name.end_with?('/')
|
180
|
+
begin
|
181
|
+
Regexp.new(name[1..-2])
|
182
|
+
rescue RegexpError => error
|
183
|
+
raise(OptionParser::InvalidArgument,"invalid Regexp: #{error.message}")
|
184
|
+
end
|
185
|
+
else
|
186
|
+
name
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Error names.
|
191
|
+
ERROR_CODES = {
|
192
|
+
'NoError' => :NoError,
|
193
|
+
'FormErr' => :FormErr,
|
194
|
+
'ServFail' => :ServFail,
|
195
|
+
'NXDomain' => :NXDomain,
|
196
|
+
'NotImp' => :NotImp,
|
197
|
+
'Refused' => :Refused,
|
198
|
+
'NotAuth' => :NotAuth
|
199
|
+
}
|
200
|
+
|
201
|
+
#
|
202
|
+
# Parses a result value.
|
203
|
+
#
|
204
|
+
# @param [String] result
|
205
|
+
# A result value to parse.
|
206
|
+
#
|
207
|
+
# @return [String, :NoError, :FormErr, :ServFail, :NXDomain, :NotImp, :Refused, :NotAuth]
|
208
|
+
# The parsed result value or a DNS error code.
|
209
|
+
#
|
210
|
+
def parse_rule_result(result)
|
211
|
+
ERROR_CODES.fetch(result,result)
|
212
|
+
end
|
213
|
+
|
214
|
+
#
|
215
|
+
# Parses a rule string.
|
216
|
+
#
|
217
|
+
# @param [String] rule
|
218
|
+
# The string to parse.
|
219
|
+
#
|
220
|
+
# @return [(Symbol, String, String), (Symbol, Regexp, String)]
|
221
|
+
# The parsed rule.
|
222
|
+
#
|
223
|
+
# @raise [OptionParser::InvalidArgument]
|
224
|
+
# The rule string could not be parsed.
|
225
|
+
#
|
226
|
+
def parse_rule(rule)
|
227
|
+
record_type, name, result = rule.split(':',3)
|
228
|
+
|
229
|
+
[
|
230
|
+
parse_record_type(record_type),
|
231
|
+
parse_record_name(name),
|
232
|
+
parse_rule_result(result)
|
233
|
+
]
|
234
|
+
end
|
235
|
+
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
@@ -20,6 +20,7 @@ require 'ronin/cli/value_processor_command'
|
|
20
20
|
require 'ronin/cli/printing/http'
|
21
21
|
require 'ronin/cli/http_shell'
|
22
22
|
require 'ronin/support/network/http'
|
23
|
+
require 'ronin/support/network/http/cookie'
|
23
24
|
|
24
25
|
require 'command_kit/options/verbose'
|
25
26
|
require 'addressable/uri'
|
@@ -57,9 +58,11 @@ module Ronin
|
|
57
58
|
# --shell URL Open an interactive HTTP shell
|
58
59
|
# -P, --proxy URL The proxy to use
|
59
60
|
# -U, --user-agent-string STRING The User-Agent string to use
|
60
|
-
# -u chrome
|
61
|
-
# --user-agent The User-Agent to use
|
61
|
+
# -u random|chrome|firefox|safari|linux|macos|windows|iphone|ipad|android|chrome_linux|chrome_macos|chrome_windows|chrome_iphone|chrome_ipad|chrome_android|firefox_linux|firefox_macos|firefox_windows|firefox_iphone|firefox_ipad|firefox_android|safari_macos|safari_iphone|safari_ipad|edge,
|
62
|
+
# --user-agent The User-Agent alias to use
|
62
63
|
# -H, --header "NAME: VALUE" Adds a header to the request
|
64
|
+
# -C, --cookie COOKIE Sets the Cookie header
|
65
|
+
# -c, --cookie-param NAME=VALUE Sets an additional cookie param
|
63
66
|
# -B, --body STRING The request body
|
64
67
|
# -F, --body-file FILE Sends the file as the request body
|
65
68
|
# -f, --form-data NAME=VALUE Adds a value to the form data
|
@@ -76,7 +79,7 @@ module Ronin
|
|
76
79
|
include Printing::HTTP
|
77
80
|
|
78
81
|
# `http://` and `https://` URL validation regex.
|
79
|
-
URL_REGEX = URI::DEFAULT_PARSER.make_regexp(%w[http https])
|
82
|
+
URL_REGEX = /\A#{URI::DEFAULT_PARSER.make_regexp(%w[http https])}\z/
|
80
83
|
|
81
84
|
usage '[options] {URL [...] | --shell URL}'
|
82
85
|
|
@@ -178,13 +181,46 @@ module Ronin
|
|
178
181
|
@user_agent = ua
|
179
182
|
end
|
180
183
|
|
184
|
+
# Mapping of user-agent aliases.
|
185
|
+
USER_AGENT_ALIASES = {
|
186
|
+
'random' => :random,
|
187
|
+
'chrome' => :chrome,
|
188
|
+
'firefox' => :firefox,
|
189
|
+
'safari' => :safari,
|
190
|
+
'linux' => :linux,
|
191
|
+
'macos' => :macos,
|
192
|
+
'windows' => :windows,
|
193
|
+
'iphone' => :iphone,
|
194
|
+
'ipad' => :ipad,
|
195
|
+
'android' => :android,
|
196
|
+
|
197
|
+
'chrome_linux' => :chrome_linux,
|
198
|
+
'chrome_macos' => :chrome_macos,
|
199
|
+
'chrome_windows' => :chrome_windows,
|
200
|
+
'chrome_iphone' => :chrome_iphone,
|
201
|
+
'chrome_ipad' => :chrome_ipad,
|
202
|
+
'chrome_android' => :chrome_android,
|
203
|
+
|
204
|
+
'firefox_linux' => :firefox_linux,
|
205
|
+
'firefox_macos' => :firefox_macos,
|
206
|
+
'firefox_windows' => :firefox_windows,
|
207
|
+
'firefox_iphone' => :firefox_iphone,
|
208
|
+
'firefox_ipad' => :firefox_ipad,
|
209
|
+
|
210
|
+
'firefox_android' => :firefox_android,
|
211
|
+
|
212
|
+
'safari_macos' => :safari_macos,
|
213
|
+
'safari_iphone' => :safari_iphone,
|
214
|
+
'safari_ipad' => :safari_ipad,
|
215
|
+
|
216
|
+
'edge' => :edge
|
217
|
+
}
|
218
|
+
|
181
219
|
option :user_agent, short: '-u',
|
182
220
|
value: {
|
183
|
-
type:
|
184
|
-
key.to_s.tr('_','-')
|
185
|
-
}
|
221
|
+
type: USER_AGENT_ALIASES
|
186
222
|
},
|
187
|
-
desc: 'The User-Agent to use' do |name|
|
223
|
+
desc: 'The User-Agent alias to use' do |name|
|
188
224
|
@user_agent = name
|
189
225
|
end
|
190
226
|
|
@@ -199,6 +235,35 @@ module Ronin
|
|
199
235
|
@headers[name] = value
|
200
236
|
end
|
201
237
|
|
238
|
+
option :cookie, short: '-C',
|
239
|
+
value: {
|
240
|
+
type: String,
|
241
|
+
usage: 'COOKIE'
|
242
|
+
},
|
243
|
+
desc: 'Sets the Cookie header' do |cookie|
|
244
|
+
cookie = Support::Network::HTTP::Cookie.parse(cookie)
|
245
|
+
|
246
|
+
if @cookie
|
247
|
+
@cookie.merge!(cookie)
|
248
|
+
else
|
249
|
+
@cookie = cookie
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
option :cookie_param, short: '-c',
|
254
|
+
value: {
|
255
|
+
type: /[^\s=]+=\w+/,
|
256
|
+
usage: 'NAME=VALUE'
|
257
|
+
},
|
258
|
+
desc: 'Sets an additional cookie param' do |param|
|
259
|
+
name, value = param.split('=',2)
|
260
|
+
|
261
|
+
# lazy initialize the cookie
|
262
|
+
@cookie ||= Support::Network::HTTP::Cookie.new
|
263
|
+
|
264
|
+
@cookie[name] = value
|
265
|
+
end
|
266
|
+
|
202
267
|
option :body, short: '-B',
|
203
268
|
value: {
|
204
269
|
type: String,
|
@@ -262,9 +327,14 @@ module Ronin
|
|
262
327
|
# @return [Hash{String => String}]
|
263
328
|
attr_reader :headers
|
264
329
|
|
330
|
+
# The optional `Cookie` header to send.
|
331
|
+
#
|
332
|
+
# @return [Ronin::Support::Network::HTTP::Cookie, nil]
|
333
|
+
attr_reader :cookie
|
334
|
+
|
265
335
|
# Optional `User-agent` string to use.
|
266
336
|
#
|
267
|
-
# @return [String, nil]
|
337
|
+
# @return [String, Symbol, nil]
|
268
338
|
attr_reader :user_agent
|
269
339
|
|
270
340
|
# Additional URL query params.
|
@@ -294,6 +364,7 @@ module Ronin
|
|
294
364
|
@proxy = nil
|
295
365
|
@http_method = :get
|
296
366
|
@headers = {}
|
367
|
+
@cookie = nil
|
297
368
|
@user_agent = nil
|
298
369
|
@query_params = {}
|
299
370
|
@form_data = {}
|
@@ -347,6 +418,7 @@ module Ronin
|
|
347
418
|
begin
|
348
419
|
Support::Network::HTTP.request(
|
349
420
|
@http_method, uri, proxy: @proxy,
|
421
|
+
cookie: @cookie,
|
350
422
|
user_agent: @user_agent,
|
351
423
|
query_params: @query_params,
|
352
424
|
headers: @headers,
|
@@ -19,6 +19,7 @@
|
|
19
19
|
require 'ronin/cli/value_processor_command'
|
20
20
|
require 'ronin/support/network/ip'
|
21
21
|
require 'uri'
|
22
|
+
require 'ipaddr'
|
22
23
|
|
23
24
|
module Ronin
|
24
25
|
class CLI
|
@@ -40,6 +41,10 @@ module Ronin
|
|
40
41
|
# -D, --decimal Converts the IP address to decimal format
|
41
42
|
# -O, --octal Converts the IP address to octal format
|
42
43
|
# -B, --binary Converts the IP address to binary format
|
44
|
+
# --hex-octet Converts the IP address to hexadecimal format by octet
|
45
|
+
# --octal-octet Converts the IP address to octal format by octet
|
46
|
+
# --ipv6-compat Converts the IPv4 address to an IPv6 compatible address
|
47
|
+
# --ipv6-expanded Expands a shortened or compressed IPv6 address
|
43
48
|
# -C, --cidr NETMASK Converts the IP address into a CIDR range
|
44
49
|
# -H, --host Converts the IP address to a host name
|
45
50
|
# -p, --port PORT Appends the port number to each IP
|
@@ -89,6 +94,16 @@ module Ronin
|
|
89
94
|
option :binary, short: '-B',
|
90
95
|
desc: 'Converts the IP address to binary format'
|
91
96
|
|
97
|
+
option :hex_octet,
|
98
|
+
desc: 'Converts the IP address to hexadecimal format by octet'
|
99
|
+
|
100
|
+
option :octal_octet,
|
101
|
+
desc: 'Converts the IP address to octal format by octet'
|
102
|
+
|
103
|
+
option :ipv6_compat, desc: 'Converts the IPv4 address to an IPv6 compatible address'
|
104
|
+
|
105
|
+
option :ipv6_expanded, desc: 'Expands a shortened or compressed IPv6 address'
|
106
|
+
|
92
107
|
option :cidr, short: '-C',
|
93
108
|
value: {
|
94
109
|
type: String,
|
@@ -225,19 +240,105 @@ module Ronin
|
|
225
240
|
# The formatted IP address.
|
226
241
|
#
|
227
242
|
def format_ip(ip)
|
243
|
+
if ip.ipv4?
|
244
|
+
format_ipv4(ip)
|
245
|
+
else
|
246
|
+
format_ipv6(ip)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
private
|
251
|
+
|
252
|
+
#
|
253
|
+
# Formats an IPv4 address.
|
254
|
+
#
|
255
|
+
# @param [Ronin::Support::Network::IP] ip
|
256
|
+
# The IP address to format.
|
257
|
+
#
|
258
|
+
# @return [String]
|
259
|
+
# The formatted IP address.
|
260
|
+
#
|
261
|
+
def format_ipv4(ip)
|
228
262
|
if options[:hex]
|
229
263
|
"0x%x" % ip.to_i
|
264
|
+
elsif options[:hex_octet]
|
265
|
+
ipv4_hex_octet(ip)
|
230
266
|
elsif options[:decimal]
|
231
267
|
"%u" % ip.to_i
|
232
268
|
elsif options[:octal]
|
233
269
|
"0%o" % ip.to_i
|
270
|
+
elsif options[:octal_octet]
|
271
|
+
ip.to_s.split(".").map { |octet| "0%o" % octet.to_i }.join(".")
|
272
|
+
elsif options[:binary]
|
273
|
+
"%b" % ip.to_i
|
274
|
+
elsif options[:ipv6_compat]
|
275
|
+
ip.ipv4_mapped.to_s
|
276
|
+
elsif options[:ipv6_expanded]
|
277
|
+
print_error "called with --ipv6-expanded for #{ip}"
|
278
|
+
exit(1)
|
279
|
+
else
|
280
|
+
ip.to_s
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
#
|
285
|
+
# Formats an IPv6 address.
|
286
|
+
#
|
287
|
+
# @param [Ronin::Support::Network::IP] ip
|
288
|
+
# The IP address to format.
|
289
|
+
#
|
290
|
+
# @return [String]
|
291
|
+
# The formatted IP address.
|
292
|
+
#
|
293
|
+
def format_ipv6(ip)
|
294
|
+
if options[:decimal]
|
295
|
+
"%u" % ip.to_i
|
296
|
+
elsif options[:hex]
|
297
|
+
"0x%x" % ip.to_i
|
298
|
+
elsif options[:octal]
|
299
|
+
"0%o" % ip.to_i
|
300
|
+
elsif options[:octal_octet]
|
301
|
+
print_error "called with --octal-octet for #{ip}"
|
302
|
+
exit(1)
|
303
|
+
elsif options[:hex_octet]
|
304
|
+
if ip.ipv4_mapped?
|
305
|
+
"::ffff:#{ipv4_hex_octet(ip.ipv4)}"
|
306
|
+
else
|
307
|
+
print_error "called with --hex-octet for #{ip}"
|
308
|
+
exit(1)
|
309
|
+
end
|
234
310
|
elsif options[:binary]
|
235
311
|
"%b" % ip.to_i
|
312
|
+
elsif options[:ipv6_expanded]
|
313
|
+
ip.canonical
|
314
|
+
elsif options[:ipv6_compat]
|
315
|
+
print_error "called with --ipv6-compat for #{ip}"
|
316
|
+
exit(1)
|
236
317
|
else
|
237
318
|
ip.to_s
|
238
319
|
end
|
239
320
|
end
|
240
321
|
|
322
|
+
#
|
323
|
+
# Converts the octets of an IP address to hex
|
324
|
+
#
|
325
|
+
# @param [Ronin::Support::Network::IP] ip
|
326
|
+
# The IP address to convert.
|
327
|
+
#
|
328
|
+
# @return [String]
|
329
|
+
# The formatted IP address.
|
330
|
+
#
|
331
|
+
def ipv4_hex_octet(ip)
|
332
|
+
ip_uint = ip.to_i
|
333
|
+
|
334
|
+
format(
|
335
|
+
"%<octet1>x.%<octet2>x.%<octet3>x.%<octet4>x",
|
336
|
+
octet1: (ip_uint & 0xff000000) >> 24,
|
337
|
+
octet2: (ip_uint & 0xff0000) >> 16,
|
338
|
+
octet3: (ip_uint & 0xff00) >> 8,
|
339
|
+
octet4: (ip_uint & 0xff)
|
340
|
+
)
|
341
|
+
end
|
241
342
|
end
|
242
343
|
end
|
243
344
|
end
|