ronin-support 0.3.0 → 0.4.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/ChangeLog.md +77 -7
  2. data/README.md +19 -3
  3. data/gemspec.yml +2 -2
  4. data/lib/ronin/extensions/regexp.rb +50 -2
  5. data/lib/ronin/extensions/string.rb +1 -0
  6. data/lib/ronin/formatting.rb +1 -0
  7. data/lib/ronin/formatting/extensions.rb +1 -0
  8. data/lib/ronin/formatting/extensions/binary/string.rb +56 -5
  9. data/lib/ronin/formatting/extensions/html/string.rb +6 -7
  10. data/lib/ronin/formatting/extensions/sql/string.rb +34 -0
  11. data/lib/ronin/formatting/extensions/text/string.rb +0 -180
  12. data/lib/ronin/fuzzing.rb +21 -0
  13. data/lib/ronin/fuzzing/extensions.rb +20 -0
  14. data/lib/ronin/fuzzing/extensions/string.rb +380 -0
  15. data/lib/ronin/fuzzing/fuzzing.rb +191 -0
  16. data/lib/ronin/network/esmtp.rb +94 -1
  17. data/lib/ronin/network/extensions/esmtp/net.rb +2 -82
  18. data/lib/ronin/network/extensions/http/net.rb +1 -736
  19. data/lib/ronin/network/extensions/imap/net.rb +1 -103
  20. data/lib/ronin/network/extensions/pop3/net.rb +1 -71
  21. data/lib/ronin/network/extensions/smtp/net.rb +2 -157
  22. data/lib/ronin/network/extensions/ssl/net.rb +1 -132
  23. data/lib/ronin/network/extensions/tcp/net.rb +2 -296
  24. data/lib/ronin/network/extensions/telnet/net.rb +1 -135
  25. data/lib/ronin/network/extensions/udp/net.rb +2 -214
  26. data/lib/ronin/network/http/http.rb +750 -5
  27. data/lib/ronin/network/imap.rb +105 -2
  28. data/lib/ronin/network/mixins.rb +1 -1
  29. data/lib/ronin/network/mixins/esmtp.rb +49 -52
  30. data/lib/ronin/network/mixins/http.rb +49 -53
  31. data/lib/ronin/network/mixins/imap.rb +47 -44
  32. data/lib/ronin/network/mixins/mixin.rb +58 -0
  33. data/lib/ronin/network/mixins/pop3.rb +44 -38
  34. data/lib/ronin/network/mixins/smtp.rb +49 -51
  35. data/lib/ronin/network/mixins/tcp.rb +56 -69
  36. data/lib/ronin/network/mixins/telnet.rb +57 -50
  37. data/lib/ronin/network/mixins/udp.rb +48 -52
  38. data/lib/ronin/network/network.rb +1 -0
  39. data/lib/ronin/network/pop3.rb +72 -2
  40. data/lib/ronin/network/smtp/email.rb +1 -0
  41. data/lib/ronin/network/smtp/smtp.rb +159 -3
  42. data/lib/ronin/network/ssl.rb +131 -2
  43. data/lib/ronin/network/tcp.rb +306 -1
  44. data/lib/ronin/network/telnet.rb +136 -2
  45. data/lib/ronin/network/udp.rb +229 -1
  46. data/lib/ronin/support.rb +2 -3
  47. data/lib/ronin/support/support.rb +38 -0
  48. data/lib/ronin/support/version.rb +1 -1
  49. data/lib/ronin/templates/erb.rb +2 -1
  50. data/lib/ronin/ui/output/helpers.rb +35 -1
  51. data/lib/ronin/ui/shell.rb +12 -2
  52. data/lib/ronin/wordlist.rb +157 -0
  53. data/spec/extensions/regexp_spec.rb +38 -0
  54. data/spec/formatting/html/string_spec.rb +1 -1
  55. data/spec/formatting/sql/string_spec.rb +23 -3
  56. data/spec/formatting/text/string_spec.rb +0 -110
  57. data/spec/fuzzing/string_spec.rb +158 -0
  58. data/spec/wordlist_spec.rb +65 -0
  59. metadata +35 -27
