plugins/waf_detector.rb in arachni-0.4.0.4 vs plugins/waf_detector.rb in arachni-0.4.1

- old
+ new

@@ -1,18 +1,21 @@ =begin - Arachni - Copyright (c) 2010-2012 Tasos "Zapotek" Laskos <tasos.laskos@gmail.com> + Copyright 2010-2012 Tasos Laskos <tasos.laskos@gmail.com> - This is free software; you can copy and distribute and modify - this program under the term of the GPL v2.0 License - (See LICENSE file for details) + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. =end -module Arachni -module Plugins - # # Web Application Firewall detection plugin. # # This is a 4 stage process: # 1. Grab the original page as is @@ -21,150 +24,144 @@ # 4. Make heads or tails of the gathered responses # # Steps 1 to 3 will be repeated _precision_ times and the responses will be averaged using rDiff analysis. # # -# @author: Tasos "Zapotek" Laskos -# <tasos.laskos@gmail.com> -# <zapotek@segfault.gr> -# @version: 0.1.1 +# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com> # -class WAFDetector < Arachni::Plugin::Base +# @version 0.1.2 +# +class Arachni::Plugins::WAFDetector < Arachni::Plugin::Base MSG_INCONCLUSIVE = %q{Could not establish a baseline behavior for the website. Due to that fact analysis has been aborted.} - MSG_FOUND = %q{Request parameters are being filtered, this is usually a sign of a WAF.} - MSG_NOT_FOUND = %q{Could not detect any sign of filtering, a WAF doesn't seem to be present.} def prepare - @precision = @options['precision'] + framework.pause + @precision = options['precision'] + bad = [ '../../../../', '<script>foo</script>', '\'--;`', ] names = [] - bad.size.times { - |i| - names << i.to_s + '_' + Digest::SHA2.hexdigest( rand( i*1000 ).to_s ) - } + bad.size.times do |i| + names << i.to_s + '_' + Digest::SHA2.hexdigest( rand( i * 1000 ).to_s ) + end @safe = { } @unsafe = { } - names.each_with_index { - |name, i| - @safe[name] = 'value_' + name - @unsafe[name] = i.to_s + '_' + bad.join( '_' ) - } + names.each.with_index do |name, i| + @safe[name] = 'value_' + name + @unsafe[name] = i.to_s + '_' + bad.join( '_' ) + end - @url = @framework.opts.url + @url = framework.opts.url @responses = { - :original => nil, - :vanilla => nil, - :spicy => nil + original: nil, + vanilla: nil, + spicy: nil } - end def run - print_status( "Starting detection with a precision of #{@precision}." ) + print_status "Starting detection with a precision of #{@precision}." - print_status( "Stage #1: Requesting original page." ) - queue_original( ) + print_status "Stage #1: Requesting original page." + queue_original - print_status( "Stage #2: Requesting with vanilla inputs." ) - queue_vanilla( ) + print_status "Stage #2: Requesting with vanilla inputs." + queue_vanilla - print_status( "Stage #3: Requesting with spicy inputs." ) - queue_spicy( ) + print_status "Stage #3: Requesting with spicy inputs." + queue_spicy - print_status( "Stage #4: Analyzing gathered responses." ) + print_status "Stage #4: Analyzing gathered responses." - @framework.http.after_run { - + http.after_run { if @responses[:original] == @responses[:vanilla] if @responses[:vanilla] == @responses[:spicy] - not_found! + not_found else - found! + found end else - inconclusive! + inconclusive end } - @framework.http.run + + http_run end - def found! - print_ok( MSG_FOUND ) - register_results( { :code => 1, :msg => MSG_FOUND } ) + def clean_up + framework.resume end - def not_found! - print_ok( MSG_NOT_FOUND ) - register_results( { :code => 0, :msg => MSG_NOT_FOUND } ) + def found + print_ok MSG_FOUND + register_results( code: 1, msg: MSG_FOUND ) end - def inconclusive! - print_ok( MSG_INCONCLUSIVE ) - register_results( { :code => -1, :msg => MSG_INCONCLUSIVE } ) + def not_found + print_ok MSG_NOT_FOUND + register_results( code: 0, msg: MSG_NOT_FOUND ) end + def inconclusive + print_ok MSG_INCONCLUSIVE + register_results( code: -1, msg: MSG_INCONCLUSIVE ) + end + def queue_original @precision.times { - @framework.http.get( @url.to_s ).on_complete { - |res| + http.get( @url.to_s ) do |res| @responses[:original] ||= res.body @responses[:original] = @responses[:original].rdiff( res.body ) - } + end } end - def queue_vanilla( ) + def queue_vanilla @precision.times { - @framework.http.get( @url.to_s, :params => @safe ).on_complete { - |res| + http.get( @url.to_s, params: @safe ) do |res| @responses[:vanilla] ||= res.body @responses[:vanilla] = @responses[:vanilla].rdiff( res.body ) - } + end } end - def queue_spicy( ) + def queue_spicy @precision.times { - @framework.http.get( @url.to_s, :params => @unsafe ).on_complete { - |res| + http.get( @url.to_s, params: @unsafe ) do |res| @responses[:spicy] ||= res.body @responses[:spicy] = @responses[:spicy].rdiff( res.body ) - } + end } end def self.info { - :name => 'WAF Detector', - :description => %q{Performs basic profiling on the web application + name: 'WAF Detector', + description: %q{Performs basic profiling on the web application in order to assess the existence of a Web Application Firewall. This is a 4 stage process: 1. Grab the original page as is 2. Send a lot of innocent (vanilla) strings in non-existent inputs so as to profile normal behavior 3. Send a lot of suspicious (spicy) strings in non-existent inputs and check if behavior changes 4. Make heads or tails of the gathered responses Steps 1 to 3 will be repeated _precision_ times (default: 5) and the responses will be averaged using rDiff analysis.}, - :author => 'Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>', - :version => '0.1.1', - :options => [ - Arachni::OptInt.new( 'precision', [ false, 'Stage precision (how many times to perform each detection stage).', 5 ] ) + author: 'Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>', + version: '0.1.2', + options: [ + Options::Int.new( 'precision', [false, 'Stage precision (how many times to perform each detection stage).', 5] ) ] } end -end - -end end