ronin 1.5.0.rc2 → 1.5.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.
- data/ChangeLog.md +1 -1
- data/Gemfile +1 -2
- data/README.md +4 -0
- data/bin/ronin-fuzzer +25 -0
- data/gemspec.yml +3 -2
- data/lib/ronin/auto_load.rb +2 -0
- data/lib/ronin/database/migrations/graph.rb +2 -2
- data/lib/ronin/email_address.rb +1 -1
- data/lib/ronin/host_name.rb +1 -1
- data/lib/ronin/installation.rb +13 -13
- data/lib/ronin/ip_address.rb +1 -1
- data/lib/ronin/mac_address.rb +1 -1
- data/lib/ronin/model/importable.rb +1 -1
- data/lib/ronin/repository.rb +1 -1
- data/lib/ronin/ui/cli/cli.rb +2 -1
- data/lib/ronin/ui/cli/command.rb +2 -2
- data/lib/ronin/ui/cli/commands/database.rb +5 -8
- data/lib/ronin/ui/cli/commands/fuzzer.rb +306 -0
- data/lib/ronin/ui/cli/commands/net/proxy.rb +1 -0
- data/lib/ronin/ui/cli/model_command.rb +1 -1
- data/lib/ronin/url.rb +28 -28
- data/lib/ronin/version.rb +1 -1
- data/man/ronin-fuzzer.1.md +73 -0
- data/spec/installation_spec.rb +7 -31
- data/spec/ui/cli/cli_spec.rb +34 -0
- metadata +12 -6
data/ChangeLog.md
CHANGED
data/Gemfile
CHANGED
@@ -23,8 +23,7 @@ gem 'jruby-openssl', '~> 0.7', :platforms => :jruby
|
|
23
23
|
# gem 'dm-timestamps', DM_VERSION, :git => "#{DM_URI}/dm-timestamps.git"
|
24
24
|
|
25
25
|
# Library dependencies
|
26
|
-
# gem 'ronin-support', '~> 0.5
|
27
|
-
# :branch => '0.5.0'
|
26
|
+
# gem 'ronin-support', '~> 0.5', :git => "#{RONIN_URI}/ronin-support.git"
|
28
27
|
|
29
28
|
group :development do
|
30
29
|
gem 'rake', '~> 0.8'
|
data/README.md
CHANGED
data/bin/ronin-fuzzer
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
root_dir = File.expand_path(File.join(File.dirname(__FILE__),'..'))
|
6
|
+
if File.directory?(File.join(root_dir,'.git'))
|
7
|
+
Dir.chdir(root_dir) do |path|
|
8
|
+
require 'bundler'
|
9
|
+
|
10
|
+
begin
|
11
|
+
Bundler.setup(:default)
|
12
|
+
rescue Bundler::BundlerError => e
|
13
|
+
warn e.message
|
14
|
+
warn "Run `bundle install` to install missing gems"
|
15
|
+
exit e.status_code
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
lib_dir = File.join(root_dir,'lib')
|
21
|
+
$LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
|
22
|
+
|
23
|
+
require 'ronin/ui/cli/commands/fuzzer'
|
24
|
+
|
25
|
+
Ronin::UI::CLI::Commands::Fuzzer.start
|
data/gemspec.yml
CHANGED
@@ -8,7 +8,7 @@ description:
|
|
8
8
|
license: GPL-3
|
9
9
|
authors: Postmodern
|
10
10
|
email: postmodern.mod3@gmail.com
|
11
|
-
homepage: http://github.com/
|
11
|
+
homepage: http://ronin-ruby.github.com/
|
12
12
|
has_yard: true
|
13
13
|
post_install_message: |
|
14
14
|
*************************************************************************
|
@@ -41,6 +41,7 @@ generated_files:
|
|
41
41
|
- man/ronin-database.1
|
42
42
|
- man/ronin-emails.1
|
43
43
|
- man/ronin-exec.1
|
44
|
+
- man/ronin-fuzzer.1
|
44
45
|
- man/ronin-help.1
|
45
46
|
- man/ronin-hosts.1
|
46
47
|
- man/ronin-install.1
|
@@ -80,7 +81,7 @@ dependencies:
|
|
80
81
|
ripl-short_errors: ~> 0.1
|
81
82
|
ripl-color_result: ~> 0.3
|
82
83
|
# Ronin dependencies:
|
83
|
-
ronin-support: ~> 0.5
|
84
|
+
ronin-support: ~> 0.5
|
84
85
|
|
85
86
|
development_dependencies:
|
86
87
|
bundler: ~> 1.0
|
data/lib/ronin/auto_load.rb
CHANGED
@@ -212,7 +212,7 @@ module Ronin
|
|
212
212
|
# @api semipublic
|
213
213
|
#
|
214
214
|
def upto(position_or_name=nil)
|
215
|
-
return enum_for(
|
215
|
+
return enum_for(__method__,position_or_name) unless block_given?
|
216
216
|
|
217
217
|
name = name_of(position_or_name)
|
218
218
|
|
@@ -250,7 +250,7 @@ module Ronin
|
|
250
250
|
# @api semipublic
|
251
251
|
#
|
252
252
|
def downto(position_or_name=nil)
|
253
|
-
return enum_for(
|
253
|
+
return enum_for(__method__,position_or_name) unless block_given?
|
254
254
|
|
255
255
|
name = name_of(position_or_name)
|
256
256
|
|
data/lib/ronin/email_address.rb
CHANGED
data/lib/ronin/host_name.rb
CHANGED
data/lib/ronin/installation.rb
CHANGED
@@ -39,7 +39,7 @@ module Ronin
|
|
39
39
|
#
|
40
40
|
# @api semipublic
|
41
41
|
#
|
42
|
-
def
|
42
|
+
def self.gems
|
43
43
|
load! if @gems.empty?
|
44
44
|
return @gems
|
45
45
|
end
|
@@ -54,7 +54,7 @@ module Ronin
|
|
54
54
|
#
|
55
55
|
# @api semipublic
|
56
56
|
#
|
57
|
-
def
|
57
|
+
def self.paths
|
58
58
|
load! if @paths.empty?
|
59
59
|
return @paths
|
60
60
|
end
|
@@ -69,7 +69,7 @@ module Ronin
|
|
69
69
|
#
|
70
70
|
# @api semipublic
|
71
71
|
#
|
72
|
-
def
|
72
|
+
def self.libraries
|
73
73
|
gems.keys
|
74
74
|
end
|
75
75
|
|
@@ -93,8 +93,8 @@ module Ronin
|
|
93
93
|
#
|
94
94
|
# @api semipublic
|
95
95
|
#
|
96
|
-
def
|
97
|
-
return enum_for(
|
96
|
+
def self.each_file(pattern)
|
97
|
+
return enum_for(__method__,pattern) unless block_given?
|
98
98
|
|
99
99
|
# query the installed gems
|
100
100
|
paths.each do |gem_path|
|
@@ -130,16 +130,16 @@ module Ronin
|
|
130
130
|
#
|
131
131
|
# @api semipublic
|
132
132
|
#
|
133
|
-
def
|
134
|
-
return enum_for(
|
133
|
+
def self.each_file_in(directory,ext=nil)
|
134
|
+
return enum_for(__method__,directory,ext) unless block_given?
|
135
|
+
|
136
|
+
directory = File.join(directory,File::SEPARATOR)
|
135
137
|
|
136
138
|
pattern = File.join(directory,'**','*')
|
137
139
|
pattern << ".#{ext}" if ext
|
138
140
|
|
139
|
-
slice_index = directory.length + 1
|
140
|
-
|
141
141
|
each_file(pattern) do |path|
|
142
|
-
yield path
|
142
|
+
yield path.sub(directory,'')
|
143
143
|
end
|
144
144
|
end
|
145
145
|
|
@@ -155,7 +155,7 @@ module Ronin
|
|
155
155
|
#
|
156
156
|
# @api private
|
157
157
|
#
|
158
|
-
def
|
158
|
+
def self.load_gems!
|
159
159
|
register_gem = lambda { |gem|
|
160
160
|
@gems[gem.name] = gem
|
161
161
|
@paths << gem.full_gem_path
|
@@ -184,7 +184,7 @@ module Ronin
|
|
184
184
|
#
|
185
185
|
# @api private
|
186
186
|
#
|
187
|
-
def
|
187
|
+
def self.load_gemspecs!
|
188
188
|
$LOAD_PATH.each do |lib_dir|
|
189
189
|
root_dir = File.expand_path(File.join(lib_dir,'..'))
|
190
190
|
gemspec_path = Dir[File.join(root_dir,'ronin*.gemspec')][0]
|
@@ -216,7 +216,7 @@ module Ronin
|
|
216
216
|
#
|
217
217
|
# @api private
|
218
218
|
#
|
219
|
-
def
|
219
|
+
def self.load!
|
220
220
|
if Gem.loaded_specs.has_key?('ronin')
|
221
221
|
load_gems!
|
222
222
|
else
|
data/lib/ronin/ip_address.rb
CHANGED
@@ -98,7 +98,7 @@ module Ronin
|
|
98
98
|
# @api public
|
99
99
|
#
|
100
100
|
def self.extract(text,version=nil)
|
101
|
-
return enum_for(
|
101
|
+
return enum_for(__method__,text,version).to_a unless block_given?
|
102
102
|
|
103
103
|
IPAddr.extract(text,version) do |ip|
|
104
104
|
yield parse(ip)
|
data/lib/ronin/mac_address.rb
CHANGED
data/lib/ronin/repository.rb
CHANGED
data/lib/ronin/ui/cli/cli.rb
CHANGED
@@ -94,8 +94,9 @@ module Ronin
|
|
94
94
|
#
|
95
95
|
def CLI.command(name)
|
96
96
|
name = name.to_s
|
97
|
+
path = name.tr(':','/')
|
97
98
|
|
98
|
-
unless (command = Commands.require_const(
|
99
|
+
unless (command = Commands.require_const(path))
|
99
100
|
raise(UnknownCommand,"unable to load the command #{name.dump}",caller)
|
100
101
|
end
|
101
102
|
|
data/lib/ronin/ui/cli/command.rb
CHANGED
@@ -471,7 +471,7 @@ module Ronin
|
|
471
471
|
# @api private
|
472
472
|
#
|
473
473
|
def self.each_option(&block)
|
474
|
-
return enum_for(
|
474
|
+
return enum_for(__method__) unless block
|
475
475
|
|
476
476
|
ancestors.reverse_each do |ancestor|
|
477
477
|
if ancestor <= Command
|
@@ -557,7 +557,7 @@ module Ronin
|
|
557
557
|
# @api semipublic
|
558
558
|
#
|
559
559
|
def self.each_argument(&block)
|
560
|
-
return enum_for(
|
560
|
+
return enum_for(__method__) unless block
|
561
561
|
|
562
562
|
ancestors.reverse_each do |ancestor|
|
563
563
|
if ancestor <= Command
|
@@ -121,12 +121,9 @@ module Ronin
|
|
121
121
|
return
|
122
122
|
end
|
123
123
|
|
124
|
-
if
|
125
|
-
|
126
|
-
elsif
|
127
|
-
set_repository
|
128
|
-
elsif delete?
|
129
|
-
delete_repository
|
124
|
+
if add? then add_repository
|
125
|
+
elsif set? then set_repository
|
126
|
+
elsif remove? then remove_repository
|
130
127
|
else
|
131
128
|
Ronin::Database.repositories.each do |name,uri|
|
132
129
|
print_hash uri, :title => name
|
@@ -174,7 +171,7 @@ module Ronin
|
|
174
171
|
def set_repository
|
175
172
|
unless Ronin::Database.repository?(@set)
|
176
173
|
print_error "Unknown Database repository #{@set}"
|
177
|
-
|
174
|
+
exit -1
|
178
175
|
end
|
179
176
|
|
180
177
|
Ronin::Database.save do
|
@@ -190,7 +187,7 @@ module Ronin
|
|
190
187
|
def remove_repository
|
191
188
|
unless Ronin::Database.repository?(@remove)
|
192
189
|
print_error "Unknown Database repository #{@remove}"
|
193
|
-
|
190
|
+
exit -1
|
194
191
|
end
|
195
192
|
|
196
193
|
Ronin::Database.save do
|
@@ -0,0 +1,306 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2006-2012 Hal Brodigan (postmodern.mod3 at gmail.com)
|
3
|
+
#
|
4
|
+
# This file is part of Ronin.
|
5
|
+
#
|
6
|
+
# Ronin is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# Ronin is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with Ronin. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'ronin/ui/cli/command'
|
21
|
+
require 'ronin/fuzzing/repeater'
|
22
|
+
require 'ronin/fuzzing/fuzzer'
|
23
|
+
|
24
|
+
require 'shellwords'
|
25
|
+
require 'tempfile'
|
26
|
+
require 'socket'
|
27
|
+
|
28
|
+
module Ronin
|
29
|
+
module UI
|
30
|
+
module CLI
|
31
|
+
module Commands
|
32
|
+
#
|
33
|
+
# Performs basic fuzzing of files, commands or TCP/UDP services.
|
34
|
+
#
|
35
|
+
# ## Usage
|
36
|
+
#
|
37
|
+
# ronin fuzzer [options]
|
38
|
+
#
|
39
|
+
# ## Options
|
40
|
+
#
|
41
|
+
# -v, --[no-]verbose Enable verbose output.
|
42
|
+
# -q, --[no-]quiet Disable verbose output.
|
43
|
+
# --[no-]silent Silence all output.
|
44
|
+
# --[no-]color Enables color output.
|
45
|
+
# Default: true
|
46
|
+
# -r [[PATTERN|/REGEXP/]:[METHOD|STRING*N[-M]]],
|
47
|
+
# --rule Fuzzing rules.
|
48
|
+
# -i, --input [FILE] Input file to fuzz.
|
49
|
+
# -o, --output [FILE] Output file path.
|
50
|
+
# -c [PROGRAM [OPTIONS|#string#|#path#] ...],
|
51
|
+
# --command Template command to run.
|
52
|
+
# -t, --tcp [HOST:PORT] TCP service to fuzz.
|
53
|
+
# -u, --udp [HOST:PORT] UDP service to fuzz.
|
54
|
+
#
|
55
|
+
# ## Examples
|
56
|
+
#
|
57
|
+
# ronin fuzzer -i request.txt -r unix_path:bad_strings -o bad.txt
|
58
|
+
#
|
59
|
+
# @since 1.5.0
|
60
|
+
#
|
61
|
+
class Fuzzer < Command
|
62
|
+
|
63
|
+
summary 'Performs basic fuzzing of files'
|
64
|
+
|
65
|
+
option :input, :type => String,
|
66
|
+
:flag => '-i',
|
67
|
+
:usage => 'FILE',
|
68
|
+
:description => 'Input file to fuzz'
|
69
|
+
|
70
|
+
option :rules, :type => Hash[String => String],
|
71
|
+
:flag => '-r',
|
72
|
+
:usage => '[PATTERN|/REGEXP/|STRING]:[METHOD|STRING*N[-M]]',
|
73
|
+
:description => 'Fuzzing rules'
|
74
|
+
|
75
|
+
option :output, :type => String,
|
76
|
+
:flag => '-o',
|
77
|
+
:usgae => 'PATH',
|
78
|
+
:description => 'Output file path'
|
79
|
+
|
80
|
+
option :command, :type => String,
|
81
|
+
:flag => '-c',
|
82
|
+
:usage => 'PROGRAM [OPTIONS|#string#|#path#] ...',
|
83
|
+
:description => 'Template command to run'
|
84
|
+
|
85
|
+
option :tcp, :type => String,
|
86
|
+
:flag => '-t',
|
87
|
+
:usage => 'HOST:PORT',
|
88
|
+
:description => 'TCP service to fuzz'
|
89
|
+
|
90
|
+
option :udp, :type => String,
|
91
|
+
:flag => '-u',
|
92
|
+
:usage => 'HOST:PORT',
|
93
|
+
:description => 'UDP service to fuzz'
|
94
|
+
|
95
|
+
examples [
|
96
|
+
"ronin fuzzer -i request.txt -o bad.txt -r unix_path:bad_strings"
|
97
|
+
]
|
98
|
+
|
99
|
+
#
|
100
|
+
# Sets up the fuzz command.
|
101
|
+
#
|
102
|
+
def setup
|
103
|
+
super
|
104
|
+
|
105
|
+
unless rules?
|
106
|
+
print_error "Must specify at least one fuzzing rule"
|
107
|
+
exit -1
|
108
|
+
end
|
109
|
+
|
110
|
+
@rules = Hash[@rules.map { |pattern,substitution|
|
111
|
+
[parse_pattern(pattern), parse_substitution(substitution)]
|
112
|
+
}]
|
113
|
+
|
114
|
+
if output?
|
115
|
+
@file_ext = File.extname(@output)
|
116
|
+
@file_name = @file.chomp(@file_ext)
|
117
|
+
elsif command?
|
118
|
+
@command = shellwords(@command)
|
119
|
+
elsif (tcp? || udp?)
|
120
|
+
@socket_class = if tcp? then TCPSocket
|
121
|
+
elsif udp? then UDPSocket
|
122
|
+
end
|
123
|
+
|
124
|
+
@host, @port = (@tcp || @udp).split(':',2)
|
125
|
+
@port = @port.to_i
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def execute
|
130
|
+
data = if input? then File.read(@input)
|
131
|
+
else $stdin.read
|
132
|
+
end
|
133
|
+
|
134
|
+
method = if output? then method(:fuzz_file)
|
135
|
+
elsif command? then method(:fuzz_command)
|
136
|
+
elsif (tcp? || udp?) then method(:fuzz_network)
|
137
|
+
else method(:print_fuzz)
|
138
|
+
end
|
139
|
+
|
140
|
+
fuzzer = Fuzzing::Fuzzer.new(@rules)
|
141
|
+
fuzzer.each(data).each_with_index do |string,index|
|
142
|
+
index = index + 1
|
143
|
+
|
144
|
+
method.call(string,index)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
protected
|
149
|
+
|
150
|
+
include Shellwords
|
151
|
+
|
152
|
+
#
|
153
|
+
# Writes the fuzzed string to a file.
|
154
|
+
#
|
155
|
+
# @param [String] string
|
156
|
+
# The fuzzed string.
|
157
|
+
#
|
158
|
+
# @param [Integer] index
|
159
|
+
# The iteration number.
|
160
|
+
#
|
161
|
+
def fuzz_file(string,index)
|
162
|
+
path = "#{@file_name}-#{index}#{@file_ext}"
|
163
|
+
|
164
|
+
print_info "Creating file ##{index}: #{path} ..."
|
165
|
+
|
166
|
+
File.open(path,'wb') do |file|
|
167
|
+
file.write string
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
#
|
172
|
+
# Runs the fuzzed string in a command.
|
173
|
+
#
|
174
|
+
# @param [String] string
|
175
|
+
# The fuzzed string.
|
176
|
+
#
|
177
|
+
# @param [Integer] index
|
178
|
+
# The iteration number.
|
179
|
+
#
|
180
|
+
def fuzz_command(string,index)
|
181
|
+
Tempfile.open("ronin-fuzzer-#{index}") do |tempfile|
|
182
|
+
tempfile.write(string)
|
183
|
+
tempfile.flush
|
184
|
+
|
185
|
+
arguments = @command.map do |argument|
|
186
|
+
if argument.include?('#path#')
|
187
|
+
argument.sub('#path#',tempfile.path)
|
188
|
+
elsif argument.include?('#string#')
|
189
|
+
argument.sub('#string#',string)
|
190
|
+
else
|
191
|
+
argument
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
print_info "Running command #{index}: #{arguments.join(' ')} ..."
|
196
|
+
|
197
|
+
# run the command as it's own process
|
198
|
+
unless system(*arguments)
|
199
|
+
status = $?
|
200
|
+
|
201
|
+
if status.coredump?
|
202
|
+
# jack pot!
|
203
|
+
print_error "Process ##{status.pid} coredumped!"
|
204
|
+
else
|
205
|
+
# process errored out
|
206
|
+
print_warning "Process ##{status.pid} exited with status #{status.exitstatus}"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
#
|
213
|
+
# Sends the fuzzed string to a TCP/UDP Service.
|
214
|
+
#
|
215
|
+
# @param [String] string
|
216
|
+
# The fuzzed string.
|
217
|
+
#
|
218
|
+
# @param [Integer] index
|
219
|
+
# The iteration number.
|
220
|
+
#
|
221
|
+
def fuzz_network(string,index)
|
222
|
+
print_debug "Connecting to #{@host}:#{@port} ..."
|
223
|
+
socket = @socket_class.new(@host,@port)
|
224
|
+
|
225
|
+
print_info "Sending message ##{index}: #{string.inspect} ..."
|
226
|
+
socket.write(string)
|
227
|
+
socket.flush
|
228
|
+
|
229
|
+
print_debug "Disconnecting from #{@host}:#{@port} ..."
|
230
|
+
socket.close
|
231
|
+
end
|
232
|
+
|
233
|
+
#
|
234
|
+
# Prints the fuzzed string to STDOUT.
|
235
|
+
#
|
236
|
+
# @param [String] string
|
237
|
+
# The fuzzed string.
|
238
|
+
#
|
239
|
+
# @param [Integer] index
|
240
|
+
# The iteration number.
|
241
|
+
#
|
242
|
+
def print_fuzz(string,index)
|
243
|
+
print_debug "String ##{index} ..."
|
244
|
+
|
245
|
+
puts string
|
246
|
+
end
|
247
|
+
|
248
|
+
#
|
249
|
+
# Parses a fuzz pattern.
|
250
|
+
#
|
251
|
+
# @param [String] string
|
252
|
+
# The string to parse.
|
253
|
+
#
|
254
|
+
# @return [Regexp, String]
|
255
|
+
# The parsed pattern.
|
256
|
+
#
|
257
|
+
def parse_pattern(string)
|
258
|
+
case string
|
259
|
+
when /^\/.+\/$/
|
260
|
+
Regexp.new(string[1..-2])
|
261
|
+
when /^[a-z][a-z_]+$/
|
262
|
+
const = string.upcase
|
263
|
+
|
264
|
+
if (Regexp.const_defined?(const) &&
|
265
|
+
Regexp.const_get(const).kind_of?(Regexp))
|
266
|
+
Regexp.const_get(const)
|
267
|
+
else
|
268
|
+
string
|
269
|
+
end
|
270
|
+
else
|
271
|
+
string
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
#
|
276
|
+
# Parses a fuzz substitution Enumerator.
|
277
|
+
#
|
278
|
+
# @param [String] string
|
279
|
+
# The string to parse.
|
280
|
+
#
|
281
|
+
# @return [Enumerator]
|
282
|
+
# The parsed substitution Enumerator.
|
283
|
+
#
|
284
|
+
def parse_substitution(string)
|
285
|
+
if string.include?('*')
|
286
|
+
string, lengths = string.split('*',2)
|
287
|
+
|
288
|
+
lengths = if lengths.include?('-')
|
289
|
+
min, max = lengths.split('-',2)
|
290
|
+
|
291
|
+
(min.to_i .. max.to_i)
|
292
|
+
else
|
293
|
+
lengths.to_i
|
294
|
+
end
|
295
|
+
|
296
|
+
Fuzzing::Repeater.new(lengths).each(string)
|
297
|
+
else
|
298
|
+
Fuzzing[string]
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
data/lib/ronin/url.rb
CHANGED
@@ -43,8 +43,8 @@ module Ronin
|
|
43
43
|
# Mapping of URL Schemes and URI classes
|
44
44
|
SCHEMES = {
|
45
45
|
'https' => ::URI::HTTPS,
|
46
|
-
'http'
|
47
|
-
'ftp'
|
46
|
+
'http' => ::URI::HTTP,
|
47
|
+
'ftp' => ::URI::FTP
|
48
48
|
}
|
49
49
|
|
50
50
|
# Primary key of the URL
|
@@ -100,7 +100,7 @@ module Ronin
|
|
100
100
|
# @api public
|
101
101
|
#
|
102
102
|
def self.extract(text)
|
103
|
-
return enum_for(
|
103
|
+
return enum_for(__method__,text).to_a unless block_given?
|
104
104
|
|
105
105
|
::URI.extract(text) do |uri|
|
106
106
|
uri = begin
|
@@ -287,10 +287,10 @@ module Ronin
|
|
287
287
|
|
288
288
|
# create the initial query
|
289
289
|
query = all(
|
290
|
-
'scheme.name'
|
290
|
+
'scheme.name' => url.scheme,
|
291
291
|
'host_name.address' => url.host,
|
292
|
-
:path
|
293
|
-
:fragment
|
292
|
+
:path => normalized_path(url),
|
293
|
+
:fragment => url.fragment
|
294
294
|
)
|
295
295
|
|
296
296
|
if url.port
|
@@ -300,10 +300,10 @@ module Ronin
|
|
300
300
|
|
301
301
|
if url.query
|
302
302
|
# add the query params to the query
|
303
|
-
URI::QueryParams.parse(url.query).each do |name,value|
|
303
|
+
::URI::QueryParams.parse(url.query).each do |name,value|
|
304
304
|
query = query.all(
|
305
305
|
'query_params.name.name' => name,
|
306
|
-
'query_params.value'
|
306
|
+
'query_params.value' => value
|
307
307
|
)
|
308
308
|
end
|
309
309
|
end
|
@@ -326,13 +326,13 @@ module Ronin
|
|
326
326
|
#
|
327
327
|
def self.from(uri)
|
328
328
|
# find or create the URL scheme, host_name and port
|
329
|
-
scheme
|
329
|
+
scheme = URLScheme.first_or_new(:name => uri.scheme)
|
330
330
|
host_name = HostName.first_or_new(:address => uri.host)
|
331
|
-
port
|
332
|
-
|
333
|
-
|
331
|
+
port = if uri.port
|
332
|
+
TCPPort.first_or_new(:number => uri.port)
|
333
|
+
end
|
334
334
|
|
335
|
-
path
|
335
|
+
path = normalized_path(uri)
|
336
336
|
fragment = uri.fragment
|
337
337
|
|
338
338
|
query_params = []
|
@@ -341,7 +341,7 @@ module Ronin
|
|
341
341
|
# find or create the URL query params
|
342
342
|
uri.query_params.each do |name,value|
|
343
343
|
query_params << {
|
344
|
-
:name
|
344
|
+
:name => URLQueryParamName.first_or_new(:name => name),
|
345
345
|
:value => value
|
346
346
|
}
|
347
347
|
end
|
@@ -349,11 +349,11 @@ module Ronin
|
|
349
349
|
|
350
350
|
# find or create the URL
|
351
351
|
return first_or_new(
|
352
|
-
:scheme
|
353
|
-
:host_name
|
354
|
-
:port
|
355
|
-
:path
|
356
|
-
:fragment
|
352
|
+
:scheme => scheme,
|
353
|
+
:host_name => host_name,
|
354
|
+
:port => port,
|
355
|
+
:path => path,
|
356
|
+
:fragment => fragment,
|
357
357
|
:query_params => query_params
|
358
358
|
)
|
359
359
|
end
|
@@ -422,7 +422,7 @@ module Ronin
|
|
422
422
|
params[param.name] = param.value
|
423
423
|
end
|
424
424
|
|
425
|
-
return URI::QueryParams.dump(params)
|
425
|
+
return ::URI::QueryParams.dump(params)
|
426
426
|
end
|
427
427
|
|
428
428
|
#
|
@@ -441,9 +441,9 @@ module Ronin
|
|
441
441
|
def query_string=(query)
|
442
442
|
self.query_params.clear
|
443
443
|
|
444
|
-
URI::QueryParams.parse(query).each do |name,value|
|
444
|
+
::URI::QueryParams.parse(query).each do |name,value|
|
445
445
|
self.query_params.new(
|
446
|
-
:name
|
446
|
+
:name => URLQueryParamName.first_or_new(:name => name),
|
447
447
|
:value => value
|
448
448
|
)
|
449
449
|
end
|
@@ -478,11 +478,11 @@ module Ronin
|
|
478
478
|
|
479
479
|
# build the URI
|
480
480
|
return url_class.build(
|
481
|
-
:scheme
|
482
|
-
:host
|
483
|
-
:port
|
484
|
-
:path
|
485
|
-
:query
|
481
|
+
:scheme => self.scheme.name,
|
482
|
+
:host => host,
|
483
|
+
:port => port,
|
484
|
+
:path => self.path,
|
485
|
+
:query => query,
|
486
486
|
:fragment => self.fragment
|
487
487
|
)
|
488
488
|
end
|
@@ -532,7 +532,7 @@ module Ronin
|
|
532
532
|
#
|
533
533
|
def self.normalized_path(uri)
|
534
534
|
case uri
|
535
|
-
when URI::HTTP
|
535
|
+
when ::URI::HTTP
|
536
536
|
# map empty HTTP paths to '/'
|
537
537
|
unless uri.path.empty?
|
538
538
|
uri.path
|
data/lib/ronin/version.rb
CHANGED
@@ -0,0 +1,73 @@
|
|
1
|
+
# ronin-fuzzer 1 "April 2012" Ronin "User Manuals"
|
2
|
+
|
3
|
+
## SYNOPSIS
|
4
|
+
|
5
|
+
`ronin fuzzer` [*options*] [*TEMPLATE*]
|
6
|
+
|
7
|
+
## DESCRIPTION
|
8
|
+
|
9
|
+
Fuzzes data read from a *FILE* or from `STDIN`. The fuzzed data can be written
|
10
|
+
to output files, run in commands or sent to TCP/UDP services.
|
11
|
+
|
12
|
+
## OPTIONS
|
13
|
+
|
14
|
+
`-v`, `--[no-]verbose`
|
15
|
+
Enable verbose output.
|
16
|
+
|
17
|
+
`-q`, `--[no-]quiet`
|
18
|
+
Disable verbose output.
|
19
|
+
|
20
|
+
`--[no-]silent`
|
21
|
+
Silence all output.
|
22
|
+
|
23
|
+
`--[no-]color`
|
24
|
+
Enables color output.
|
25
|
+
|
26
|
+
`-i`, `--input` *FILE*
|
27
|
+
The input text FILE to parse. Data will be read from `STDIN` by default.
|
28
|
+
|
29
|
+
`-r`, `--rule` [*PATTERN*|*/REGEXP/*|STRING]:[*METHOD*|*STRING***N*[-*M*]]
|
30
|
+
The rule to apply to the *INPUT*. Fuzzer rules consist of a pattern and
|
31
|
+
substitution. Patterns may be one of the following:
|
32
|
+
|
33
|
+
* A name of a Ronin Regular Expression (ex: `unix_path`)
|
34
|
+
* A custom Regular Expression (ex: `/\d+/`)
|
35
|
+
* A plain String (ex: `example.com`).
|
36
|
+
|
37
|
+
Substitutions may be one of the following:
|
38
|
+
|
39
|
+
* A method from `Ronin::Fuzzing` (ex: `bad_strings`)
|
40
|
+
* A *STRING*, repeated *N* or *M* times (ex: `A*100-200`).
|
41
|
+
|
42
|
+
`-o`, `--output` *PATH*
|
43
|
+
The output PATH to write the fuzzer to.
|
44
|
+
|
45
|
+
`-c`, `--command` *COMMAND*
|
46
|
+
The command to run with the fuzzed data. All ocurrences of `#string#` will be
|
47
|
+
replaced with the fuzzed data, and ocurrences of `#path#` will be replaced
|
48
|
+
with the path to the fuzzed data.
|
49
|
+
|
50
|
+
`-t`, `--tcp` *HOST*:*PORT*
|
51
|
+
The TCP service to send the fuzzed data to.
|
52
|
+
|
53
|
+
`-u`, `--udp` *HOST*:*PORT*
|
54
|
+
The UDP service to send the fuzzed data to.
|
55
|
+
|
56
|
+
## EXAMPLES
|
57
|
+
|
58
|
+
`ronin fuzzer -i http_request.txt -o bad.txt -r unix_path:bad_strings`
|
59
|
+
Fuzzes a HTTP request, replacing every occurrence of a UNIX path, with
|
60
|
+
strings from the `bad_strings` method.
|
61
|
+
|
62
|
+
## LINKS
|
63
|
+
|
64
|
+
Ronin Regular Expressions
|
65
|
+
http://ronin-ruby.github.com/docs/ronin-support/Regexp.html
|
66
|
+
|
67
|
+
`Ronin::Fuzzing`
|
68
|
+
http://ronin-ruby.github.com/docs/ronin-support/Ronin/Fuzzing.html
|
69
|
+
|
70
|
+
## AUTHOR
|
71
|
+
|
72
|
+
Postmodern <postmodern.mod3@gmail.com>
|
73
|
+
|
data/spec/installation_spec.rb
CHANGED
@@ -10,40 +10,18 @@ describe Installation do
|
|
10
10
|
subject.libraries.should include('ronin')
|
11
11
|
end
|
12
12
|
|
13
|
-
let(:directory) { 'lib/ronin/ui/cli/commands'
|
14
|
-
let(:
|
15
|
-
|
16
|
-
|
17
|
-
console.rb
|
18
|
-
creds.rb
|
19
|
-
database.rb
|
20
|
-
emails.rb
|
21
|
-
exec.rb
|
22
|
-
help.rb
|
23
|
-
hosts.rb
|
24
|
-
install.rb
|
25
|
-
ips.rb
|
26
|
-
net/proxy.rb
|
27
|
-
repos.rb
|
28
|
-
update.rb
|
29
|
-
urls.rb
|
30
|
-
uninstall.rb
|
31
|
-
wordlist.rb
|
32
|
-
]
|
33
|
-
}
|
13
|
+
let(:directory) { 'lib/ronin/ui/cli/commands/' }
|
14
|
+
let(:pattern) { File.join(directory,'**','*.rb') }
|
15
|
+
let(:paths) { Dir[pattern] }
|
16
|
+
let(:files) { paths.map { |path| path.sub(directory,'') } }
|
34
17
|
|
35
18
|
describe "each_file" do
|
36
|
-
let(:pattern) { File.join(directory,'**','*.rb') }
|
37
|
-
let(:expected) { files.map { |name| File.join(directory,name) } }
|
38
|
-
|
39
19
|
it "should enumerate over the files which match a glob pattern" do
|
40
|
-
subject.each_file(pattern).to_a.should =~
|
20
|
+
subject.each_file(pattern).to_a.should =~ paths
|
41
21
|
end
|
42
22
|
|
43
23
|
it "should return an Enumerator when no block is given" do
|
44
|
-
subject.each_file(pattern).
|
45
|
-
expected.include?(file)
|
46
|
-
}.should == true
|
24
|
+
subject.each_file(pattern).should respond_to(:each)
|
47
25
|
end
|
48
26
|
end
|
49
27
|
|
@@ -56,9 +34,7 @@ describe Installation do
|
|
56
34
|
end
|
57
35
|
|
58
36
|
it "should return an Enumerator when no block is given" do
|
59
|
-
subject.each_file_in(directory,ext).
|
60
|
-
expected.include?(file)
|
61
|
-
}.should == true
|
37
|
+
subject.each_file_in(directory,ext).should respond_to(:each)
|
62
38
|
end
|
63
39
|
end
|
64
40
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ronin/ui/cli/cli'
|
3
|
+
|
4
|
+
describe UI::CLI do
|
5
|
+
describe "commands" do
|
6
|
+
subject { described_class.commands }
|
7
|
+
|
8
|
+
it { should_not be_empty }
|
9
|
+
|
10
|
+
it "should replace '/' characters with a ':'" do
|
11
|
+
subject.all? { |command| command.include?('/') }.should be_false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "command" do
|
16
|
+
it "should load classes from 'ronin/ui/cli/commands/'" do
|
17
|
+
command = subject.command('help')
|
18
|
+
|
19
|
+
command.name.should == 'Ronin::UI::CLI::Commands::Help'
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should load classes from namespaces within 'ronin/ui/cli/commands/'" do
|
23
|
+
command = subject.command('net:proxy')
|
24
|
+
|
25
|
+
command.name.should == 'Ronin::UI::CLI::Commands::Net::Proxy'
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should raise UnknownCommand for unknown commands" do
|
29
|
+
lambda {
|
30
|
+
subject.command('foo')
|
31
|
+
}.should raise_error(described_class::UnknownCommand)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ronin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.0
|
5
|
-
prerelease:
|
4
|
+
version: 1.5.0
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Postmodern
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-06-
|
12
|
+
date: 2012-06-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: dm-sqlite-adapter
|
@@ -344,7 +344,7 @@ dependencies:
|
|
344
344
|
requirements:
|
345
345
|
- - ~>
|
346
346
|
- !ruby/object:Gem::Version
|
347
|
-
version: 0.5
|
347
|
+
version: '0.5'
|
348
348
|
type: :runtime
|
349
349
|
prerelease: false
|
350
350
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -352,7 +352,7 @@ dependencies:
|
|
352
352
|
requirements:
|
353
353
|
- - ~>
|
354
354
|
- !ruby/object:Gem::Version
|
355
|
-
version: 0.5
|
355
|
+
version: '0.5'
|
356
356
|
- !ruby/object:Gem::Dependency
|
357
357
|
name: bundler
|
358
358
|
requirement: !ruby/object:Gem::Requirement
|
@@ -429,6 +429,7 @@ executables:
|
|
429
429
|
- ronin-database
|
430
430
|
- ronin-emails
|
431
431
|
- ronin-exec
|
432
|
+
- ronin-fuzzer
|
432
433
|
- ronin-help
|
433
434
|
- ronin-hosts
|
434
435
|
- ronin-install
|
@@ -462,6 +463,7 @@ files:
|
|
462
463
|
- bin/ronin-database
|
463
464
|
- bin/ronin-emails
|
464
465
|
- bin/ronin-exec
|
466
|
+
- bin/ronin-fuzzer
|
465
467
|
- bin/ronin-help
|
466
468
|
- bin/ronin-hosts
|
467
469
|
- bin/ronin-install
|
@@ -561,6 +563,7 @@ files:
|
|
561
563
|
- lib/ronin/ui/cli/commands/database.rb
|
562
564
|
- lib/ronin/ui/cli/commands/emails.rb
|
563
565
|
- lib/ronin/ui/cli/commands/exec.rb
|
566
|
+
- lib/ronin/ui/cli/commands/fuzzer.rb
|
564
567
|
- lib/ronin/ui/cli/commands/help.rb
|
565
568
|
- lib/ronin/ui/cli/commands/hosts.rb
|
566
569
|
- lib/ronin/ui/cli/commands/install.rb
|
@@ -596,6 +599,7 @@ files:
|
|
596
599
|
- man/ronin-database.1.md
|
597
600
|
- man/ronin-emails.1.md
|
598
601
|
- man/ronin-exec.1.md
|
602
|
+
- man/ronin-fuzzer.1.md
|
599
603
|
- man/ronin-help.1.md
|
600
604
|
- man/ronin-hosts.1.md
|
601
605
|
- man/ronin-install.1.md
|
@@ -675,6 +679,7 @@ files:
|
|
675
679
|
- spec/software_spec.rb
|
676
680
|
- spec/spec_helper.rb
|
677
681
|
- spec/ui/cli/classes/test_command.rb
|
682
|
+
- spec/ui/cli/cli_spec.rb
|
678
683
|
- spec/ui/cli/command_spec.rb
|
679
684
|
- spec/url_query_param_spec.rb
|
680
685
|
- spec/url_scheme_spec.rb
|
@@ -687,6 +692,7 @@ files:
|
|
687
692
|
- man/ronin-database.1
|
688
693
|
- man/ronin-emails.1
|
689
694
|
- man/ronin-exec.1
|
695
|
+
- man/ronin-fuzzer.1
|
690
696
|
- man/ronin-help.1
|
691
697
|
- man/ronin-hosts.1
|
692
698
|
- man/ronin-install.1
|
@@ -697,7 +703,7 @@ files:
|
|
697
703
|
- man/ronin-update.1
|
698
704
|
- man/ronin-urls.1
|
699
705
|
- man/ronin-wordlist.1
|
700
|
-
homepage: http://github.com/
|
706
|
+
homepage: http://ronin-ruby.github.com/
|
701
707
|
licenses:
|
702
708
|
- GPL-3
|
703
709
|
post_install_message: ! "*************************************************************************\n\n
|