@@ -0,0 +1,21 @@
1
+ #
2
+ # Copyright (c) 2006-2011 Hal Brodigan (postmodern.mod3 at gmail.com)
3
+ #
4
+ # This file is part of Ronin Support.
5
+ #
6
+ # Ronin Support is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Ronin Support 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 Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with Ronin Support. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ require 'ronin/fuzzing/extensions'
21
+ require 'ronin/fuzzing/fuzzing'
@@ -0,0 +1,20 @@
1
+ #
2
+ # Copyright (c) 2006-2011 Hal Brodigan (postmodern.mod3 at gmail.com)
3
+ #
4
+ # This file is part of Ronin Support.
5
+ #
6
+ # Ronin Support is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Ronin Support 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 Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with Ronin Support. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ require 'ronin/fuzzing/extensions/string'
@@ -0,0 +1,380 @@
1
+ #
2
+ # Copyright (c) 2006-2011 Hal Brodigan (postmodern.mod3 at gmail.com)
3
+ #
4
+ # This file is part of Ronin Support.
5
+ #
6
+ # Ronin Support is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Ronin Support 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 Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with Ronin Support. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ require 'ronin/extensions/regexp'
21
+ require 'ronin/fuzzing/fuzzing'
22
+
23
+ require 'combinatorics/generator'
24
+ require 'combinatorics/list_comprehension'
25
+ require 'combinatorics/power_set'
26
+ require 'chars'
27
+
28
+ class String
29
+
30
+ #
31
+ # Generate permutations of Strings from a format template.
32
+ #
33
+ # @param [Array(<String,Symbol,Enumerable>, <Integer,Array,Range>)] template
34
+ # The template which defines the string or character sets which will
35
+ # make up parts of the String.
36
+ #
37
+ # @yield [string]
38
+ # The given block will be passed each unique String.
39
+ #
40
+ # @yieldparam [String] string
41
+ # A newly generated String.
42
+ #
43
+ # @return [Enumerator]
44
+ # If no block is given, an Enumerator will be returned.
45
+ #
46
+ # @raise [ArgumentError]
47
+ # A given character set name was unknown.
48
+ #
49
+ # @raise [TypeError]
50
+ # A given string set was not a String, Symbol or Enumerable.
51
+ # A given string set length was not an Integer or Enumerable.
52
+ #
53
+ # @example Generate Strings with ranges of repeating sub-strings.
54
+ #
55
+ # @example Generate Strings with three alpha chars and one numeric chars.
56
+ # String.generate([:alpha, 3], :numeric) do |password|
57
+ # puts password
58
+ # end
59
+ #
60
+ # @example Generate Strings with two to four alpha chars.
61
+ # String.generate([:alpha, 2..4]) do |password|
62
+ # puts password
63
+ # end
64
+ #
65
+ # @example Generate Strings using alpha and punctuation chars.
66
+ # String.generate([Chars.alpha + Chars.punctuation, 4]) do |password|
67
+ # puts password
68
+ # end
69
+ #
70
+ # @example Generate Strings from a custom char set.
71
+ # String.generate([['a', 'b', 'c'], 3], [['1', '2', '3'], 3]) do |password|
72
+ # puts password
73
+ # end
74
+ #
75
+ # @example Generate Strings containing known Strings.
76
+ # String.generate("rock", [:numeric, 4]) do |password|
77
+ # puts password
78
+ # end
79
+ #
80
+ # @example Generate Strings with ranges of repeating sub-strings.
81
+ # String.generate(['/AA', (1..100).step(5)]) do |path|
82
+ # puts path
83
+ # end
84
+ #
85
+ # @since 0.3.0
86
+ #
87
+ # @api public
88
+ #
89
+ def self.generate(*template)
90
+ return enum_for(:generate,*template) unless block_given?
91
+
92
+ sets = []
93
+
94
+ template.each do |pattern|
95
+ set, length = pattern
96
+ set = case set
97
+ when String
98
+ [set].each
99
+ when Symbol
100
+ name = set.to_s.upcase
101
+
102
+ unless Chars.const_defined?(name)
103
+ raise(ArgumentError,"unknown charset #{set.inspect}")
104
+ end
105
+
106
+ Chars.const_get(name).each_char
107
+ when Enumerable
108
+ set
109
+ else
110
+ raise(TypeError,"set must be a String, Symbol or Enumerable")
111
+ end
112
+
113
+ case length
114
+ when Integer
115
+ length.times { sets << set.dup }
116
+ when Array, Range
117
+ sets << Combinatorics::Generator.new do |g|
118
+ length.each do |sublength|
119
+ superset = Array.new(sublength) { set.dup }
120
+
121
+ superset.comprehension { |strings| g.yield strings.join }
122
+ end
123
+ end
124
+ when nil
125
+ sets << set
126
+ else
127
+ raise(TypeError,"length must be an Integer, Range or Array")
128
+ end
129
+ end
130
+
131
+ sets.comprehension do |strings|
132
+ new_string = ''
133
+
134
+ strings.each do |string|
135
+ new_string << case string
136
+ when Integer
137
+ string.chr
138
+ else
139
+ string.to_s
140
+ end
141
+ end
142
+
143
+ yield new_string
144
+ end
145
+ return nil
146
+ end
147
+
148
+ #
149
+ # Repeats the String.
150
+ #
151
+ # @param [Enumerable, Integer] n
152
+ # The number of times to repeat the String.
153
+ #
154
+ # @yield [repeated]
155
+ # The given block will be passed every repeated String.
156
+ #
157
+ # @yieldparam [String] repeated
158
+ # A repeated version of the String.
159
+ #
160
+ # @return [Enumerator]
161
+ # If no block is given, an Enumerator will be returned.
162
+ #
163
+ # @raise [TypeError]
164
+ # `n` must either be Enumerable or an Integer.
165
+ #
166
+ # @example
167
+ # 'A'.repeating(100)
168
+ # # => "AAAAAAAAAAAAA..."
169
+ #
170
+ # @example Generates 100 upto 700 `A`s, increasing by 100 at a time:
171
+ # 'A'.repeating((100..700).step(100)) do |str|
172
+ # # ...
173
+ # end
174
+ #
175
+ # @example Generates 128, 1024, 65536 `A`s:
176
+ # 'A'.repeating([128, 1024, 65536]) do |str|
177
+ # # ...
178
+ # end
179
+ #
180
+ # @api public
181
+ #
182
+ # @since 0.4.0
183
+ #
184
+ def repeating(n)
185
+ if n.kind_of?(Integer)
186
+ # if n is an Integer, simply multiply the String and return
187
+ repeated = (self * n)
188
+
189
+ yield repeated if block_given?
190
+ return repeated
191
+ end
192
+
193
+ return enum_for(:repeating,n) unless block_given?
194
+
195
+ unless n.kind_of?(Enumerable)
196
+ raise(TypeError,"argument must be Enumerable or an Integer")
197
+ end
198
+
199
+ n.each do |length|
200
+ yield(self * length)
201
+ end
202
+
203
+ return self
204
+ end
205
+
206
+ #
207
+ # Incrementally fuzzes the String.
208
+ #
209
+ # @param [Hash{Regexp,String => #each}] substitutions
210
+ # Patterns and their substitutions.
211
+ #
212
+ # @yield [fuzz]
213
+ # The given block will be passed every fuzzed String.
214
+ #
215
+ # @yieldparam [String] fuzz
216
+ # A fuzzed String.
217
+ #
218
+ # @return [Enumerator]
219
+ # If no block is given, an Enumerator will be returned.
220
+ #
221
+ # @example Replace every `e`, `i`, `o`, `u` with `(`, 100 `A`s and a `\0`:
222
+ # "the quick brown fox".fuzz(/[eiou]/ => ['(', ('A' * 100), "\0"]) do |str|
223
+ # p str
224
+ # end
225
+ #
226
+ # @example {String.generate} with {String#fuzz}:
227
+ # "GET /".fuzz('/' => String.generate(['A', 1..100])) do |str|
228
+ # p str
229
+ # end
230
+ #
231
+ # @since 0.3.0
232
+ #
233
+ # @api public
234
+ #
235
+ def fuzz(substitutions={})
236
+ return enum_for(:fuzz,substitutions) unless block_given?
237
+
238
+ substitutions.each do |pattern,substitution|
239
+ pattern = case pattern
240
+ when Regexp
241
+ pattern
242
+ when String
243
+ Regexp.new(Regexp.escape(pattern))
244
+ when Symbol
245
+ Regexp.const_get(pattern.to_s.upcase)
246
+ else
247
+ raise(TypeError,"cannot convert #{pattern.inspect} to a Regexp")
248
+ end
249
+
250
+ substitution = case substitution
251
+ when Enumerable
252
+ substitution
253
+ when Symbol
254
+ Ronin::Fuzzing[substitution]
255
+ else
256
+ raise(TypeError,"substitutions must be Enumerable or a Symbol")
257
+ end
258
+
259
+ scanner = StringScanner.new(self)
260
+ indices = []
261
+
262
+ while scanner.scan_until(pattern)
263
+ indices << [scanner.pos - scanner.matched_size, scanner.matched_size]
264
+ end
265
+
266
+ indices.each do |index,length|
267
+ substitution.each do |substitute|
268
+ substitute = case substitute
269
+ when Proc
270
+ substitute.call(self[index,length])
271
+ when Integer
272
+ substitute.chr
273
+ else
274
+ substitute.to_s
275
+ end
276
+
277
+ fuzzed = dup
278
+ fuzzed[index,length] = substitute
279
+ yield fuzzed
280
+ end
281
+ end
282
+ end
283
+ end
284
+
285
+ #
286
+ # Permutes over every possible mutation of the String.
287
+ #
288
+ # @param [Hash{Regexp,String,Symbol => Symbol,#each}] mutations
289
+ # The patterns and substitutions to mutate the String with.
290
+ #
291
+ # @yield [mutant]
292
+ # The given block will be yielded every possible mutant String.
293
+ #
294
+ # @yieldparam [String] mutant
295
+ # A mutated String.
296
+ #
297
+ # @return [Enumerator]
298
+ # If no block is given, an Enumerator will be returned.
299
+ #
300
+ # @example
301
+ # "hello old dog".mutate('e' => ['3'], 'l' => ['1'], 'o' => ['0']) do |str|
302
+ # puts str
303
+ # end
304
+ #
305
+ # @since 0.4.0
306
+ #
307
+ # @api public
308
+ #
309
+ def mutate(mutations={})
310
+ return enum_for(:mutate,mutations) unless block_given?
311
+
312
+ matches = Set[]
313
+
314
+ mutations.each do |pattern,mutation|
315
+ pattern = case pattern
316
+ when Regexp
317
+ pattern
318
+ when String
319
+ Regexp.new(Regexp.escape(pattern))
320
+ when Symbol
321
+ Regexp.const_get(pattern.to_s.upcase)
322
+ else
323
+ raise(TypeError,"cannot convert #{pattern.inspect} to a Regexp")
324
+ end
325
+
326
+ scanner = StringScanner.new(self)
327
+
328
+ while scanner.scan_until(pattern)
329
+ length = scanner.matched_size
330
+ index = scanner.pos - length
331
+ original = scanner.matched
332
+
333
+ mutator = Combinatorics::Generator.new do |g|
334
+ mutation.each do |mutate|
335
+ g.yield case mutate
336
+ when Proc
337
+ mutate.call(original)
338
+ when Integer
339
+ mutate.chr
340
+ else
341
+ mutate.to_s
342
+ end
343
+ end
344
+ end
345
+
346
+ matches << [index, length, mutator]
347
+ end
348
+ end
349
+
350
+ matches.powerset do |submatches|
351
+ # ignore the empty Set
352
+ next if submatches.empty?
353
+
354
+ # sort the submatches by index
355
+ submatches = submatches.sort_by { |index,length,mutator| index }
356
+ sets = []
357
+ prev_index = 0
358
+
359
+ submatches.each do |index,length,mutator|
360
+ # add the previous substring to the set of Strings
361
+ if index > prev_index
362
+ sets << [self[prev_index,index - prev_index]]
363
+ end
364
+
365
+ # add the mutator to the set of Strings
366
+ sets << mutator
367
+
368
+ prev_index = index + length
369
+ end
370
+
371
+ # add the remaining substring to the set of Strings
372
+ if prev_index < self.length
373
+ sets << [self[prev_index..-1]]
374
+ end
375
+
376
+ sets.comprehension { |strings| yield strings.join }
377
+ end
378
+ end
379
+
380
+ end
@@ -0,0 +1,191 @@
1
+ #
2
+ # Copyright (c) 2006-2011 Hal Brodigan (postmodern.mod3 at gmail.com)
3
+ #
4
+ # This file is part of Ronin Support.
5
+ #
6
+ # Ronin Support is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Ronin Support 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 Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with Ronin Support. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ require 'set'
21
+
22
+ module Ronin
23
+ module Fuzzing
24
+ SHORT_LENGTHS = SortedSet[1, 100, 500, 1_000, 10_000]
25
+
26
+ LONG_LENGTHS = SortedSet[
27
+ 128, 255, 256, 257, 511, 512, 513, 1023, 1024, 2048, 2049, 4095,
28
+ 4096, 4097, 5_000, 10_000, 20_000, 32762, 32763, 32764, 32765, 32766,
29
+ 32767, 32768, 32769,
30
+ 0xffff-2, 0xffff-1, 0xffff, 0xffff+1, 0xffff+2,
31
+ 99_999, 100_000, 500_000, 1_000_000
32
+ ]
33
+
34
+ # Null bytes in various encodings
35
+ NULL_BYTES = ['%00', '%u0000', "\x00"]
36
+
37
+ # Newline characters
38
+ NEW_LINES = ["\n", "\r", "\n\r"]
39
+
40
+ # Format String flags
41
+ FORMAT_STRINGS = ['%p', '%s', '%n']
42
+
43
+ #
44
+ # Returns a fuzzer method.
45
+ #
46
+ # @param [Symbol] name
47
+ # The name of the fuzzer to return.
48
+ #
49
+ # @return [Enumerator]
50
+ # An Enumerator for the fuzzer method.
51
+ #
52
+ # @api semipublic
53
+ #
54
+ # @since 0.4.0
55
+ #
56
+ def self.[](name)
57
+ if (!Object.respond_to?(name) && respond_to?(name))
58
+ enum_for(name)
59
+ end
60
+ end
61
+
62
+ def self.bad_strings(&block)
63
+ yield ''
64
+
65
+ chars = [
66
+ 'A', 'a', '1', '<', '>', '"', "'", '/', "\\", '?', '=', 'a=', '&',
67
+ '.', ',', '(', ')', ']', '[', '%', '*', '-', '+', '{', '}',
68
+ "\x14", "\xfe", "\xff"
69
+ ]
70
+
71
+ chars.each do |c|
72
+ LONG_LENGTHS.each { |length| yield c * length }
73
+ end
74
+
75
+ yield '!@#$%%^#$%#$@#$%$$@#$%^^**(()'
76
+ yield '%01%02%03%04%0a%0d%0aADSF'
77
+ yield '%01%02%03@%04%0a%0d%0aADSF'
78
+
79
+ NULL_BYTES.each do |c|
80
+ SHORT_LENGTHS.each { |length| yield c * length }
81
+ end
82
+
83
+ yield "%\xfe\xf0%\x00\xff"
84
+ yield "%\xfe\xf0%\x00\xff" * 20
85
+
86
+ SHORT_LENGTHS.each do |length|
87
+ yield "\xde\xad\xbe\xef" * length
88
+ end
89
+
90
+ yield "\n\r" * 100
91
+ yield "<>" * 500
92
+ end
93
+
94
+ def self.format_strings(&block)
95
+ FORMAT_STRINGS.each do |fmt|
96
+ yield fmt
97
+ yield fmt * 100
98
+ yield fmt * 500
99
+ yield "\"#{fmt}\"" * 500
100
+ end
101
+ end
102
+
103
+ def self.bad_paths(&block)
104
+ padding = 'A' * 5_000
105
+
106
+ yield "/.:/#{padding}\x00\x00"
107
+ yield "/.../#{padding}\x00\x00"
108
+
109
+ yield "\\\\*"
110
+ yield "\\\\?\\"
111
+
112
+ yield "/\\" * 5_000
113
+ yield '/.' * 5_000
114
+
115
+ NULL_BYTES.each do |c|
116
+ if c.start_with?('%')
117
+ yield "#{c}/"
118
+ yield "/#{c}"
119
+ yield "/#{c}/"
120
+ end
121
+ end
122
+ end
123
+
124
+ def self.bit_fields(&block)
125
+ ("\x00".."\xff").each do |c|
126
+ yield c
127
+ yield c << c # x2
128
+ yield c << c # x4
129
+ yield c << c # x8
130
+ end
131
+ end
132
+
133
+ def self.signed_bit_fields(&block)
134
+ ("\x80".."\xff").each do |c|
135
+ yield c
136
+ yield c << c # x2
137
+ yield c << c # x4
138
+ yield c << c # x8
139
+ end
140
+ end
141
+
142
+ def self.uint8(&block)
143
+ ("\x00".."\xff").each(&block)
144
+ end
145
+
146
+ def self.uint16
147
+ uint8 { |c| yield c * 2 }
148
+ end
149
+
150
+ def self.uint32
151
+ uint8 { |c| yield c * 4 }
152
+ end
153
+
154
+ def self.uint64
155
+ uint8 { |c| yield c * 8 }
156
+ end
157
+
158
+ def self.int8(&block)
159
+ ("\x00".."\x70").each(&block)
160
+ end
161
+
162
+ def self.int16
163
+ int8 { |c| yield c * 2 }
164
+ end
165
+
166
+ def self.int32
167
+ int8 { |c| yield c * 4 }
168
+ end
169
+
170
+ def self.int64
171
+ int8 { |c| yield c * 8 }
172
+ end
173
+
174
+ def self.sint8(&block)
175
+ ("\x80".."\xff").each(&block)
176
+ end
177
+
178
+ def self.sint16
179
+ sint8 { |c| yield c * 2 }
180
+ end
181
+
182
+ def self.sint32
183
+ sint8 { |c| yield c * 4 }
184
+ end
185
+
186
+ def self.sint64
187
+ sint8 { |c| yield c * 8 }
188
+ end
189
+
190
+ end
191
+ end