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.
@@ -1,4 +1,4 @@
1
- ### 1.5.0 / 2012-05-28
1
+ ### 1.5.0 / 2012-06-16
2
2
 
3
3
  * Require ronin-support ~> 0.5.
4
4
  * Added {Ronin::UI::CLI::Command#setup}.
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.0.rc1', :git => "#{RONIN_URI}/ronin-support.git",
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
@@ -109,6 +109,10 @@ View available commands:
109
109
 
110
110
  $ ronin help
111
111
 
112
+ View a man-page for a command:
113
+
114
+ $ ronin help wordlist
115
+
112
116
  Install a Repository:
113
117
 
114
118
  $ ronin install svn://example.com/path/to/repo
@@ -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
@@ -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/ronin-ruby/ronin
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.0.rc2
84
+ ronin-support: ~> 0.5
84
85
 
85
86
  development_dependencies:
86
87
  bundler: ~> 1.0
@@ -25,6 +25,8 @@ module Ronin
25
25
  # When included into other namespaces, it allows for auto-loading Classes
26
26
  # or Modules via {ClassMethods#const_missing}.
27
27
  #
28
+ # @api semipublic
29
+ #
28
30
  # @since 1.1.0
29
31
  #
30
32
  module AutoLoad
@@ -212,7 +212,7 @@ module Ronin
212
212
  # @api semipublic
213
213
  #
214
214
  def upto(position_or_name=nil)
215
- return enum_for(:upto,position_or_name) unless block_given?
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(:downto,position_or_name) unless block_given?
253
+ return enum_for(__method__,position_or_name) unless block_given?
254
254
 
255
255
  name = name_of(position_or_name)
256
256
 
@@ -76,7 +76,7 @@ module Ronin
76
76
  # @api public
77
77
  #
78
78
  def self.extract(text)
79
- return enum_for(:extract,text).to_a unless block_given?
79
+ return enum_for(__method__,text).to_a unless block_given?
80
80
 
81
81
  scanner = StringScanner.new(text)
82
82
 
@@ -83,7 +83,7 @@ module Ronin
83
83
  # @api public
84
84
  #
85
85
  def self.extract(text)
86
- return enum_for(:extract,text).to_a unless block_given?
86
+ return enum_for(__method__,text).to_a unless block_given?
87
87
 
88
88
  scanner = StringScanner.new(text)
89
89
 
@@ -39,7 +39,7 @@ module Ronin
39
39
  #
40
40
  # @api semipublic
41
41
  #
42
- def Installation.gems
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 Installation.paths
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 Installation.libraries
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 Installation.each_file(pattern)
97
- return enum_for(:each_file,pattern) unless block_given?
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 Installation.each_file_in(directory,ext=nil)
134
- return enum_for(:each_file_in,directory,ext) unless block_given?
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[slice_index..-1]
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 Installation.load_gems!
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 Installation.load_gemspecs!
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 Installation.load!
219
+ def self.load!
220
220
  if Gem.loaded_specs.has_key?('ronin')
221
221
  load_gems!
222
222
  else
@@ -98,7 +98,7 @@ module Ronin
98
98
  # @api public
99
99
  #
100
100
  def self.extract(text,version=nil)
101
- return enum_for(:extract,text,version).to_a unless block_given?
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)
@@ -64,7 +64,7 @@ module Ronin
64
64
  # @api public
65
65
  #
66
66
  def self.extract(text)
67
- return enum_for(:extract,text).to_a unless block_given?
67
+ return enum_for(__method__,text).to_a unless block_given?
68
68
 
69
69
  scanner = StringScanner.new(text)
70
70
 
@@ -49,7 +49,7 @@ module Ronin
49
49
  # @api public
50
50
  #
51
51
  def import(path)
52
- return enum_for(:import,path).to_a unless block_given?
52
+ return enum_for(__method__,path).to_a unless block_given?
53
53
 
54
54
  File.open(path) do |file|
55
55
  file.each_line do |line|
@@ -475,7 +475,7 @@ module Ronin
475
475
  # @api private
476
476
  #
477
477
  def each_script(&block)
478
- return enum_for(:each_script) unless block
478
+ return enum_for(__method__) unless block
479
479
 
480
480
  @script_dirs.each do |dir|
481
481
  Pathname.glob(dir.join('**','*.rb'),&block)
@@ -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(name))
99
+ unless (command = Commands.require_const(path))
99
100
  raise(UnknownCommand,"unable to load the command #{name.dump}",caller)
100
101
  end
101
102
 
@@ -471,7 +471,7 @@ module Ronin
471
471
  # @api private
472
472
  #
473
473
  def self.each_option(&block)
474
- return enum_for(:each_option) unless block
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(:each_argument) unless block
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 add?
125
- add_repository
126
- elsif set?
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
- return
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
- return
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
@@ -313,6 +313,7 @@ module Ronin
313
313
  print_data data
314
314
  end
315
315
 
316
+ print_info "Listening on #{@host}:#{@port} ..."
316
317
  @proxy.start
317
318
  end
318
319
 
@@ -61,7 +61,7 @@ module Ronin
61
61
  # @since 1.1.0
62
62
  #
63
63
  def self.each_query_option(&block)
64
- return enum_for(:each_query_option) unless block
64
+ return enum_for(__method__) unless block
65
65
 
66
66
  self.class.ancestors.each do |ancestor|
67
67
  if ancestor < ModelCommand
@@ -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' => ::URI::HTTP,
47
- 'ftp' => ::URI::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(:extract,text).to_a unless block_given?
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' => url.scheme,
290
+ 'scheme.name' => url.scheme,
291
291
  'host_name.address' => url.host,
292
- :path => normalized_path(url),
293
- :fragment => url.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' => 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 = URLScheme.first_or_new(:name => uri.scheme)
329
+ scheme = URLScheme.first_or_new(:name => uri.scheme)
330
330
  host_name = HostName.first_or_new(:address => uri.host)
331
- port = if uri.port
332
- TCPPort.first_or_new(:number => uri.port)
333
- end
331
+ port = if uri.port
332
+ TCPPort.first_or_new(:number => uri.port)
333
+ end
334
334
 
335
- path = normalized_path(uri)
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 => URLQueryParamName.first_or_new(:name => 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 => scheme,
353
- :host_name => host_name,
354
- :port => port,
355
- :path => path,
356
- :fragment => 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 => URLQueryParamName.first_or_new(:name => 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 => self.scheme.name,
482
- :host => host,
483
- :port => port,
484
- :path => self.path,
485
- :query => 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
@@ -19,5 +19,5 @@
19
19
 
20
20
  module Ronin
21
21
  # Ronin version
22
- VERSION = '1.5.0.rc2'
22
+ VERSION = '1.5.0'
23
23
  end
@@ -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
+
@@ -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(:files) {
15
- %w[
16
- campaigns.rb
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 =~ expected
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).all? { |file|
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).all? { |file|
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.rc2
5
- prerelease: 6
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-10 00:00:00.000000000 Z
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.0.rc2
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.0.rc2
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/ronin-ruby/ronin
706
+ homepage: http://ronin-ruby.github.com/
701
707
  licenses:
702
708
  - GPL-3
703
709
  post_install_message: ! "*************************************************************************\n\n