ronin-fuzzer 0.1.0.beta1 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9564e6b05be69b5d8ca409a2a8c95f831727c3319f71303c477b2f60080b4592
4
- data.tar.gz: de9f24233b6435549ea06c5ec7db4211c432fe77313af905482edd444ce09764
3
+ metadata.gz: b75ddebfc52f82912471833f168b9e8813af985b9443cb1c6b88a27b1c730a3b
4
+ data.tar.gz: 7a0454d2ece994db0151eb7ed1df4ce0edf6ab2e05d48d12f13621930d66cd8d
5
5
  SHA512:
6
- metadata.gz: 7350b4af7a680571e4dd1674cdd7e064248a6028e3aac0836077cc8730ceb52feb7f065d39c2b0654dcf951b5773a8f237823ec7a94fe58c36ef3707ea4369d3
7
- data.tar.gz: 23488e361a02a84dd0bcb332289cbf7b0c94949b6dfa6698a23771bb507c361c790e5f6c0aa079291c74b7ecb91eb738c5f4077cd12f4359f46923117c6c02e9
6
+ metadata.gz: 508b1ede3b5ec7e9be7d1a9bccfab1add955ce60f028559d444613f6e485195ef52f95f293acab505a9493222b2ba31337901df3038a8bd2fee0a3b8668c8a43
7
+ data.tar.gz: 65fdbda74f4b756e3378e1fbdc5ac533612a6aad873eff7b8b17bc0a0f1a94726bdb15525668f974f18b2a5d50feb2853077d8a8ba00040c64ed88b5a3352a3f
@@ -21,6 +21,7 @@ jobs:
21
21
  uses: ruby/setup-ruby@v1
22
22
  with:
23
23
  ruby-version: ${{ matrix.ruby }}
24
+ bundler-cache: true
24
25
  - name: Install libsqlite3
25
26
  run: |
