ronin-fuzzer 0.1.0.beta1
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 +7 -0
- data/.document +5 -0
- data/.github/workflows/ruby.yml +31 -0
- data/.gitignore +13 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/.yardopts +1 -0
- data/COPYING.txt +165 -0
- data/ChangeLog.md +9 -0
- data/Gemfile +39 -0
- data/README.md +91 -0
- data/Rakefile +34 -0
- data/bin/ronin-fuzzer +37 -0
- data/gemspec.yml +30 -0
- data/lib/ronin/fuzzer/cli/command.rb +37 -0
- data/lib/ronin/fuzzer/cli/commands/fuzz.rb +326 -0
- data/lib/ronin/fuzzer/cli.rb +39 -0
- data/lib/ronin/fuzzer/root.rb +29 -0
- data/lib/ronin/fuzzer/version.rb +27 -0
- data/lib/ronin/fuzzing/core_ext/string.rb +203 -0
- data/lib/ronin/fuzzing/core_ext.rb +22 -0
- data/lib/ronin/fuzzing/fuzzer.rb +112 -0
- data/lib/ronin/fuzzing/mutator.rb +163 -0
- data/lib/ronin/fuzzing/repeater.rb +81 -0
- data/lib/ronin/fuzzing/template.rb +133 -0
- data/lib/ronin/fuzzing.rb +365 -0
- data/man/ronin-fuzzer-fuzz.1 +95 -0
- data/man/ronin-fuzzer-fuzz.1.md +73 -0
- data/ronin-fuzzer.gemspec +61 -0
- data/spec/core_ext/string_spec.rb +87 -0
- data/spec/fuzzer_spec.rb +109 -0
- data/spec/fuzzing_spec.rb +24 -0
- data/spec/mutator_spec.rb +112 -0
- data/spec/repeater_spec.rb +57 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/template_spec.rb +54 -0
- metadata +149 -0
@@ -0,0 +1,365 @@
|
|
1
|
+
#
|
2
|
+
# ronin-fuzzer - A Ruby library for generating, mutating, and fuzzing data.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
5
|
+
#
|
6
|
+
# This file is part of ronin-fuzzer.
|
7
|
+
#
|
8
|
+
# ronin-fuzzer is free software: you can redistribute it and/or modify
|
9
|
+
# it under the terms of the GNU Lesser General Public License as published
|
10
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
11
|
+
# (at your option) any later version.
|
12
|
+
#
|
13
|
+
# ronin-fuzzer is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU Lesser General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU Lesser General Public License
|
19
|
+
# along with ronin-fuzzer. If not, see <https://www.gnu.org/licenses/>.
|
20
|
+
#
|
21
|
+
|
22
|
+
require 'ronin/fuzzing/fuzzer'
|
23
|
+
require 'ronin/fuzzing/mutator'
|
24
|
+
require 'ronin/fuzzing/repeater'
|
25
|
+
require 'ronin/fuzzing/core_ext'
|
26
|
+
|
27
|
+
require 'set'
|
28
|
+
|
29
|
+
module Ronin
|
30
|
+
#
|
31
|
+
# Contains class-methods which generate malicious data for fuzzing.
|
32
|
+
#
|
33
|
+
# @see Fuzzing.[]
|
34
|
+
#
|
35
|
+
module Fuzzing
|
36
|
+
# Short String lengths
|
37
|
+
SHORT_LENGTHS = Set[1, 100, 500, 1_000, 10_000]
|
38
|
+
|
39
|
+
# Long String lengths
|
40
|
+
LONG_LENGTHS = Set[
|
41
|
+
128, 255, 256, 257, 511, 512, 513, 1023, 1024, 2048, 2049, 4095,
|
42
|
+
4096, 4097, 5_000, 10_000, 20_000, 32762, 32763, 32764, 32765, 32766,
|
43
|
+
32767, 32768, 32769,
|
44
|
+
0xffff-2, 0xffff-1, 0xffff, 0xffff+1, 0xffff+2,
|
45
|
+
99_999, 100_000, 500_000, 1_000_000
|
46
|
+
]
|
47
|
+
|
48
|
+
# Null bytes in various encodings
|
49
|
+
NULL_BYTES = ['%00', '%u0000', "\x00"]
|
50
|
+
|
51
|
+
# Newline characters
|
52
|
+
NEW_LINES = ["\n", "\r", "\n\r"]
|
53
|
+
|
54
|
+
# Format String flags
|
55
|
+
FORMAT_STRINGS = ['%p', '%s', '%n']
|
56
|
+
|
57
|
+
#
|
58
|
+
# Returns a fuzzer method.
|
59
|
+
#
|
60
|
+
# @param [Symbol] name
|
61
|
+
# The name of the fuzzer to return.
|
62
|
+
#
|
63
|
+
# @return [Enumerator]
|
64
|
+
# An Enumerator for the fuzzer method.
|
65
|
+
#
|
66
|
+
# @raise [NoMethodError]
|
67
|
+
# The fuzzing method could not be found.
|
68
|
+
#
|
69
|
+
# @api semipublic
|
70
|
+
#
|
71
|
+
def self.[](name)
|
72
|
+
if (!respond_to?(name) || Module.respond_to?(name))
|
73
|
+
raise(NoMethodError,"no such fuzzing method: #{name}")
|
74
|
+
end
|
75
|
+
|
76
|
+
return enum_for(name)
|
77
|
+
end
|
78
|
+
|
79
|
+
module_function
|
80
|
+
|
81
|
+
#
|
82
|
+
# Various bad-strings.
|
83
|
+
#
|
84
|
+
# @yield [string]
|
85
|
+
# The given block will be passed each bad-string.
|
86
|
+
#
|
87
|
+
# @yieldparam [String] string
|
88
|
+
# A bad-string containing known control characters, deliminators
|
89
|
+
# or null-bytes (see {NULL_BYTES}), of varying length
|
90
|
+
# (see {SHORT_LENGTHS} and {LONG_LENGTHS}).
|
91
|
+
#
|
92
|
+
def bad_strings(&block)
|
93
|
+
yield ''
|
94
|
+
|
95
|
+
chars = [
|
96
|
+
'A', 'a', '1', '<', '>', '"', "'", '/', "\\", '?', '=', 'a=', '&',
|
97
|
+
'.', ',', '(', ')', ']', '[', '%', '*', '-', '+', '{', '}',
|
98
|
+
"\x14", "\xfe", "\xff"
|
99
|
+
]
|
100
|
+
|
101
|
+
chars.each do |c|
|
102
|
+
LONG_LENGTHS.each { |length| yield c * length }
|
103
|
+
end
|
104
|
+
|
105
|
+
yield '!@#$%%^#$%#$@#$%$$@#$%^^**(()'
|
106
|
+
yield '%01%02%03%04%0a%0d%0aADSF'
|
107
|
+
yield '%01%02%03@%04%0a%0d%0aADSF'
|
108
|
+
|
109
|
+
NULL_BYTES.each do |c|
|
110
|
+
SHORT_LENGTHS.each { |length| yield c * length }
|
111
|
+
end
|
112
|
+
|
113
|
+
yield "%\xfe\xf0%\x00\xff"
|
114
|
+
yield "%\xfe\xf0%\x00\xff" * 20
|
115
|
+
|
116
|
+
SHORT_LENGTHS.each do |length|
|
117
|
+
yield "\xde\xad\xbe\xef" * length
|
118
|
+
end
|
119
|
+
|
120
|
+
yield "\n\r" * 100
|
121
|
+
yield "<>" * 500
|
122
|
+
end
|
123
|
+
|
124
|
+
#
|
125
|
+
# Various format-strings.
|
126
|
+
#
|
127
|
+
# @yield [fmt_string]
|
128
|
+
# The given block will be passed each format-string.
|
129
|
+
#
|
130
|
+
# @yieldparam [String] fmt_string
|
131
|
+
# A format-string containing format operators (see {FORMAT_STRINGS}).
|
132
|
+
#
|
133
|
+
def format_strings(&block)
|
134
|
+
FORMAT_STRINGS.each do |fmt|
|
135
|
+
yield fmt
|
136
|
+
yield fmt * 100
|
137
|
+
yield fmt * 500
|
138
|
+
yield "\"#{fmt}\"" * 500
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
#
|
143
|
+
# Various bad paths and directory traversals.
|
144
|
+
#
|
145
|
+
# @yield [path]
|
146
|
+
# The given block will be passed each path.
|
147
|
+
#
|
148
|
+
# @yieldparam [String] path
|
149
|
+
# A known bad path.
|
150
|
+
#
|
151
|
+
def bad_paths(&block)
|
152
|
+
padding = 'A' * 5_000
|
153
|
+
|
154
|
+
yield "/.:/#{padding}\x00\x00"
|
155
|
+
yield "/.../#{padding}\x00\x00"
|
156
|
+
|
157
|
+
yield "\\\\*"
|
158
|
+
yield "\\\\?\\"
|
159
|
+
|
160
|
+
yield "/\\" * 5_000
|
161
|
+
yield '/.' * 5_000
|
162
|
+
|
163
|
+
NULL_BYTES.each do |c|
|
164
|
+
if c.start_with?('%')
|
165
|
+
yield "#{c}/"
|
166
|
+
yield "/#{c}"
|
167
|
+
yield "/#{c}/"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
#
|
173
|
+
# The range of bit-fields.
|
174
|
+
#
|
175
|
+
# @yield [bitfield]
|
176
|
+
# The given block will be passed each bit-field.
|
177
|
+
#
|
178
|
+
# @yieldparam [String] bitfield
|
179
|
+
# A bit-field (8bit - 64bit).
|
180
|
+
#
|
181
|
+
def bit_fields(&block)
|
182
|
+
("\x00".."\xff").each do |c|
|
183
|
+
yield c
|
184
|
+
yield c << c # x2
|
185
|
+
yield c << c # x4
|
186
|
+
yield c << c # x8
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
#
|
191
|
+
# The range of signed bit-fields.
|
192
|
+
#
|
193
|
+
# @yield [bitfield]
|
194
|
+
# The given block will be passed each bit-field.
|
195
|
+
#
|
196
|
+
# @yieldparam [String] bitfield
|
197
|
+
# A signed bit-field (8bit - 64bit).
|
198
|
+
#
|
199
|
+
def signed_bit_fields(&block)
|
200
|
+
("\x80".."\xff").each do |c|
|
201
|
+
yield c
|
202
|
+
yield c << c # x2
|
203
|
+
yield c << c # x4
|
204
|
+
yield c << c # x8
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
#
|
209
|
+
# The range of unsigned 8bit integers.
|
210
|
+
#
|
211
|
+
# @yield [int]
|
212
|
+
# The given block will be passed each integer.
|
213
|
+
#
|
214
|
+
# @yieldparam [String] int
|
215
|
+
# A unsigned 8bit integer.
|
216
|
+
#
|
217
|
+
def uint8(&block)
|
218
|
+
("\x00".."\xff").each(&block)
|
219
|
+
end
|
220
|
+
|
221
|
+
#
|
222
|
+
# The range of unsigned 16bit integers.
|
223
|
+
#
|
224
|
+
# @yield [int]
|
225
|
+
# The given block will be passed each integer.
|
226
|
+
#
|
227
|
+
# @yieldparam [String] int
|
228
|
+
# A unsigned 16bit integer.
|
229
|
+
#
|
230
|
+
def uint16
|
231
|
+
uint8 { |c| yield c * 2 }
|
232
|
+
end
|
233
|
+
|
234
|
+
#
|
235
|
+
# The range of unsigned 32bit integers.
|
236
|
+
#
|
237
|
+
# @yield [int]
|
238
|
+
# The given block will be passed each integer.
|
239
|
+
#
|
240
|
+
# @yieldparam [String] int
|
241
|
+
# A unsigned 32bit integer.
|
242
|
+
#
|
243
|
+
def uint32
|
244
|
+
uint8 { |c| yield c * 4 }
|
245
|
+
end
|
246
|
+
|
247
|
+
#
|
248
|
+
# The range of unsigned 64bit integers.
|
249
|
+
#
|
250
|
+
# @yield [int]
|
251
|
+
# The given block will be passed each integer.
|
252
|
+
#
|
253
|
+
# @yieldparam [String] int
|
254
|
+
# A unsigned 64bit integer.
|
255
|
+
#
|
256
|
+
def uint64
|
257
|
+
uint8 { |c| yield c * 8 }
|
258
|
+
end
|
259
|
+
|
260
|
+
#
|
261
|
+
# The range of signed 8bit integers.
|
262
|
+
#
|
263
|
+
# @yield [int]
|
264
|
+
# The given block will be passed each integer.
|
265
|
+
#
|
266
|
+
# @yieldparam [String] int
|
267
|
+
# A signed 8bit integer.
|
268
|
+
#
|
269
|
+
def int8(&block)
|
270
|
+
("\x00".."\x70").each(&block)
|
271
|
+
end
|
272
|
+
|
273
|
+
#
|
274
|
+
# The range of signed 16bit integers.
|
275
|
+
#
|
276
|
+
# @yield [int]
|
277
|
+
# The given block will be passed each integer.
|
278
|
+
#
|
279
|
+
# @yieldparam [String] int
|
280
|
+
# A signed 16bit integer.
|
281
|
+
#
|
282
|
+
def int16
|
283
|
+
int8 { |c| yield c * 2 }
|
284
|
+
end
|
285
|
+
|
286
|
+
#
|
287
|
+
# The range of signed 32bit integers.
|
288
|
+
#
|
289
|
+
# @yield [int]
|
290
|
+
# The given block will be passed each integer.
|
291
|
+
#
|
292
|
+
# @yieldparam [String] int
|
293
|
+
# A signed 32bit integer.
|
294
|
+
#
|
295
|
+
def int32
|
296
|
+
int8 { |c| yield c * 4 }
|
297
|
+
end
|
298
|
+
|
299
|
+
#
|
300
|
+
# The range of signed 64bit integers.
|
301
|
+
#
|
302
|
+
# @yield [int]
|
303
|
+
# The given block will be passed each integer.
|
304
|
+
#
|
305
|
+
# @yieldparam [String] int
|
306
|
+
# A signed 64bit integer.
|
307
|
+
#
|
308
|
+
def int64
|
309
|
+
int8 { |c| yield c * 8 }
|
310
|
+
end
|
311
|
+
|
312
|
+
#
|
313
|
+
# The range of negative-signed 8bit integers.
|
314
|
+
#
|
315
|
+
# @yield [int]
|
316
|
+
# The given block will be passed each integer.
|
317
|
+
#
|
318
|
+
# @yieldparam [String] int
|
319
|
+
# A negative-signed 8bit integer.
|
320
|
+
#
|
321
|
+
def sint8(&block)
|
322
|
+
("\x80".."\xff").each(&block)
|
323
|
+
end
|
324
|
+
|
325
|
+
#
|
326
|
+
# The range of negative-signed 16bit integers.
|
327
|
+
#
|
328
|
+
# @yield [int]
|
329
|
+
# The given block will be passed each integer.
|
330
|
+
#
|
331
|
+
# @yieldparam [String] int
|
332
|
+
# A negative-signed 16bit integer.
|
333
|
+
#
|
334
|
+
def sint16
|
335
|
+
sint8 { |c| yield c * 2 }
|
336
|
+
end
|
337
|
+
|
338
|
+
#
|
339
|
+
# The range of negative-signed 32bit integers.
|
340
|
+
#
|
341
|
+
# @yield [int]
|
342
|
+
# The given block will be passed each integer.
|
343
|
+
#
|
344
|
+
# @yieldparam [String] int
|
345
|
+
# A negative-signed 32bit integer.
|
346
|
+
#
|
347
|
+
def sint32
|
348
|
+
sint8 { |c| yield c * 4 }
|
349
|
+
end
|
350
|
+
|
351
|
+
#
|
352
|
+
# The range of negative-signed 64bit integers.
|
353
|
+
#
|
354
|
+
# @yield [int]
|
355
|
+
# The given block will be passed each integer.
|
356
|
+
#
|
357
|
+
# @yieldparam [String] int
|
358
|
+
# A negative-signed 64bit integer.
|
359
|
+
#
|
360
|
+
def sint64
|
361
|
+
sint8 { |c| yield c * 8 }
|
362
|
+
end
|
363
|
+
|
364
|
+
end
|
365
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
.\" Generated by kramdown-man 0.1.8
|
2
|
+
.\" https://github.com/postmodern/kramdown-man#readme
|
3
|
+
.TH ronin-fuzzer-fuzz 1 "2022-01-01" Ronin Fuzzer "User Manuals"
|
4
|
+
.LP
|
5
|
+
.SH SYNOPSIS
|
6
|
+
.LP
|
7
|
+
.HP
|
8
|
+
\fBronin-fuzzer fuzz\fR \[lB]\fIoptions\fP\[rB] \[lB]\fITEMPLATE\fP\[rB]
|
9
|
+
.LP
|
10
|
+
.SH DESCRIPTION
|
11
|
+
.LP
|
12
|
+
.PP
|
13
|
+
Fuzzes data read from a \fIFILE\fP or from \fBSTDIN\fR\. The fuzzed data can be written
|
14
|
+
to output files, run in commands or sent to TCP\[sl]UDP services\.
|
15
|
+
.LP
|
16
|
+
.SH OPTIONS
|
17
|
+
.LP
|
18
|
+
.TP
|
19
|
+
\fB-v\fR, \fB--[no-]verbose\fR
|
20
|
+
Enable verbose output\.
|
21
|
+
.LP
|
22
|
+
.TP
|
23
|
+
\fB-q\fR, \fB--[no-]quiet\fR
|
24
|
+
Disable verbose output\.
|
25
|
+
.LP
|
26
|
+
.TP
|
27
|
+
\fB--[no-]silent\fR
|
28
|
+
Silence all output\.
|
29
|
+
.LP
|
30
|
+
.TP
|
31
|
+
\fB-i\fR, \fB--input\fR \fIFILE\fP
|
32
|
+
The input text FILE to parse\. Data will be read from \fBSTDIN\fR by default\.
|
33
|
+
.LP
|
34
|
+
.HP
|
35
|
+
\fB-r\fR, \fB--rule\fR \[lB]\fIPATTERN\fP\[or]\fI\[sl]REGEXP\[sl]\fP\[or]STRING\[rB]:\[lB]\fIMETHOD\fP\[or]\fISTRING\fP\fI*N\fP\[lB]\-\fIM\fP\[rB]\[rB]
|
36
|
+
The rule to apply to the \fIINPUT\fP\. Fuzzer rules consist of a pattern and
|
37
|
+
substitution\. Patterns may be one of the following:
|
38
|
+
.LP
|
39
|
+
.nf
|
40
|
+
* A name of a Ronin Regular Expression (ex: \`unix\[ru]path\`)
|
41
|
+
* A custom Regular Expression (ex: \`\[sl]\ed\[pl]\[sl]\`)
|
42
|
+
* A plain String (ex: \`example\.com\`)\.
|
43
|
+
|
44
|
+
Substitutions may be one of the following:
|
45
|
+
|
46
|
+
* A method from \`Ronin::Fuzzer\` (ex: \`bad\[ru]strings\`)
|
47
|
+
* A *STRING*, repeated *N* or *M* times (ex: \`A*100\-200\`)\.
|
48
|
+
.fi
|
49
|
+
.LP
|
50
|
+
.TP
|
51
|
+
\fB-o\fR, \fB--output\fR \fIPATH\fP
|
52
|
+
The output PATH to write the fuzzer to\.
|
53
|
+
.LP
|
54
|
+
.TP
|
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
|
58
|
+
be replaced with the path to the fuzzed data\.
|
59
|
+
.LP
|
60
|
+
.TP
|
61
|
+
\fB-t\fR, \fB--tcp\fR \fIHOST\fP:\fIPORT\fP
|
62
|
+
The TCP service to send the fuzzed data to\.
|
63
|
+
.LP
|
64
|
+
.TP
|
65
|
+
\fB-u\fR, \fB--udp\fR \fIHOST\fP:\fIPORT\fP
|
66
|
+
The UDP service to send the fuzzed data to\.
|
67
|
+
.LP
|
68
|
+
.TP
|
69
|
+
\fB-p\fR, \fB--pause\fR \fISECONDS\fP
|
70
|
+
Pause in between mutations\.
|
71
|
+
.LP
|
72
|
+
.SH EXAMPLES
|
73
|
+
.LP
|
74
|
+
.TP
|
75
|
+
\fBronin-fuzzer fuzz -i http_request.txt -o bad.txt -r unix_path:bad_strings\fR
|
76
|
+
Fuzzes a HTTP request, replacing every occurrence of a UNIX path, with
|
77
|
+
strings from the \fBbad_strings\fR method\.
|
78
|
+
.LP
|
79
|
+
.SH LINKS
|
80
|
+
.LP
|
81
|
+
.PP
|
82
|
+
Ronin Regular Expressions
|
83
|
+
https:\[sl]\[sl]ronin\-rb\.dev\[sl]docs\[sl]ronin\-support\[sl]Regexp\.html
|
84
|
+
.LP
|
85
|
+
.TP
|
86
|
+
\fBRonin::Fuzzer\fR
|
87
|
+
https:\[sl]\[sl]ronin\-rb\.dev\[sl]docs\[sl]ronin\-fuzzer\[sl]Ronin\[sl]Fuzzer\.html
|
88
|
+
.LP
|
89
|
+
.SH AUTHOR
|
90
|
+
.LP
|
91
|
+
.PP
|
92
|
+
Postmodern
|
93
|
+
.MT postmodern\.mod3\[at]gmail\.com
|
94
|
+
.ME
|
95
|
+
.LP
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# ronin-fuzzer-fuzz 1 "2022-01-01" Ronin Fuzzer "User Manuals"
|
2
|
+
|
3
|
+
## SYNOPSIS
|
4
|
+
|
5
|
+
`ronin-fuzzer fuzz` [*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
|
+
`-i`, `--input` *FILE*
|
24
|
+
The input text FILE to parse. Data will be read from `STDIN` by default.
|
25
|
+
|
26
|
+
`-r`, `--rule` [*PATTERN*|*/REGEXP/*|STRING]:[*METHOD*|*STRING***N*[-*M*]]
|
27
|
+
The rule to apply to the *INPUT*. Fuzzer rules consist of a pattern and
|
28
|
+
substitution. Patterns may be one of the following:
|
29
|
+
|
30
|
+
* A name of a Ronin Regular Expression (ex: `unix_path`)
|
31
|
+
* A custom Regular Expression (ex: `/\d+/`)
|
32
|
+
* A plain String (ex: `example.com`).
|
33
|
+
|
34
|
+
Substitutions may be one of the following:
|
35
|
+
|
36
|
+
* A method from `Ronin::Fuzzer` (ex: `bad_strings`)
|
37
|
+
* A *STRING*, repeated *N* or *M* times (ex: `A*100-200`).
|
38
|
+
|
39
|
+
`-o`, `--output` *PATH*
|
40
|
+
The output PATH to write the fuzzer to.
|
41
|
+
|
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
|
45
|
+
be replaced with the path to the fuzzed data.
|
46
|
+
|
47
|
+
`-t`, `--tcp` *HOST*:*PORT*
|
48
|
+
The TCP service to send the fuzzed data to.
|
49
|
+
|
50
|
+
`-u`, `--udp` *HOST*:*PORT*
|
51
|
+
The UDP service to send the fuzzed data to.
|
52
|
+
|
53
|
+
`-p`, `--pause` *SECONDS*
|
54
|
+
Pause in between mutations.
|
55
|
+
|
56
|
+
## EXAMPLES
|
57
|
+
|
58
|
+
`ronin-fuzzer fuzz -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
|
+
https://ronin-rb.dev/docs/ronin-support/Regexp.html
|
66
|
+
|
67
|
+
`Ronin::Fuzzer`
|
68
|
+
https://ronin-rb.dev/docs/ronin-fuzzer/Ronin/Fuzzer.html
|
69
|
+
|
70
|
+
## AUTHOR
|
71
|
+
|
72
|
+
Postmodern <postmodern.mod3@gmail.com>
|
73
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gemspec = YAML.load_file('gemspec.yml')
|
7
|
+
|
8
|
+
gem.name = gemspec.fetch('name')
|
9
|
+
gem.version = gemspec.fetch('version') do
|
10
|
+
lib_dir = File.join(File.dirname(__FILE__),'lib')
|
11
|
+
$LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
|
12
|
+
|
13
|
+
require 'ronin/fuzzer/version'
|
14
|
+
Ronin::Fuzzer::VERSION
|
15
|
+
end
|
16
|
+
|
17
|
+
gem.summary = gemspec['summary']
|
18
|
+
gem.description = gemspec['description']
|
19
|
+
gem.licenses = Array(gemspec['license'])
|
20
|
+
gem.authors = Array(gemspec['authors'])
|
21
|
+
gem.email = gemspec['email']
|
22
|
+
gem.homepage = gemspec['homepage']
|
23
|
+
gem.metadata = gemspec['metadata'] if gemspec['metadata']
|
24
|
+
|
25
|
+
glob = lambda { |patterns| gem.files & Dir[*patterns] }
|
26
|
+
|
27
|
+
gem.files = `git ls-files`.split($/)
|
28
|
+
gem.files = glob[gemspec['files']] if gemspec['files']
|
29
|
+
gem.files += Array(gemspec['generated_files'])
|
30
|
+
|
31
|
+
gem.executables = gemspec.fetch('executables') do
|
32
|
+
glob['bin/*'].map { |path| File.basename(path) }
|
33
|
+
end
|
34
|
+
|
35
|
+
gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
|
36
|
+
gem.test_files = glob[gemspec['test_files'] || 'spec/{**/}*_spec.rb']
|
37
|
+
gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
|
38
|
+
|
39
|
+
gem.require_paths = Array(gemspec.fetch('require_paths') {
|
40
|
+
%w[ext lib].select { |dir| File.directory?(dir) }
|
41
|
+
})
|
42
|
+
|
43
|
+
gem.requirements = gemspec['requirements']
|
44
|
+
gem.required_ruby_version = gemspec['required_ruby_version']
|
45
|
+
gem.required_rubygems_version = gemspec['required_rubygems_version']
|
46
|
+
gem.post_install_message = gemspec['post_install_message']
|
47
|
+
|
48
|
+
split = lambda { |string| string.split(/,\s*/) }
|
49
|
+
|
50
|
+
if gemspec['dependencies']
|
51
|
+
gemspec['dependencies'].each do |name,versions|
|
52
|
+
gem.add_dependency(name,split[versions])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
if gemspec['development_dependencies']
|
57
|
+
gemspec['development_dependencies'].each do |name,versions|
|
58
|
+
gem.add_development_dependency(name,split[versions])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,87 @@
|
|
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
|