ronin 1.5.0.rc2 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|