Ticket #13: tarantula_fuzzers.patch.txt

File tarantula_fuzzers.patch.txt, 12.3 kB (added by someone23, 5 months ago)

improve tarantula fuzzing ability

Line 
1 diff -Naru --exclude=.svn --exclude='*~' tarantula.orig/lib/relevance/tarantula/crawler.rb tarantula.xss_check/lib/relevance/tarantula/crawler.rb
2 --- tarantula.orig/lib/relevance/tarantula/crawler.rb   2008-05-04 15:09:03.000000000 -0400
3 +++ tarantula.xss_check/lib/relevance/tarantula/crawler.rb      2008-05-04 16:25:18.000000000 -0400
4 @@ -7,7 +7,8 @@
5    
6    attr_accessor :proxy, :handlers, :skip_uri_patterns, :log_grabber,
7                  :reporters, :links_to_crawl, :links_queued, :forms_to_crawl,
8 -                :form_signatures_queued, :max_url_length, :response_code_handler
9 +                :form_signatures_queued, :max_url_length, :response_code_handler,
10 +                :times_to_crawl, :fuzzers
11    attr_reader   :transform_url_patterns, :referrers, :failures, :successes
12    
13    def initialize
14 @@ -30,7 +31,8 @@
15      ]
16      @reporters = [Relevance::Tarantula::IOReporter.new($stderr)]
17      @decoder = HTMLEntities.new
18 -   
19 +    @times_to_crawl = 1
20 +    @fuzzers = [Relevance::Tarantula::FormSubmission]
21    end
22    
23    def method_missing(meth, *args)
24 @@ -45,8 +47,18 @@
25    end
26    
27    def crawl(url = "/")
28 -    queue_link url
29 -    do_crawl
30 +    @times_to_crawl.times do |i|
31 +      queue_link url
32 +      do_crawl
33 +     
34 +      puts "#{(i+1).ordinalize} crawl" if @times_to_crawl > 1
35 +     
36 +      if i + 1 < @times_to_crawl
37 +        @links_queued = Set.new
38 +        @form_signatures_queued = Set.new
39 +        @referrers = {}
40 +      end
41 +    end
42    rescue Interrupt
43      $stderr.puts "CTRL-C"
44    ensure
45 @@ -165,12 +177,16 @@
46    end
47    
48    def queue_form(form, referrer = nil)
49 -    fs = FormSubmission.new(Form.new(form))
50 -    fs.action = transform_url(fs.action)
51 -    return if should_skip_form_submission?(fs)
52 -    @referrers[fs.action] = referrer if referrer
53 -    @forms_to_crawl << fs
54 -    @form_signatures_queued << fs.signature
55 +    fuzzers.each do |fuzzer|
56 +      fuzzer.mutate(Form.new(form)).each do |fs|
57 +        # fs = fuzzer.new(Form.new(form))
58 +        fs.action = transform_url(fs.action)
59 +        return if should_skip_form_submission?(fs)
60 +        @referrers[fs.action] = referrer if referrer
61 +        @forms_to_crawl << fs
62 +        @form_signatures_queued << fs.signature
63 +      end
64 +    end
65    end
66    
67    def report_dir
68 diff -Naru --exclude=.svn --exclude='*~' tarantula.orig/lib/relevance/tarantula/form_submission.rb tarantula.xss_check/lib/relevance/tarantula/form_submission.rb
69 --- tarantula.orig/lib/relevance/tarantula/form_submission.rb   2008-05-04 15:08:57.000000000 -0400
70 +++ tarantula.xss_check/lib/relevance/tarantula/form_submission.rb      2008-05-04 14:22:35.000000000 -0400
71 @@ -6,6 +6,10 @@
72      @data = mutate_selects(form).merge(mutate_text_areas(form)).merge(mutate_inputs(form))
73    end
74    
75 +  def self.mutate(form)
76 +    [self.new(form)]
77 +  end
78
79    def to_s
80      "#{action} #{method} #{data.inspect}"
81    end
82 diff -Naru --exclude=.svn --exclude='*~' tarantula.orig/lib/relevance/tarantula/html_report_helper.rb tarantula.xss_check/lib/relevance/tarantula/html_report_helper.rb
83 --- tarantula.orig/lib/relevance/tarantula/html_report_helper.rb        2008-05-03 18:49:16.000000000 -0400
84 +++ tarantula.xss_check/lib/relevance/tarantula/html_report_helper.rb   2008-05-03 19:33:46.000000000 -0400
85 @@ -1,4 +1,6 @@
86 +require "erb"
87  module Relevance::Tarantula::HtmlReportHelper
88 +  include ERB::Util
89    include Relevance::Tarantula
90    def wrap_in_line_number_table(text, &blk)
91      x = Builder::XmlMarkup.new
92 @@ -43,12 +45,12 @@
93    
94    def wrap_stack_trace_line(text)
95      if text =~ %r{^\s*(/[^:]+):(\d+):([^:]+)$}
96 -      file = $1.to_s_xss_protected
97 +      file = h($1) # .to_s_xss_protected
98        line_number = $2
99 -      message = $3.to_s_xss_protected
100 -      "<a href='#{textmate_url(file, line_number)}'>#{file}:#{line_number}</a>:#{message}".mark_as_xss_protected
101 +      message = h($3) # .to_s_xss_protected
102 +      "<a href='#{textmate_url(file, line_number)}'>#{file}:#{line_number}</a>:#{message}" # .mark_as_xss_protected
103      else
104 -      text.to_s_xss_protected
105 +      h(text) # .to_s_xss_protected
106      end
107    end
108  end
109 diff -Naru --exclude=.svn --exclude='*~' tarantula.orig/lib/relevance/tarantula/xss_document_checker_handler.rb tarantula.xss_check/lib/relevance/tarantula/xss_document_checker_handler.rb
110 --- tarantula.orig/lib/relevance/tarantula/xss_document_checker_handler.rb      1969-12-31 19:00:00.000000000 -0500
111 +++ tarantula.xss_check/lib/relevance/tarantula/xss_document_checker_handler.rb 2008-05-04 20:46:50.000000000 -0400
112 @@ -0,0 +1,35 @@
113 +require 'hpricot'
114 +
115 +class Relevance::Tarantula::XssDocumentCheckerHandler
116
117 +  def initialize(attacks)
118 +    @attacks = attacks
119 +    @regexp = '(' + attacks.map {|a| Regexp.escape a['code']}.join('|') + ')'
120 +  end
121
122 +  def handle(result)
123 +    response = result.response
124 +    return unless response.html?
125 +    if n = (response.body =~ /#{@regexp}/)
126 +      error_result = result.dup
127 +      error_result.success = false
128 +      error_result.description = "XSS error found, match was: #{$1}"
129 +      error_result.data = <<-STR
130 +        ########################################################################
131 +        # Text around unescaped string: #{$1}
132 +        ########################################################################
133 +        #{response.body[[0, n - 200].max , 400]}
134 +       
135 +       
136 +       
137 +       
138 +       
139 +        ########################################################################
140 +        # Attack information:
141 +        ########################################################################
142 +        #{@attacks.select {|a| a['code'] == $1}[0].to_yaml}
143 +      STR
144 +      error_result
145 +    end
146 +  end
147 +end
148 diff -Naru --exclude=.svn --exclude='*~' tarantula.orig/lib/relevance/tarantula/xss_form_submission.rb tarantula.xss_check/lib/relevance/tarantula/xss_form_submission.rb
149 --- tarantula.orig/lib/relevance/tarantula/xss_form_submission.rb       1969-12-31 19:00:00.000000000 -0500
150 +++ tarantula.xss_check/lib/relevance/tarantula/xss_form_submission.rb  2008-05-04 21:38:31.000000000 -0400
151 @@ -0,0 +1,60 @@
152 +class Relevance::Tarantula::XssFormSubmission
153 +  attr_accessor :method, :action, :data, :attack
154
155 +  cattr_accessor :attacks
156
157 +  def initialize(form, attack = nil)
158 +    @method = form.method
159 +    @action = form.action
160 +    @attack = attack
161 +    @data = mutate_selects(form).merge(mutate_text_areas(form)).merge(mutate_inputs(form))
162 +  end
163
164 +  def self.mutate(form)
165 +    attacks and attacks.map do |attack|
166 +      self.new(form, attack)
167 +    end
168 +  end
169
170 +  def to_s
171 +    "#{action} #{method} #{data.inspect} #{attack.inspect}"
172 +  end
173
174 +  # a form's signature is what makes it unique (e.g. action + fields)
175 +  # used to keep track of which forms we have submitted already
176 +  def signature
177 +    [action, data.keys.sort, attack['name']]
178 +  end
179
180 +  def create_random_data_for(form, tag_selector)
181 +    form.search(tag_selector).inject({}) do |form_args, input|
182 +      # TODO: test
183 +      form_args[input['name']] = random_data(input) if input['name']
184 +      form_args
185 +    end
186 +  end
187 +
188 +  def mutate_inputs(form)
189 +    create_random_data_for(form, 'input')
190 +  end
191 +
192 +  def mutate_text_areas(form)
193 +    create_random_data_for(form, 'textarea')
194 +  end
195
196 +  def mutate_selects(form)
197 +    form.search('select').inject({}) do |form_args, select|
198 +      options = select.search('option')
199 +      option = options.rand
200 +      form_args[select['name']] = option['value']
201 +      form_args
202 +    end
203 +  end
204
205 +  def random_data(input)
206 +    case input['name']
207 +      when /^_method$/      : input['value']
208 +      else                    attack['code']
209 +    end
210 +  end
211 +end
212 diff -Naru --exclude=.svn --exclude='*~' tarantula.orig/lib/relevance/tarantula.rb tarantula.xss_check/lib/relevance/tarantula.rb
213 --- tarantula.orig/lib/relevance/tarantula.rb   2008-05-04 15:09:03.000000000 -0400
214 +++ tarantula.xss_check/lib/relevance/tarantula.rb      2008-05-04 21:02:28.000000000 -0400
215 @@ -9,9 +9,9 @@
216  gem 'actionpack'
217  require 'active_support'
218  require 'action_controller'
219 -xss_shield_path = File.join(TARANTULA_ROOT, %w{vendor xss-shield})
220 -$: << File.join(xss_shield_path, "lib")
221 -require File.join(xss_shield_path, "init")
222 +#xss_shield_path = File.join(TARANTULA_ROOT, %w{vendor xss-shield})
223 +#$: << File.join(xss_shield_path, "lib")
224 +#require File.join(xss_shield_path, "init")
225  
226  gem 'facets'
227  gem 'htmlentities'
228 @@ -57,5 +57,7 @@
229  require 'relevance/tarantula/crawler'
230  require 'relevance/tarantula/form'
231  require 'relevance/tarantula/form_submission'
232 +require 'relevance/tarantula/xss_form_submission'
233 +require 'relevance/tarantula/xss_document_checker_handler'
234  
235  require 'relevance/tarantula/tidy_handler' if ENV['TIDY_PATH']
236 diff -Naru --exclude=.svn --exclude='*~' tarantula.orig/test/relevance/tarantula/xss_document_checker_handler_test.rb tarantula.xss_check/test/relevance/tarantula/xss_document_checker_handler_test.rb
237 --- tarantula.orig/test/relevance/tarantula/xss_document_checker_handler_test.rb        1969-12-31 19:00:00.000000000 -0500
238 +++ tarantula.xss_check/test/relevance/tarantula/xss_document_checker_handler_test.rb   2008-05-04 21:39:32.000000000 -0400
239 @@ -0,0 +1,14 @@
240 +require File.join(File.dirname(__FILE__), "..", "..", "test_helper.rb")
241 +include Relevance::Tarantula
242 +
243 +describe "Relevance::Tarantula::XssDocumentCheckerHandler" do
244 +  before do
245 +    @handler = Relevance::Tarantula::XssDocumentCheckerHandler.new([{'name' => 'foo_name', 'code' => 'foo_code', 'desc' => 'foo_desc'}])
246 +  end
247
248 +  it "detects the supplied code" do
249 +    # @handler.expects(:queue_link).never
250 +    result = @handler.handle(Result.new(:response => stub(:html? => true, :body => '<a href="/foo">foo_code</a>')))
251 +    result.success.should == false
252 +  end
253 +end
254 diff -Naru --exclude=.svn --exclude='*~' tarantula.orig/test/relevance/tarantula/xss_form_submission_test.rb tarantula.xss_check/test/relevance/tarantula/xss_form_submission_test.rb
255 --- tarantula.orig/test/relevance/tarantula/xss_form_submission_test.rb 1969-12-31 19:00:00.000000000 -0500
256 +++ tarantula.xss_check/test/relevance/tarantula/xss_form_submission_test.rb    2008-05-04 21:39:17.000000000 -0400
257 @@ -0,0 +1,74 @@
258 +require File.join(File.dirname(__FILE__), "..", "..", "test_helper.rb")
259 +
260 +describe "Relevance::Tarantula::XssFormSubmission" do
261
262 +  # TODO: add more from field types to this example form as needed
263 +  before do
264 +    @tag = Hpricot(<<END)
265 +<form action="/session" method="post">
266 +  <input id="email" name="email" size="30" type="text" />
267 +  <textarea id="comment" name="comment"value="1" />
268 +  <input name="commit" type="submit" value="Postit" />
269 +  <input name="secret" type="hidden" value="secret" />
270 +  <select id="foo_opened_on_1i" name="foo[opened_on(1i)]">
271 +    <option value="2003">2003</option>
272 +    <option value="2004">2004</option>
273 +  </select>
274 +</form>
275 +END
276 +    @form = Relevance::Tarantula::Form.new(@tag.at('form'))
277 +    @fs = Relevance::Tarantula::XssFormSubmission.new(@form, {'name' => 'foo_name', 'code' => 'foo_code', 'desc' => 'foo_desc'})
278 +  end
279
280 +  it "can mutate text areas" do
281 +    @fs.mutate_text_areas(@form).should == {"comment" => "foo_code"}
282 +  end
283
284 +  it "can mutate selects" do
285 +    Hpricot::Elements.any_instance.stubs(:rand).returns(stub(:[] => "2006-stub"))
286 +    @fs.mutate_selects(@form).should == {"foo[opened_on(1i)]" => "2006-stub"}
287 +  end
288
289 +  it "can mutate inputs" do
290 +    @fs.mutate_inputs(@form).should == {"commit"=>"foo_code", "secret"=>"foo_code", "email"=>"foo_code"}
291 +  end
292 +
293 +  it "has a signature based on action,  fields, and attack name" do
294 +    @fs.signature.should == ['/session', [
295 +      "comment",
296 +      "commit",
297 +      "email",
298 +      "foo[opened_on(1i)]",
299 +      "secret"],
300 +      "foo_name"
301 +    ]
302 +  end
303
304 +  it "has a friendly to_s" do
305 +    @fs.to_s.should =~ %r{^/session post}
306 +  end
307
308 +  it "processes all its attacks" do
309 +    Relevance::Tarantula::XssFormSubmission.attacks = [
310 +      {'name' => 'foo_name1', 'code1' => 'foo_code1', 'desc' => 'foo_desc1'},
311 +      {'name' => 'foo_name2', 'code2' => 'foo_code2', 'desc' => 'foo_desc2'},
312 +    ]
313 +    Relevance::Tarantula::XssFormSubmission.mutate(@form).size.should == 2
314 +  end
315 +end
316 +
317 +describe "Relevance::Tarantula::XssFormSubmission for a crummy form" do
318 +  before do
319 +    @tag = Hpricot(<<END)
320 +<form action="/session" method="post">
321 +  <input value="no_name" />
322 +</form>
323 +END
324 +    @form = Relevance::Tarantula::Form.new(@tag.at('form'))
325 +    @fs = Relevance::Tarantula::XssFormSubmission.new(@form, {'name' => 'foo_name', 'code' => 'foo_code', 'desc' => 'foo_desc'})
326 +  end
327
328 +  it "ignores unnamed inputs" do
329 +    @fs.mutate_inputs(@form).should == {}
330 +  end
331 +end