Class: Ronin::Fuzzing::Mutator

Inherits:
Object
  • Object
show all
Defined in:
lib/ronin/fuzzing/mutator.rb

Overview

Fuzzer class that permutates over every mutation of a String, given mutation rules.

Constant Summary collapse

PATTERNS =
Support::Text::Patterns

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rules) ⇒ Mutator

Initialize the Mutator.

Parameters:

  • rules (Hash{Regexp,String,Symbol => Symbol,Enumerable})

    The patterns and substitutions to mutate the String with.

Raises:

  • (TypeError)

    A mutation pattern was not a Regexp, String or Symbol. A mutation substitution was not a Symbol or Enumerable.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/ronin/fuzzing/mutator.rb', line 56

def initialize(rules)
  @rules = {}
  
  rules.each do |pattern,mutation|
    pattern = case pattern
              when Regexp
                pattern
              when String
                Regexp.new(Regexp.escape(pattern))
              when Symbol
                PATTERNS.const_get(pattern.upcase)
              else
                raise(TypeError,"cannot convert #{pattern.inspect} to a Regexp")
              end

    mutation = case mutation
               when Enumerable
                 mutation
               when Symbol
                 Ronin::Fuzzing[mutation]
               else
                 raise(TypeError,"mutation #{mutation.inspect} must be a Symbol or Enumerable")
               end

    @rules[pattern] = mutation
  end
end

Instance Attribute Details

#rulesObject (readonly)

Mutation rules



44
45
46
# File 'lib/ronin/fuzzing/mutator.rb', line 44

def rules
  @rules
end

Instance Method Details

#each(string) {|mutant| ... } ⇒ Enumerator

Permutes over every possible mutation of the String.

Parameters:

  • string (String)

    The String to be mutated.

Yields:

  • (mutant)

    The given block will be yielded every possible mutant String.

Yield Parameters:

  • mutant (String)

    A mutated String.

Returns:

  • (Enumerator)

    If no block is given, an Enumerator will be returned.



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/ronin/fuzzing/mutator.rb', line 99

def each(string)
  return enum_for(__method__,string) unless block_given?

  matches = Set[]

  @rules.each do |pattern,mutation|
    scanner = StringScanner.new(string)

    while scanner.scan_until(pattern)
      length   = scanner.matched_size
      index    = scanner.pos - length
      original = scanner.matched

      mutator = Combinatorics::Generator.new do |g|
        mutation.each do |mutate|
          g.yield case mutate
                  when Proc
                    mutate.call(original)
                  when Integer
                    mutate.chr
                  else
                    mutate.to_s
                  end
        end
      end

      matches << [index, length, mutator]
    end
  end

  matches.powerset do |submatches|
    # ignore the empty Set
    next if submatches.empty?

    # sort the submatches by index
    submatches = submatches.sort_by { |index,length,mutator| index }
    sets       = []
    prev_index = 0

    submatches.each do |index,length,mutator|
      # add the previous substring to the set of Strings
      if index > prev_index
        sets << [string[prev_index,index - prev_index]]
      end

      # add the mutator to the set of Strings
      sets << mutator

      prev_index = index + length
    end

    # add the remaining substring to the set of Strings
    if prev_index < string.length
      sets << [string[prev_index..-1]]
    end

    sets.comprehension { |strings| yield strings.join }
  end

  return nil
end