26
27
  sudo apt update -y && \
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![CI](https://github.com/ronin-rb/ronin-fuzzer/actions/workflows/ruby.yml/badge.svg)](https://github.com/ronin-rb/ronin-fuzzer/actions/workflows/ruby.yml)
4
4
  [![Code Climate](https://codeclimate.com/github/ronin-rb/ronin-fuzzer.svg)](https://codeclimate.com/github/ronin-rb/ronin-fuzzer)
5
+ [![Gem Version](https://badge.fury.io/rb/ronin-fuzzer.svg)](https://badge.fury.io/rb/ronin-fuzzer)
5
6
 
6
7
  * [Website](https://ronin-rb.dev/)
7
8
  * [Source](https://github.com/ronin-rb/ronin-fuzzer)
@@ -13,7 +14,9 @@
13
14
 
14
15
  ## Description
15
16
 
16
- ronin-fuzzer is a Ruby library for generating, mutating, and fuzzing data.
17
+ ronin-fuzzer is a Ruby library and CLI for generating, mutating, and fuzzing
18
+ data. The goal of ronin-fuzzer is to be both easy to use and highly
19
+ customizable.
17
20
 
18
21
  ## Features
19
22
 
@@ -68,7 +71,7 @@ gem.add_dependency 'ronin-fuzzer', '~> 0.1'
68
71
 
69
72
  ## License
70
73
 
71
- Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3@gmail.com)
74
+ Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3@gmail.com)
72
75
 
73
76
  This file is part of ronin-fuzzer.
74
77
 
data/bin/ronin-fuzzer CHANGED
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # ronin-fuzzer - A Ruby library for generating, mutating, and fuzzing data.
4
4
  #
5
- # Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
5
+ # Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
6
6
  #
7
7
  # This file is part of ronin-fuzzer.
8
8
  #
data/gemspec.yml CHANGED
@@ -1,7 +1,8 @@
1
1
  name: ronin-fuzzer
2
- summary: generate, mutate, and fuzz data
2
+ summary: A highly configurable fuzzing library and CLI for Ruby.
3
3
  description: |
4
- A Ruby library for generating, mutating, and fuzzing data.
4
+ A Ruby library and CLI for generating, mutating, and fuzzing data.
5
+ The goal of ronin-fuzzer is to be both easy to use and highly customizable.
5
6
 
6
7
  license: LGPL-3.0
7
8
  authors: Postmodern
@@ -10,10 +11,11 @@ homepage: https://ronin-rb.dev/
10
11
  has_yard: true
11
12
 
12
13
  metadata:
13
- documentation_uri: https://rubydoc.info/gems/ronin-fuzzer
14
+ documentation_uri: https://ronin-rb.dev/docs/ronin-fuzzer
14
15
  source_code_uri: https://github.com/ronin-rb/ronin-fuzzer
15
16
  bug_tracker_uri: https://github.com/ronin-rb/ronin-fuzzer/issues
16
- changelog_uri: https://github.com/ronin-rb/ronin-fuzzer/blob/master/ChangeLog.md
17
+ changelog_uri: https://github.com/ronin-rb/ronin-fuzzer/blob/main/ChangeLog.md
18
+ rubygems_mfa_required: 'true'
17
19
 
18
20
  generated_files:
19
21
  - man/ronin-fuzzer-fuzz.1
@@ -23,8 +25,8 @@ required_ruby_version: ">= 3.0.0"
23
25
  dependencies:
24
26
  combinatorics: ~> 0.4
25
27
  # Ronin dependencies:
26
- ronin-support: ~> 1.0.0.beta1
27
- ronin-core: ~> 0.1.0.beta1
28
+ ronin-support: ~> 1.0
29
+ ronin-core: ~> 0.1
28
30
 
29
31
  development_dependencies:
30
32
  bundler: ~> 2.0
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # ronin-fuzzer - A Ruby library for generating, mutating, and fuzzing data.
3
3
  #
4
- # Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ # Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
5
  #
6
6
  # This file is part of ronin-fuzzer.
7
7
  #
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # ronin-fuzzer - A Ruby library for generating, mutating, and fuzzing data.
3
3
  #
4
- # Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ # Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
5
  #
6
6
  # This file is part of ronin-fuzzer.
7
7
  #
@@ -20,8 +20,12 @@
20
20
  #
21
21
 
22
22
  require 'ronin/fuzzer/cli/command'
23
- require 'ronin/fuzzer/repeater'
24
- require 'ronin/fuzzer/fuzzer'
23
+ require 'ronin/core/cli/logging'
24
+
25
+ require 'ronin/support/text/patterns'
26
+ require 'ronin/fuzzing/repeater'
27
+ require 'ronin/fuzzing/fuzzer'
28
+ require 'ronin/fuzzing'
25
29
 
26
30
  require 'shellwords'
27
31
  require 'tempfile'
@@ -44,7 +48,7 @@ module Ronin
44
48
  # -q, --[no-]quiet Disable verbose output.
45
49
  # --[no-]silent Silence all output.
46
50
  # -r [[PATTERN|/REGEXP/]:[METHOD|STRING*N[-M]]],
47
- # --rule Fuzzing rules.
51
+ # --rule Adds a fuzzing rule.
48
52
  # -i, --input [FILE] Input file to fuzz.
49
53
  # -o, --output [FILE] Output file path.
50
54
  # -c [PROGRAM [OPTIONS|#string#|#path#] ...],
@@ -59,6 +63,8 @@ module Ronin
59
63
  #
60
64
  class Fuzz < Command
61
65
 
66
+ include Core::CLI::Logging
67
+
62
68
  option :input, short: '-i',
63
69
  value: {
64
70
  type: String,
@@ -68,45 +74,66 @@ module Ronin
68
74
 
69
75
  option :rules, short: '-r',
70
76
  value: {
71
- type: Hash[String => String],
77
+ type: String,
72
78
  usage: '[PATTERN|/REGEXP/|STRING]:[METHOD|STRING*N[-M]]'
73
79
  },
74
- desc: 'Fuzzing rules'
80
+ desc: 'Adds a fuzzing rule' do |value|
81
+ @rules << parse_rule(value)
82
+ end
75
83
 
76
84
  option :output, short: '-o',
77
85
  value: {
78
86
  type: String,
79
87
  usage: 'PATH'
80
88
  },
81
- desc: 'Output file path'
89
+ desc: 'Output file path' do |value|
90
+ @mode = :output
91
+
92
+ @output = value
93
+ @output_ext = File.extname(@output)
94
+ @output_name = @output.chomp(@output_ext)
95
+ end
82
96
 
83
97
  option :command, short: '-c',
84
98
  value: {
85
99
  type: String,
86
100
  usage: '"PROGRAM [OPTIONS|#string#|#path#] ..."'
87
101
  },
88
- desc: 'Template command to run'
102
+ desc: 'Template command to run' do |value|
103
+ @mode = :command
104
+ @command = Shellwords.shellescape(value)
105
+ end
89
106
 
90
107
  option :tcp, short: '-t',
91
108
  value: {
92
109
  type: String,
93
110
  usage: 'HOST:PORT'
94
111
  },
95
- desc: 'TCP service to fuzz'
112
+ desc: 'TCP service to fuzz' do |value|
113
+ @mode = :tcp
114
+
115
+ @host, @port = parse_host_port(value)
116
+ end
96
117
 
97
118
  option :udp, short: '-u',
98
119
  value: {
99
120
  type: String,
100
121
  usage: 'HOST:PORT'
101
122
  },
102
- desc: 'UDP service to fuzz'
123
+ desc: 'UDP service to fuzz' do |value|
124
+ @mode = :udp
125
+
126
+ @host, @port = parse_host_port(value)
127
+ end
103
128
 
104
129
  option :pause, short: '-p',
105
130
  value: {
106
131
  type: Float,
107
132
  usage: 'SECONDS'
108
133
  },
109
- desc: 'Pause in between mutations'
134
+ desc: 'Pause in between mutations' do |value|
135
+ @pause = value
136
+ end
110
137
 
111
138
  description 'Performs basic fuzzing of files'
112
139
 
@@ -116,58 +143,99 @@ module Ronin
116
143
 
117
144
  man_page 'ronin-fuzzer-fuzz.1'
118
145
 
146
+ # The execution mode to run the fuzzer in.
147
+ #
148
+ # @return [:output, :command, :tcp, :udp]
149
+ attr_reader :mode
150
+
151
+ # The output file template.
119
152
  #
120
- # Sets up the fuzz command.
153
+ # @return [String, nil]
154
+ attr_reader :output
155
+
156
+ # The output file extension.
157
+ #
158
+ # @return [String, nil]
159
+ attr_reader :output_ext
160
+
161
+ # The output file name.
162
+ #
163
+ # @return [String, nil]
164
+ attr_reader :output_name
165
+
166
+ # The command template to execute.
167
+ #
168
+ # @return [String, nil]
169
+ attr_reader :command
170
+
171
+ # The host name to send fuzzing data to.
172
+ #
173
+ # @return [String, nil]
174
+ attr_reader :host
175
+
176
+ # The port to send fuzzing data to.
177
+ #
178
+ # @return [Integer, nil]
179
+ attr_reader :port
180
+
181
+ # The fuzzing rules.
182
+ #
183
+ # @return [Array<(Regexp, Enumerator)>]
184
+ attr_reader :rules
185
+
186
+ #
187
+ # Initializes the `ronin-fuzzer fuzz` command.
188
+ #
189
+ # @param [Hash{Symbol => Object}] kwargs
190
+ # Additional keyword arguments.
191
+ #
192
+ def initialize(**kwargs)
193
+ super(**kwargs)
194
+
195
+ @rules = []
196
+ end
197
+
198
+ #
199
+ # Runs the `ronin-fuzzer fuzz` command.
121
200
  #
122
201
  def run
123
- unless options[:rules]
202
+ if @rules.empty?
124
203
  print_error "Must specify at least one fuzzing rule"
125
- exit -1
204
+ exit(-1)
126
205
  end
127
206
 
128
- rules = Hash[options[:rules].map { |pattern,substitution|
129
- [parse_pattern(pattern), parse_substitution(substitution)]
130
- }]
131
-
132
- if options[:output]
133
- @file_ext = File.extname(options[:output])
134
- @file_name = @output.chomp(@file_ext)
135
- elsif options[:command]
136
- @command = shellwords(options[:command])
137
- elsif (options[:tcp] || options[:udp])
138
- @socket_class = if options[:tcp] then TCPSocket
139
- elsif options[:udp] then UDPSocket
140
- end
141
-
142
- @host, @port = (options[:tcp] || options[:udp]).split(':',2)
143
- @port = @port.to_i
144
- end
207
+ data = if options[:input] then File.read(options[:input])
208
+ else $stdin.read
209
+ end
145
210
 
146
- data = if options[:input] then File.read(options[:input])
147
- else $stdin.read
211
+ method = case @mode
212
+ when :output then method(:fuzz_file)
213
+ when :command then method(:fuzz_command)
214
+ when :tcp, :udp then method(:fuzz_network)
215
+ else method(:print_fuzz)
148
216
  end
149
217
 
150
- method = if options[:output]
151
- method(:fuzz_file)
152
- elsif options[:command]
153
- method(:fuzz_command)
154
- elsif (options[:tcp] || options[:udp])
155
- method(:fuzz_network)
156
- else
157
- method(:print_fuzz)
158
- end
218
+ fuzzer = Fuzzing::Fuzzer.new(@rules)
159
219
 
160
- fuzzer = Fuzzer::Fuzzer.new(rules)
161
220
  fuzzer.each(data).each_with_index do |string,index|
162
221
  method.call(string,index + 1)
163
222
 
164
- sleep(pause) if pause?
223
+ sleep(@pause) if @pause
165
224
  end
166
225
  end
167
226
 
168
- private
169
-
170
- include Shellwords
227
+ #
228
+ # Creates a new output path for the given index.
229
+ #
230
+ # @param [Integer] index
231
+ # The index number of the fuzzing iteration.
232
+ #
233
+ # @return [String]
234
+ # The new output path.
235
+ #
236
+ def output_path(index)
237
+ "#{@output_name}-#{index}#{@output_ext}"
238
+ end
171
239
 
172
240
  #
173
241
  # Writes the fuzzed string to a file.
@@ -176,12 +244,12 @@ module Ronin
176
244
  # The fuzzed string.
177
245
  #
178
246
  # @param [Integer] index
179
- # The iteration number.
247
+ # The fuzzing iteration number.
180
248
  #
181
249
  def fuzz_file(string,index)
182
- path = "#{@file_name}-#{index}#{@file_ext}"
250
+ path = output_path(index)
183
251
 
184
- print_info "Creating file ##{index}: #{path} ..."
252
+ log_info "Creating file ##{index}: #{path} ..."
185
253
 
186
254
  File.open(path,'wb') do |file|
187
255
  file.write string
@@ -212,7 +280,7 @@ module Ronin
212
280
  end
213
281
  end
214
282
 
215
- print_info "Running command #{index}: #{arguments.join(' ')} ..."
283
+ log_info "Running command #{index}: #{arguments.join(' ')} ..."
216
284
 
217
285
  # run the command as it's own process
218
286
  unless system(*arguments)
@@ -220,10 +288,10 @@ module Ronin
220
288
 
221
289
  if status.coredump?
222
290
  # jack pot!
223
- print_error "Process ##{status.pid} coredumped!"
291
+ log_error "Process ##{status.pid} coredumped!"
224
292
  else
225
293
  # process errored out
226
- print_warning "Process ##{status.pid} exited with status #{status.exitstatus}"
294
+ log_warning "Process ##{status.pid} exited with status #{status.exitstatus}"
227
295
  end
228
296
  end
229
297
  end
@@ -239,14 +307,18 @@ module Ronin
239
307
  # The iteration number.
240
308
  #
241
309
  def fuzz_network(string,index)
242
- print_debug "Connecting to #{@host}:#{@port} ..."
243
- socket = @socket_class.new(@host,@port)
310
+ log_debug "Connecting to #{@host}:#{@port} ..."
244
311
 
245
- print_info "Sending message ##{index}: #{string.inspect} ..."
312
+ socket = case @mode
313
+ when :tcp then TCPSocket.new(@host,@port)
314
+ when :udp then UDPSocket.new(@host,@port)
315
+ end
316
+
317
+ log_info "Sending message ##{index}: #{string.inspect} ..."
246
318
  socket.write(string)
247
319
  socket.flush
248
320
 
249
- print_debug "Disconnecting from #{@host}:#{@port} ..."
321
+ log_debug "Disconnecting from #{@host}:#{@port} ..."
250
322
  socket.close
251
323
  end
252
324
 
@@ -260,11 +332,57 @@ module Ronin
260
332
  # The iteration number.
261
333
  #
262
334
  def print_fuzz(string,index)
263
- print_debug "String ##{index} ..."
335
+ log_debug "String ##{index} ..."
264
336
 
265
337
  puts string
266
338
  end
267
339
 
340
+ #
341
+ # Parses the host and port from the value.
342
+ #
343
+ # @param [String] value
344
+ # The value to parse.
345
+ #
346
+ # @return [(String, Integer)]
347
+ # The parsed host and port.
348
+ #
349
+ def parse_host_port(value)
350
+ host, port = value.split(':',2)
351
+
352
+ return host, port.to_i
353
+ end
354
+
355
+ #
356
+ # Parses a fuzzing rule.
357
+ #
358
+ # @param [String] value
359
+ # The fuzzing rule.
360
+ #
361
+ # @return [(Regexp, Enumerator)]
362
+ # The fuzzing pattern and list of substitutions.
363
+ #
364
+ def parse_rule(value)
365
+ if value.start_with?('/')
366
+ unless (index = value.rindex('/:'))
367
+ raise(OptionParser::InvalidArgument,"argument must be of the form /REGEXP/:REPLACE, but was: #{value}")
368
+ end
369
+
370
+ regexp = parse_pattern(value[1...index])
371
+ substitution = parse_substitution(value[index+2..])
372
+
373
+ return [regexp, substitution]
374
+ else
375
+ unless (index = value.rindex(':'))
376
+ raise(OptionParser::InvalidArgument,"argument must be of the form STRING:STYLE but was: #{value}")
377
+ end
378
+
379
+ pattern = parse_pattern(value[0...index])
380
+ substitution = parse_substitution(value[index+1..])
381
+
382
+ return [pattern, substitution]
383
+ end
384
+ end
385
+
268
386
  #
269
387
  # Parses a fuzz pattern.
270
388
  #
@@ -281,9 +399,8 @@ module Ronin
281
399
  when /^[a-z][a-z_]+$/
282
400
  const = string.upcase
283
401
 
284
- if (Regexp.const_defined?(const) &&
285
- Regexp.const_get(const).kind_of?(Regexp))
286
- Regexp.const_get(const)
402
+ if Support::Text::Patterns.const_defined?(const,false)
403
+ Support::Text::Patterns.const_get(const,false)
287
404
  else
288
405
  string
289
406
  end
@@ -313,9 +430,9 @@ module Ronin
313
430
  lengths.to_i
314
431
  end
315
432
 
316
- Fuzzer::Repeater.new(lengths).each(string)
433
+ Fuzzing::Repeater.new(lengths).each(string)
317
434
  else
318
- Fuzzer[string]
435
+ Fuzzing[string]
319
436
  end
320
437
  end
321
438
 
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # ronin-fuzzer - A Ruby library for generating, mutating, and fuzzing data.
3
3
  #
4
- # Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ # Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
5
  #
6
6
  # This file is part of ronin-fuzzer.
7
7
  #
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # ronin-fuzzer - A Ruby library for generating, mutating, and fuzzing data.
3
3
  #
4
- # Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ # Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
5
  #
6
6
  # This file is part of ronin-fuzzer.
7
7
  #
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # ronin-fuzzer - A Ruby library for generating, mutating, and fuzzing data.
3
3
  #
4
- # Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ # Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
5
  #
6
6
  # This file is part of ronin-fuzzer.
7
7
  #
@@ -22,6 +22,6 @@
22
22
  module Ronin
23
23
  module Fuzzer
24
24
  # ronin-fuzzer version
25
- VERSION = '0.1.0.beta1'
25
+ VERSION = '0.1.0'
26
26
  end
27
27
  end
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # ronin-fuzzer - A Ruby library for generating, mutating, and fuzzing data.
3
3
  #
4
- # Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ # Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
5
  #
6
6
  # This file is part of ronin-fuzzer.
7
7
  #
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # ronin-fuzzer - A Ruby library for generating, mutating, and fuzzing data.
3
3
  #
4
- # Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ # Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
5
  #
6
6
  # This file is part of ronin-fuzzer.
7
7
  #
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # ronin-fuzzer - A Ruby library for generating, mutating, and fuzzing data.
3
3
  #
4
- # Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ # Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
5
  #
6
6
  # This file is part of ronin-fuzzer.
7
7
  #
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # ronin-fuzzer - A Ruby library for generating, mutating, and fuzzing data.
3
3
  #
4
- # Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ # Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
5
  #
6
6
  # This file is part of ronin-fuzzer.
7
7
  #
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # ronin-fuzzer - A Ruby library for generating, mutating, and fuzzing data.
3
3
  #
4
- # Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ # Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
5
  #
6
6
  # This file is part of ronin-fuzzer.
7
7
  #
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # ronin-fuzzer - A Ruby library for generating, mutating, and fuzzing data.
3
3
  #
4
- # Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ # Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
5
  #
6
6
  # This file is part of ronin-fuzzer.
7
7
  #
data/lib/ronin/fuzzing.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # ronin-fuzzer - A Ruby library for generating, mutating, and fuzzing data.
3
3
  #
4
- # Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ # Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
5
  #
6
6
  # This file is part of ronin-fuzzer.
7
7
  #
@@ -53,8 +53,8 @@ The output PATH to write the fuzzer to\.
53
53
  .LP
54
54
  .TP
55
55
  \fB-c\fR, \fB--command\fR \fICOMMAND\fP
56
- The command to run with the fuzzed data\. All ocurrences of \fB#string#\fR
57
- will be replaced with the fuzzed data, and ocurrences of \fB#path#\fR will
56
+ The command to run with the fuzzed data\. All occurrences of \fB#string#\fR
57
+ will be replaced with the fuzzed data, and occurrences of \fB#path#\fR will
58
58
  be replaced with the path to the fuzzed data\.
59
59
  .LP
60
60
  .TP
@@ -40,8 +40,8 @@ to output files, run in commands or sent to TCP/UDP services.
40
40
  The output PATH to write the fuzzer to.
41
41
 
42
42
  `-c`, `--command` *COMMAND*
43
- The command to run with the fuzzed data. All ocurrences of `#string#`
44
- will be replaced with the fuzzed data, and ocurrences of `#path#` will
43
+ The command to run with the fuzzed data. All occurrences of `#string#`
44
+ will be replaced with the fuzzed data, and occurrences of `#path#` will
45
45
  be replaced with the path to the fuzzed data.
46
46
 
47
47
  `-t`, `--tcp` *HOST*:*PORT*
data/ronin-fuzzer.gemspec CHANGED
@@ -27,13 +27,14 @@ Gem::Specification.new do |gem|
27
27
  gem.files = `git ls-files`.split($/)
28
28
  gem.files = glob[gemspec['files']] if gemspec['files']
29
29
  gem.files += Array(gemspec['generated_files'])
30
+ # exclude test files from the packages gem
31
+ gem.files -= glob[gemspec['test_files'] || 'spec/{**/}*']
30
32
 
31
33
  gem.executables = gemspec.fetch('executables') do
32
34
  glob['bin/*'].map { |path| File.basename(path) }
33
35
  end
34
36
 
35
37
  gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
36
- gem.test_files = glob[gemspec['test_files'] || 'spec/{**/}*_spec.rb']
37
38
  gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
38
39
 
39
40
  gem.require_paths = Array(gemspec.fetch('require_paths') {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ronin-fuzzer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.beta1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Postmodern
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-01 00:00:00.000000000 Z
11
+ date: 2023-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: combinatorics
@@ -30,28 +30,28 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.0.0.beta1
33
+ version: '1.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.0.0.beta1
40
+ version: '1.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: ronin-core
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.1.0.beta1
47
+ version: '0.1'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.1.0.beta1
54
+ version: '0.1'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -66,9 +66,9 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '2.0'
69
- description: 'A Ruby library for generating, mutating, and fuzzing data.
70
-
71
- '
69
+ description: |
70
+ A Ruby library and CLI for generating, mutating, and fuzzing data.
71
+ The goal of ronin-fuzzer is to be both easy to use and highly customizable.
72
72
  email: postmodern.mod3@gmail.com
73
73
  executables:
74
74
  - ronin-fuzzer
@@ -106,21 +106,15 @@ files:
106
106
  - man/ronin-fuzzer-fuzz.1
107
107
  - man/ronin-fuzzer-fuzz.1.md
108
108
  - ronin-fuzzer.gemspec
109
- - spec/core_ext/string_spec.rb
110
- - spec/fuzzer_spec.rb
111
- - spec/fuzzing_spec.rb
112
- - spec/mutator_spec.rb
113
- - spec/repeater_spec.rb
114
- - spec/spec_helper.rb
115
- - spec/template_spec.rb
116
109
  homepage: https://ronin-rb.dev/
117
110
  licenses:
118
111
  - LGPL-3.0
119
112
  metadata:
120
- documentation_uri: https://rubydoc.info/gems/ronin-fuzzer
113
+ documentation_uri: https://ronin-rb.dev/docs/ronin-fuzzer
121
114
  source_code_uri: https://github.com/ronin-rb/ronin-fuzzer
122
115
  bug_tracker_uri: https://github.com/ronin-rb/ronin-fuzzer/issues
123
- changelog_uri: https://github.com/ronin-rb/ronin-fuzzer/blob/master/ChangeLog.md
116
+ changelog_uri: https://github.com/ronin-rb/ronin-fuzzer/blob/main/ChangeLog.md
117
+ rubygems_mfa_required: 'true'
124
118
  post_install_message:
125
119
  rdoc_options: []
126
120
  require_paths:
@@ -139,11 +133,5 @@ requirements: []
139
133
  rubygems_version: 3.3.26
140
134
  signing_key:
141
135
  specification_version: 4
142
- summary: generate, mutate, and fuzz data
143
- test_files:
144
- - spec/core_ext/string_spec.rb
145
- - spec/fuzzer_spec.rb
146
- - spec/fuzzing_spec.rb
147
- - spec/mutator_spec.rb
148
- - spec/repeater_spec.rb
149
- - spec/template_spec.rb
136
+ summary: A highly configurable fuzzing library and CLI for Ruby.
137
+ test_files: []
@@ -1,87 +0,0 @@
1
- require 'spec_helper'
2
- require 'ronin/fuzzing/core_ext/string'
3
-
4
- describe String do
5
- it "should provide String.generate" do
6
- expect(described_class).to respond_to(:generate)
7
- end
8
-
9
- it "should provide String#repeating" do
10
- expect(subject).to respond_to(:repeating)
11
- end
12
-
13
- it "should provide String#fuzz" do
14
- expect(subject).to respond_to(:fuzz)
15
- end
16
-
17
- it "should provide String#mutate" do
18
- expect(subject).to respond_to(:mutate)
19
- end
20
-
21
- describe "generate" do
22
- subject { described_class }
23
-
24
- it "should generate Strings from a template" do
25
- strings = subject.generate([:numeric, 2]).to_a
26
-
27
- expect(strings.grep(/^[0-9]{2}$/)).to eq(strings)
28
- end
29
- end
30
-
31
- describe "#repeating" do
32
- subject { 'A' }
33
-
34
- context "when n is an Integer" do
35
- let(:n) { 100 }
36
-
37
- it "should multiply the String by n" do
38
- expect(subject.repeating(n)).to eq(subject * n)
39
- end
40
- end
41
-
42
- context "when n is Enumerable" do
43
- let(:n) { [128, 512, 1024] }
44
-
45
- it "should repeat the String by each length" do
46
- strings = subject.repeating(n).to_a
47
-
48
- expect(strings).to eq(n.map { |length| subject * length })
49
- end
50
- end
51
- end
52
-
53
- describe "#fuzz" do
54
- subject { "foo bar" }
55
-
56
- it "should apply each fuzzing rule individually" do
57
- strings = subject.fuzz(/o/ => ['O', '0'], /a/ => ['A', '@']).to_a
58
-
59
- expect(strings).to match_array([
60
- "fOo bar",
61
- "f0o bar",
62
- "foO bar",
63
- "fo0 bar",
64
- "foo bAr",
65
- "foo b@r"
66
- ])
67
- end
68
- end
69
-
70
- describe "#mutate" do
71
- subject { "foo bar" }
72
-
73
- it "should apply every combination of mutation rules" do
74
- strings = subject.mutate(/o/ => ['0'], /a/ => ['@']).to_a
75
-
76
- expect(strings).to match_array([
77
- "f0o bar",
78
- "fo0 bar",
79
- "f00 bar",
80
- "foo b@r",
81
- "f0o b@r",
82
- "fo0 b@r",
83
- "f00 b@r"
84
- ])
85
- end
86
- end
87
- end
data/spec/fuzzer_spec.rb DELETED
@@ -1,109 +0,0 @@
1
- require 'spec_helper'
2
- require 'ronin/fuzzing/fuzzer'
3
-
4
- describe Ronin::Fuzzing::Fuzzer do
5
- let(:string) { 'GET /one/two/three' }
6
-
7
- describe "#initialize" do
8
- subject { described_class }
9
-
10
- context "patterns" do
11
- let(:substitutions) { ['bar'] }
12
-
13
- it "should accept Regexps" do
14
- fuzzer = subject.new(/foo/ => substitutions)
15
-
16
- expect(fuzzer.rules).to have_key(/foo/)
17
- end
18
-
19
- context "when given Strings" do
20
- subject { described_class.new('foo' => substitutions) }
21
-
22
- it "should convert to Regexp" do
23
- expect(subject.rules).to have_key(/foo/)
24
- end
25
- end
26
-
27
- context "when given Symbols" do
28
- subject { described_class.new(:word => substitutions) }
29
-
30
- it "should lookup the Ronin::Support::Text::Patterns constant" do
31
- expect(subject.rules).to have_key(Ronin::Support::Text::Patterns::WORD)
32
- end
33
- end
34
-
35
- context "otherwise" do
36
- it "should raise a TypeError" do
37
- expect {
38
- subject.new(Object.new => substitutions)
39
- }.to raise_error(TypeError)
40
- end
41
- end
42
- end
43
-
44
- context "substitutions" do
45
- let(:pattern) { /foo/ }
46
-
47
- it "should accept Enumerable values" do
48
- fuzzer = subject.new(pattern => ['bar'])
49
-
50
- expect(fuzzer.rules[pattern]).to eq(['bar'])
51
- end
52
-
53
- context "when given Symbols" do
54
- subject { described_class.new(pattern => :bad_strings) }
55
-
56
- it "should map to an Enumerator for a Fuzzing method" do
57
- expect(subject.rules[pattern]).to be_kind_of(Enumerable)
58
- end
59
- end
60
-
61
- context "otherwise" do
62
- it "should raise a TypeError" do
63
- expect {
64
- subject.new(pattern => Object.new)
65
- }.to raise_error(TypeError)
66
- end
67
- end
68
- end
69
- end
70
-
71
- describe "#each" do
72
- let(:string) { "foo bar" }
73
-
74
- subject { described_class.new(/o/ => ['O', '0'], /a/ => ['A', '@']) }
75
-
76
- it "should apply each fuzzing rule individually" do
77
- expect(subject.each(string).to_a).to match_array([
78
- "fOo bar",
79
- "f0o bar",
80
- "foO bar",
81
- "fo0 bar",
82
- "foo bAr",
83
- "foo b@r"
84
- ])
85
- end
86
-
87
- context "when mutations contain Integers" do
88
- subject { described_class.new(/o/ => [48]) }
89
-
90
- it "should convert them to characters" do
91
- expect(subject.each(string).to_a).to match_array([
92
- "f0o bar",
93
- "fo0 bar"
94
- ])
95
- end
96
- end
97
-
98
- context "when mutations contain Procs" do
99
- subject { described_class.new(/o/ => [lambda { |str| str.upcase }]) }
100
-
101
- it "should call them with the matched String" do
102
- expect(subject.each(string).to_a).to match_array([
103
- "fOo bar",
104
- "foO bar"
105
- ])
106
- end
107
- end
108
- end
109
- end
data/spec/fuzzing_spec.rb DELETED
@@ -1,24 +0,0 @@
1
- require 'spec_helper'
2
- require 'ronin/fuzzing'
3
-
4
- describe Ronin::Fuzzing do
5
- describe "[]" do
6
- let(:method) { :bad_strings }
7
-
8
- it "should return Enumerators for fuzzing methods" do
9
- expect(subject[method]).to be_kind_of(Enumerable)
10
- end
11
-
12
- it "should raise NoMethodError for unknown methods" do
13
- expect {
14
- subject[:foo]
15
- }.to raise_error(NoMethodError)
16
- end
17
-
18
- it "should not allow accessing inherited methods" do
19
- expect {
20
- subject[:instance_eval]
21
- }.to raise_error(NoMethodError)
22
- end
23
- end
24
- end
data/spec/mutator_spec.rb DELETED
@@ -1,112 +0,0 @@
1
- require 'spec_helper'
2
- require 'ronin/fuzzing/mutator'
3
-
4
- describe Ronin::Fuzzing::Mutator do
5
- let(:string) { 'GET /one/two/three' }
6
-
7
- describe "#initialize" do
8
- subject { described_class }
9
-
10
- context "patterns" do
11
- let(:substitutions) { ['bar'] }
12
-
13
- it "should accept Regexps" do
14
- fuzzer = subject.new(/foo/ => substitutions)
15
-
16
- expect(fuzzer.rules).to have_key(/foo/)
17
- end
18
-
19
- context "when given Strings" do
20
- subject { described_class.new('foo' => substitutions) }
21
-
22
- it "should convert to Regexp" do
23
- expect(subject.rules).to have_key(/foo/)
24
- end
25
- end
26
-
27
- context "when given Symbols" do
28
- subject { described_class.new(:word => substitutions) }
29
-
30
- it "should lookup the Ronin::Support::Text::Patterns constant" do
31
- expect(subject.rules).to have_key(Ronin::Support::Text::Patterns::WORD)
32
- end
33
- end
34
-
35
- context "otherwise" do
36
- it "should raise a TypeError" do
37
- expect {
38
- subject.new(Object.new => substitutions)
39
- }.to raise_error(TypeError)
40
- end
41
- end
42
- end
43
-
44
- context "mutations" do
45
- let(:pattern) { /foo/ }
46
-
47
- it "should accept Enumerable values" do
48
- fuzzer = subject.new(pattern => ['bar'])
49
-
50
- expect(fuzzer.rules[pattern]).to eq(['bar'])
51
- end
52
-
53
- context "when given Symbols" do
54
- subject { described_class.new(pattern => :bad_strings) }
55
-
56
- it "should map to an Enumerator for a Fuzzing method" do
57
- expect(subject.rules[pattern]).to be_kind_of(Enumerable)
58
- end
59
- end
60
-
61
- context "otherwise" do
62
- it "should raise a TypeError" do
63
- expect {
64
- subject.new(pattern => Object.new)
65
- }.to raise_error(TypeError)
66
- end
67
- end
68
- end
69
- end
70
-
71
- describe "#each" do
72
- let(:string) { "foo bar" }
73
-
74
- subject { described_class.new(/o/ => ['0'], /a/ => ['@']) }
75
-
76
- it "should apply every combination of mutation rules" do
77
- expect(subject.each(string).to_a).to match_array([
78
- "f0o bar",
79
- "fo0 bar",
80
- "f00 bar",
81
- "foo b@r",
82
- "f0o b@r",
83
- "fo0 b@r",
84
- "f00 b@r"
85
- ])
86
- end
87
-
88
- context "when mutations contain Integers" do
89
- subject { described_class.new(/o/ => [48]) }
90
-
91
- it "should convert them to characters" do
92
- expect(subject.each(string).to_a).to match_array([
93
- "f0o bar",
94
- "fo0 bar",
95
- "f00 bar"
96
- ])
97
- end
98
- end
99
-
100
- context "when mutations contain Procs" do
101
- subject { described_class.new(/o/ => [lambda { |str| str.upcase }]) }
102
-
103
- it "should call them with the matched String" do
104
- expect(subject.each(string).to_a).to match_array([
105
- "fOo bar",
106
- "foO bar",
107
- "fOO bar"
108
- ])
109
- end
110
- end
111
- end
112
- end
@@ -1,57 +0,0 @@
1
- require 'spec_helper'
2
- require 'ronin/fuzzing/repeater'
3
-
4
- describe Ronin::Fuzzing::Repeater do
5
- describe "#initialize" do
6
- subject { described_class }
7
-
8
- context "when lengths is an Integer" do
9
- it "should coerce lengths to an Enumerable" do
10
- repeator = subject.new(10)
11
-
12
- expect(repeator.lengths).to be_kind_of(Enumerable)
13
- end
14
- end
15
-
16
- context "when lengths is not Enumerable or an Integer" do
17
- it "should raise a TypeError" do
18
- expect {
19
- subject.new(Object.new)
20
- }.to raise_error(TypeError)
21
- end
22
- end
23
- end
24
-
25
- describe "#each" do
26
- let(:repeatable) { 'A' }
27
-
28
- context "when lengths was an Integer" do
29
- let(:length) { 10 }
30
-
31
- subject { described_class.new(length) }
32
-
33
- it "should yield one repeated value" do
34
- values = subject.each(repeatable).to_a
35
-
36
- expect(values).to eq([repeatable * length])
37
- end
38
- end
39
-
40
- context "when lengths was Enumerable" do
41
- let(:lengths) { (1..4) }
42
-
43
- subject { described_class.new(lengths) }
44
-
45
- it "should yield repeated values for each length" do
46
- values = subject.each(repeatable).to_a
47
-
48
- expect(values).to eq([
49
- repeatable * 1,
50
- repeatable * 2,
51
- repeatable * 3,
52
- repeatable * 4
53
- ])
54
- end
55
- end
56
- end
57
- end
data/spec/spec_helper.rb DELETED
@@ -1,4 +0,0 @@
1
- require 'rspec'
2
- require 'simplecov'
3
-
4
- SimpleCov.start
@@ -1,54 +0,0 @@
1
- require 'spec_helper'
2
- require 'ronin/fuzzing/template'
3
-
4
- describe Ronin::Fuzzing::Template do
5
- subject { described_class }
6
-
7
- it "should generate Strings from CharSets" do
8
- strings = subject.new([:lowercase_hexadecimal, :numeric]).to_a
9
-
10
- expect(strings.grep(/^[0-9a-f][0-9]$/)).to eq(strings)
11
- end
12
-
13
- it "should generate Strings from lengths of CharSets" do
14
- strings = subject.new([[:numeric, 2]]).to_a
15
-
16
- expect(strings.grep(/^[0-9]{2}$/)).to eq(strings)
17
- end
18
-
19
- it "should generate Strings from varying lengths of CharSets" do
20
- strings = subject.new([[:numeric, 1..2]]).to_a
21
-
22
- expect(strings.grep(/^[0-9]{1,2}$/)).to eq(strings)
23
- end
24
-
25
- it "should generate Strings from custom CharSets" do
26
- strings = subject.new([[%w[a b c], 2]]).to_a
27
-
28
- expect(strings.grep(/^[abc]{2}$/)).to eq(strings)
29
- end
30
-
31
- it "should generate Strings containing known Strings" do
32
- strings = subject.new(['foo', [%w[a b c], 2]]).to_a
33
-
34
- expect(strings.grep(/^foo[abc]{2}$/)).to eq(strings)
35
- end
36
-
37
- it "should raise a TypeError for non String, Symbol, Enumerable CharSets" do
38
- expect {
39
- subject.new([[Object.new, 2]]).to_a
40
- }.to raise_error(TypeError)
41
- end
42
-
43
- it "should raise an ArgumentError for unknown CharSets" do
44
- expect {
45
- subject.new([[:foo_bar, 2]]).to_a
46
- }.to raise_error(ArgumentError)
47
- end
48
-
49
- it "should raise a TypeError for non Integer,Array,Range lengths" do
50
- expect {
51
- subject.new([[:numeric, 'foo']]).to_a
52
- }.to raise_error(TypeError)
53
- end
54
- end