arachni 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a4f1fba6f25f0dd437f9d31c82b3f036d4b87ec9
4
- data.tar.gz: eaa9814da188578b10283e23101525828d42b17a
3
+ metadata.gz: f1ab8801aa396dbd2a6aa10c911a91777b046542
4
+ data.tar.gz: 2251a40388dec9fc771bc8aa51ddc7680bb4f825
5
5
  SHA512:
6
- metadata.gz: a98cde207400471e0ba80cffc9fce6ce46348d43e76c509cbd06f5c7e6b4867f62f9e5382bedaa7b500d731a82428cde04d23db0ea72a4cfceb9087c8fe8062a
7
- data.tar.gz: a66344c76f782b7042f003c0e7b525b5ea173d2f72257d77f9a4673be35280624d4c73a5f874c157b4b66fd5b3eb46a0196480d9b91379639da6cf26e288c045
6
+ metadata.gz: ccf69071cb3b2ddb1d880041979ac24d8d2f0d61662eadae5ad77544cbd226d47aa746e8505022d03b466290bece49410efc61957d0fc3fbd9359e5361d0b198
7
+ data.tar.gz: 8d3f66447ef08172a43b29605b1f611131a0565a06ba70c706ee199d191043ee78c93b1eb8bef80d95e7215950e54a1ad3d650e3d6d440cc9fb5ab2babbb21f1
@@ -1,5 +1,26 @@
1
1
  # ChangeLog
2
2
 
3
+ ## 1.0.2 _(September 13, 2014)_
4
+
5
+ - `UI::Output` -- Updated null output interface with placeholder debugging methods.
6
+ - `Browser`
7
+ - Updated to catch exception when trying to manipulate read-only inputs.
8
+ - `BrowserCluster`
9
+ - Added debugging messages for job processing.
10
+ - `Worker`
11
+ - `#run_job` -- Clear the `@window_responses` cache after each job in
12
+ addition to after each browser re-spawn.
13
+ - `Form`
14
+ - `#audit` -- `:each_mutation` callback now ignores `#mutation_with_original_values`
15
+ and `#mutation_with_sample_values`.
16
+ - Checks
17
+ - Active
18
+ - `xss_dom_inputs` -- Ignore out-of-scope browser pages.
19
+ - `code_injection_php_input_wrapper` -- Cleaned up `:each_mutation` callback.
20
+ - `file_inclusion` -- Cleaned up `:each_mutation` callback.
21
+ - `path_traversal` -- Cleaned up `:each_mutation` callback.
22
+ - `source_code_disclosure` -- Cleaned up `:each_mutation` callback.
23
+
3
24
  ## 1.0.1 _(September 7, 2014)_
4
25
 
5
26
  - `RPC::Server::Dispatcher`
data/Gemfile CHANGED
@@ -21,6 +21,8 @@ end
21
21
 
22
22
  group :prof do
23
23
  gem 'stackprof'
24
+ gem 'sys-proctable'
25
+ gem 'ruby-mass'
24
26
  end
25
27
 
26
28
  gemspec
data/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  <table>
12
12
  <tr>
13
13
  <th>Version</th>
14
- <td>1.0.1</td>
14
+ <td>1.0.2</td>
15
15
  </tr>
16
16
  <tr>
17
17
  <th>Homepage</th>
@@ -7,7 +7,7 @@
7
7
  =end
8
8
 
9
9
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
10
- # @version 0.1.1
10
+ # @version 0.1.2
11
11
  # @see OWASP https://www.owasp.org/index.php/Top_10_2007-Malicious_File_Execution
12
12
  class Arachni::Checks::CodeInjectionPhpInputWrapper < Arachni::Check::Base
13
13
 
@@ -20,10 +20,7 @@ class Arachni::Checks::CodeInjectionPhpInputWrapper < Arachni::Check::Base
20
20
  # Add one more mutation (on the fly) which will include the extension
21
21
  # of the original value (if that value was a filename) after a null byte.
22
22
  each_mutation: proc do |mutation|
23
- next if !mutation.affected_input_value ||
24
- (mutation.is_a?( Arachni::Form ) &&
25
- (mutation.mutation_with_original_values? ||
26
- mutation.mutation_with_sample_values?))
23
+ next if !mutation.affected_input_value
27
24
 
28
25
  # Don't bother if the current element type can't carry nulls.
29
26
  next if !mutation.valid_input_value_data?( "\0" )
@@ -56,7 +53,7 @@ to try and load it.
56
53
  },
57
54
  elements: [ Element::Form, Element::Link, Element::Cookie, Element::Header ],
58
55
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com> ',
59
- version: '0.1.1',
56
+ version: '0.1.2',
60
57
  platforms: [:php],
61
58
 
62
59
  issue: {
@@ -9,7 +9,7 @@
9
9
  # File inclusion check.
10
10
  #
11
11
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
12
- # @version 0.1.2
12
+ # @version 0.1.3
13
13
  #
14
14
  # @see http://cwe.mitre.org/data/definitions/98.html
15
15
  # @see https://www.owasp.org/index.php/PHP_File_Inclusion
@@ -50,10 +50,7 @@ class Arachni::Checks::FileInclusion < Arachni::Check::Base
50
50
  # Add one more mutation (on the fly) which will include the extension
51
51
  # of the original value (if that value was a filename) after a null byte.
52
52
  each_mutation: proc do |mutation|
53
- next if !mutation.affected_input_value ||
54
- (mutation.is_a?( Arachni::Form ) &&
55
- (mutation.mutation_with_original_values? ||
56
- mutation.mutation_with_sample_values?))
53
+ next if !mutation.affected_input_value
57
54
 
58
55
  # Don't bother if the current element type can't carry nulls.
59
56
  next if !mutation.valid_input_value_data?( "\0" )
@@ -105,7 +102,7 @@ content or errors in the HTTP response body.
105
102
  elements: [ Element::Form, Element::Link, Element::Cookie,
106
103
  Element::Header, Element::LinkTemplate ],
107
104
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com> ',
108
- version: '0.1.2',
105
+ version: '0.1.3',
109
106
  platforms: options[:regexp].keys,
110
107
 
111
108
  issue: {
@@ -9,7 +9,7 @@
9
9
  # Path Traversal check.
10
10
  #
11
11
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
12
- # @version 0.4.2
12
+ # @version 0.4.3
13
13
  #
14
14
  # @see http://cwe.mitre.org/data/definitions/22.html
15
15
  # @see http://www.owasp.org/index.php/Path_Traversal
@@ -39,10 +39,7 @@ class Arachni::Checks::PathTraversal < Arachni::Check::Base
39
39
  # Add one more mutation (on the fly) which will include the extension
40
40
  # of the original value (if that value was a filename) after a null byte.
41
41
  each_mutation: proc do |mutation|
42
- next if !mutation.affected_input_value ||
43
- (mutation.is_a?( Arachni::Form ) &&
44
- (mutation.mutation_with_original_values? ||
45
- mutation.mutation_with_sample_values?))
42
+ next if !mutation.affected_input_value
46
43
 
47
44
  # Don't bother if the current element type can't carry nulls.
48
45
  next if !mutation.valid_input_value_data?( "\0" )
@@ -115,7 +112,7 @@ of relevant content in the HTML responses.
115
112
  elements: [ Element::Form, Element::Link, Element::Cookie,
116
113
  Element::Header, Element::LinkTemplate ],
117
114
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com> ',
118
- version: '0.4.2',
115
+ version: '0.4.3',
119
116
  platforms: payloads.keys,
120
117
 
121
118
  issue: {
@@ -12,7 +12,7 @@
12
12
  #
13
13
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
14
14
  #
15
- # @version 0.2
15
+ # @version 0.2.1
16
16
  #
17
17
  # @see http://cwe.mitre.org/data/definitions/540.html
18
18
  class Arachni::Checks::SourceCodeDisclosure < Arachni::Check::Base
@@ -39,10 +39,7 @@ class Arachni::Checks::SourceCodeDisclosure < Arachni::Check::Base
39
39
  # Add one more mutation (on the fly) which will include the extension
40
40
  # of the original value (if that value was a filename) after a null byte.
41
41
  each_mutation: proc do |mutation|
42
- next if !mutation.affected_input_value ||
43
- (mutation.is_a?( Arachni::Form ) &&
44
- (mutation.mutation_with_original_values? ||
45
- mutation.mutation_with_sample_values?))
42
+ next if !mutation.affected_input_value
46
43
 
47
44
  # Don't bother if the current element type can't carry nulls.
48
45
  next if !mutation.valid_input_value_data?( "\0" )
@@ -122,7 +119,7 @@ source code.
122
119
  elements: [ Element::Form, Element::Link, Element::Cookie,
123
120
  Element::Header, Element::LinkTemplate ],
124
121
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
125
- version: '0.2',
122
+ version: '0.2.1',
126
123
  platforms: options[:regexp].keys,
127
124
 
128
125
  issue: {
@@ -7,7 +7,7 @@
7
7
  =end
8
8
 
9
9
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
10
- # @version 0.1
10
+ # @version 0.1.1
11
11
  class Arachni::Checks::XssDomInputs < Arachni::Check::Base
12
12
 
13
13
  INPUTS = Set.new([:input, :textarea])
@@ -41,7 +41,9 @@ class Arachni::Checks::XssDomInputs < Arachni::Check::Base
41
41
  transition = b.fire_event( locator, event, value: self.tag )
42
42
  next if !transition
43
43
 
44
- p = b.to_page
44
+ # Page may be out of scope, some sort of JS redirection.
45
+ next if !(p = b.to_page)
46
+
45
47
  p.dom.transitions << transition
46
48
 
47
49
  check_and_log p
@@ -77,7 +79,7 @@ Injects an HTML element into page text fields, triggers their associated events
77
79
  and inspects the DOM for proof of vulnerability.
78
80
  },
79
81
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
80
- version: '0.1',
82
+ version: '0.1.1',
81
83
  elements: [Element::GenericDOM],
82
84
 
83
85
  issue: {
@@ -883,6 +883,7 @@ class Browser
883
883
  input.set( value.to_s )
884
884
  # Disabled inputs and such...
885
885
  rescue Watir::Exception::ObjectDisabledException,
886
+ Watir::Exception::ObjectReadOnlyException,
886
887
  Selenium::WebDriver::Error::InvalidElementStateError => e
887
888
  print_debug_level_2 "Could not fill in form input '#{name_or_id}'" <<
888
889
  " because: #{e} [#{e.class}"
@@ -150,6 +150,8 @@ class BrowserCluster
150
150
  @done_signal.clear
151
151
 
152
152
  synchronize do
153
+ print_debug "Queueing: #{job}"
154
+
153
155
  @pending_job_counter += 1
154
156
  @pending_jobs[job.id] += 1
155
157
  @job_callbacks[job.id] = block if block
@@ -200,6 +202,8 @@ class BrowserCluster
200
202
  # {Worker} states.
201
203
  def job_done( job )
202
204
  synchronize do
205
+ print_debug "Job done: #{job}"
206
+
203
207
  if !job.never_ending?
204
208
  @skip_states_per_job.delete job.id
205
209
  @job_callbacks.delete job.id
@@ -241,6 +245,8 @@ class BrowserCluster
241
245
  return if job_done? result.job
242
246
 
243
247
  synchronize do
248
+ print_debug "Got job result: #{result}"
249
+
244
250
  exception_jail( false ) do
245
251
  @job_callbacks[result.job.id].call result
246
252
  end
@@ -20,6 +20,10 @@ class BrowserProvider < Job
20
20
  browser.master.callback_for( self ).call browser
21
21
  end
22
22
 
23
+ def to_s
24
+ "#<#{self.class}:#{object_id} callback=#{browser.master.callback_for( self ) if browser && browser.master}>"
25
+ end
26
+
23
27
  end
24
28
 
25
29
  end
@@ -53,6 +53,10 @@ class ResourceExploration < Job
53
53
  super.tap { |j| j.resource = nil }
54
54
  end
55
55
 
56
+ def to_s
57
+ "#<#{self.class}:#{object_id} @resource=#{@resource}>"
58
+ end
59
+
56
60
  end
57
61
 
58
62
  end
@@ -35,6 +35,11 @@ class EventTrigger < ResourceExploration
35
35
  browser.trigger_event( resource, element, event )
36
36
  end
37
37
 
38
+ def to_s
39
+ "#<#{self.class}:#{object_id} @resource=#{@resource} " +
40
+ "@event=#{@event.inspect} @element=#{@element.inspect}>"
41
+ end
42
+
38
43
  end
39
44
 
40
45
  end
@@ -13,8 +13,14 @@ class ResourceExploration
13
13
 
14
14
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
15
15
  class Result < Job::Result
16
+
16
17
  # @return [Page]
17
18
  attr_accessor :page
19
+
20
+ def to_s
21
+ "#<#{self.class}:#{object_id} @job=#{@job} @page=#{@page}>"
22
+ end
23
+
18
24
  end
19
25
 
20
26
  end
@@ -41,6 +41,11 @@ class TaintTrace < ResourceExploration
41
41
  super
42
42
  end
43
43
 
44
+ def to_s
45
+ "#<#{self.class}:#{object_id} @resource=#{@resource} " +
46
+ "@taint=#{@taint.inspect} @injector=#{@injector.inspect}>"
47
+ end
48
+
44
49
  end
45
50
 
46
51
  end
@@ -25,6 +25,12 @@ class EventTrigger < ResourceExploration::EventTrigger
25
25
  super
26
26
  end
27
27
 
28
+ def to_s
29
+ "#<#{self.class}:#{object_id} @resource=#{@resource} " +
30
+ "@event=#{@event.inspect} @element=#{@element.inspect} " +
31
+ "@forwarder=#{@forwarder}>"
32
+ end
33
+
28
34
  end
29
35
 
30
36
  end
@@ -78,6 +78,7 @@ class Worker < Arachni::Browser
78
78
  # @see Arachni::Browser#trigger_events
79
79
  def run_job( job )
80
80
  @job = job
81
+ print_debug "Started: #{@job}"
81
82
 
82
83
  # PhantomJS may have crashed (it happens sometimes) so make sure that
83
84
  # we've got a live one before running the job.
@@ -94,7 +95,7 @@ class Worker < Arachni::Browser
94
95
  end
95
96
  end
96
97
  rescue TimeoutError => e
97
- print_debug "Job timed-out after #{@job_timeout} seconds: #{job}"
98
+ print_debug "Job timed-out after #{@job_timeout} seconds: #{@job}"
98
99
 
99
100
  # Could have left us with a broken browser.
100
101
  browser_respawn
@@ -110,6 +111,8 @@ class Worker < Arachni::Browser
110
111
  decrease_time_to_live
111
112
  browser_respawn_if_necessary
112
113
 
114
+ print_debug "Finished: #{@job}"
115
+
113
116
  true
114
117
  rescue Selenium::WebDriver::Error::WebDriverError
115
118
  browser_respawn
@@ -122,6 +125,7 @@ class Worker < Arachni::Browser
122
125
  @captured_pages.clear
123
126
  @page_snapshots.clear
124
127
  @page_snapshots_with_sinks.clear
128
+ @window_responses.clear
125
129
 
126
130
  # The jobs may have configured callbacks to capture pages etc.,
127
131
  # remove them.
@@ -18,7 +18,7 @@ module Auditable
18
18
  module DOM
19
19
  include WithNode
20
20
  include Auditable
21
- extend Forwardable
21
+ extend ::Forwardable
22
22
 
23
23
  INVALID_INPUT_DATA = [ "\0" ]
24
24
 
@@ -12,7 +12,7 @@ module WithAuditor
12
12
 
13
13
  # Delegate output related methods to the {WithAuditor#auditor}.
14
14
  module Output
15
- extend Forwardable
15
+ extend ::Forwardable
16
16
 
17
17
  [ :debug?, :print_error, :print_status, :print_verbose, :print_info,
18
18
  :print_line, :print_ok, :print_bad, :print_debug, :print_debug_backtrace,
@@ -490,6 +490,21 @@ class Form < Base
490
490
 
491
491
  private
492
492
 
493
+ def audit_single( payload, opts = {}, &block )
494
+ opts = opts.dup
495
+
496
+ if (each_m = opts.delete(:each_mutation))
497
+ opts[:each_mutation] = proc do |mutation|
498
+ next if mutation.mutation_with_original_values? ||
499
+ mutation.mutation_with_sample_values?
500
+
501
+ each_m.call( mutation )
502
+ end
503
+ end
504
+
505
+ super( payload, opts, &block )
506
+ end
507
+
493
508
  def skip?( elem )
494
509
  if elem.mutation_with_original_values? || elem.mutation_with_sample_values?
495
510
  id = elem.audit_id
@@ -425,6 +425,10 @@ class Page
425
425
  end
426
426
  alias :to_hash :to_h
427
427
 
428
+ def to_s
429
+ "#<#{self.class}:#{object_id} @url=#{@url.inspect} @dom=#{@dom}>"
430
+ end
431
+
428
432
  def persistent_hash
429
433
  digest.persistent_hash
430
434
  end
@@ -69,9 +69,16 @@ class DOM
69
69
  @url = url.freeze
70
70
  end
71
71
 
72
- def digest=( digest )
73
- return @digest = nil if !digest
74
- @digest = digest.freeze
72
+ def digest=( d )
73
+ return @digest = nil if !d
74
+
75
+ if d.include?( url ) || d.include?( page.url )
76
+ d = d.dup
77
+ d.gsub!( url, '' )
78
+ d.gsub!( page.url, '' )
79
+ end
80
+
81
+ @digest = d.freeze
75
82
  end
76
83
 
77
84
  # @param [Transition] transition
@@ -198,6 +205,10 @@ class DOM
198
205
  to_h
199
206
  end
200
207
 
208
+ def to_s
209
+ "#<#{self.class}:#{object_id} @url=#{@url.inspect}>"
210
+ end
211
+
201
212
  # @return [Hash]
202
213
  # Data representing this instance that are suitable the RPC transmission.
203
214
  def to_rpc_data
@@ -270,8 +281,14 @@ class DOM
270
281
  protected
271
282
 
272
283
  def digest_without_urls( other )
273
- digest.gsub( url, '' ).gsub( other.url, '' ).
274
- gsub( page.url, '' ).gsub( other.page.url, '' )
284
+ if !digest.include?( other.url ) && !digest.include?( other.page.url )
285
+ return digest
286
+ end
287
+
288
+ d = digest.dup
289
+ d.gsub!( other.url, '' )
290
+ d.gsub!( other.page.url, '' )
291
+ d
275
292
  end
276
293
 
277
294
  end
@@ -131,7 +131,7 @@ class Report
131
131
  end
132
132
 
133
133
  # @param [String] location
134
- # Location for the dumped report file.
134
+ # Location for the {#to_afr dumped} report file.
135
135
  #
136
136
  # @return [String]
137
137
  # Absolute location of the report.
@@ -144,15 +144,21 @@ class Report
144
144
  location += "/#{default_filename}"
145
145
  end
146
146
 
147
- IO.binwrite( location, RPC::Serializer.dump( self ) )
147
+ IO.binwrite( location, to_afr )
148
148
 
149
- # Append metadata to the end of the file.
149
+ File.expand_path( location )
150
+ end
151
+
152
+ # @return [String]
153
+ # Report serialized in the Arachni Framework Report format..
154
+ def to_afr
155
+ afr = RPC::Serializer.dump( self )
156
+
157
+ # Append metadata to the end of the dump.
150
158
  metadata = RPC::Serializer.dump( summary )
151
- File.open( location, 'a' ) do |f|
152
- f.write [metadata, metadata.size].pack( 'a*N' )
153
- end
159
+ afr << [metadata, metadata.size].pack( 'a*N' )
154
160
 
155
- File.expand_path( location )
161
+ afr
156
162
  end
157
163
 
158
164
  # @return [Hash]
@@ -19,7 +19,7 @@ class State
19
19
  #
20
20
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
21
21
  class Audit
22
- extend Forwardable
22
+ extend ::Forwardable
23
23
 
24
24
  def initialize
25
25
  @collection = Support::LookUp::HashSet.new( hasher: :persistent_hash )
@@ -6,6 +6,7 @@
6
6
  web site for more information on licensing and terms of use.
7
7
  =end
8
8
 
9
+ require 'sys/proctable'
9
10
  require 'ruby-mass'
10
11
  require 'stackprof'
11
12
 
@@ -15,6 +16,22 @@ module Support
15
16
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
16
17
  class Profiler
17
18
 
19
+ def self.write_samples_to_disk( file, options = {} )
20
+ profiler = Support::Profiler.new
21
+
22
+ Thread.new do
23
+ begin
24
+ loop do
25
+ profiler.write_object_space( file, options )
26
+ sleep options[:interval] || 1
27
+ end
28
+ rescue => e
29
+ ap e
30
+ ap e.backtrace
31
+ end
32
+ end
33
+ end
34
+
18
35
  def trace_allocations
19
36
  require 'objspace'
20
37
  ObjectSpace.trace_object_allocations_start
@@ -60,26 +77,19 @@ class Profiler
60
77
  ap find_references( o )
61
78
  end
62
79
 
63
- def print_object_space( options = {} )
64
- klass = options[:class]
65
- namespaces = options[:namespaces] || [Arachni]
66
- with_allocation_info = options[:with_allocation_info]
67
- with_references = options[:with_references]
68
- with_dependencies = options[:with_dependencies]
69
- max_entries = options[:max_entries] || 50
80
+ def object_space( options = {} )
81
+ klass = options[:class]
82
+ namespaces = options[:namespaces] || [Arachni]
83
+ max_entries = options[:max_entries] || 50
70
84
 
71
85
  object_space = Hash.new(0)
72
86
  @object_space ||= Hash.new(0)
73
87
 
74
88
  ObjectSpace.each_object do |o|
75
- next if o.class != klass || !object_within_namespace?( o, namespaces )
76
-
77
- print_object_allocations( o ) if with_allocation_info
78
- print_references( o ) if with_references
79
- print_dependencies( o ) if with_dependencies
80
-
89
+ next if o.class != klass && !object_within_namespace?( o, namespaces )
81
90
  object_space[o.class] += 1
82
91
  end
92
+
83
93
  object_space = Hash[object_space.sort_by { |_, v| v }.reverse[0..max_entries]]
84
94
 
85
95
  with_deltas = object_space.dup
@@ -91,9 +101,30 @@ class Profiler
91
101
  end
92
102
  end
93
103
 
94
- ap with_deltas
95
-
96
104
  @object_space = object_space.dup
105
+ with_deltas
106
+ end
107
+
108
+ def write_object_space( file, options = {} )
109
+ consumption = resource_consumption
110
+
111
+ str = "RAM: #{consumption[:memory_usage].round(3)}MB"
112
+ str << " (#{consumption[:memory_utilization]}%)"
113
+ str << " - CPU: #{consumption[:cpu_utilization]}%\n\n"
114
+
115
+ os = object_space( options )
116
+ maxsize = os.keys.map(&:to_s).map(&:size).sort.reverse.first
117
+
118
+ os.each do |klass, info|
119
+ offset = maxsize - klass.to_s.size
120
+ str << "#{klass}: #{' ' * offset}#{info}\n"
121
+ end
122
+
123
+ IO.write( file, str )
124
+ end
125
+
126
+ def print_object_space( options = {} )
127
+ ap object_space( options )
97
128
  end
98
129
 
99
130
  def count_objects( klass )
@@ -101,8 +132,6 @@ class Profiler
101
132
  end
102
133
 
103
134
  def resource_consumption
104
- require 'sys/proctable'
105
-
106
135
  procinfo = ::Sys::ProcTable.ps( Process.pid )
107
136
  {
108
137
  cpu_utilization: procinfo[:pctcpu],
@@ -92,6 +92,11 @@ module Output
92
92
  def debug?(*)
93
93
  end
94
94
 
95
+ 1.upto( 3 ) do |i|
96
+ define_method( "debug_level_#{i}?" ) {}
97
+ define_method( "debug_level_#{i}" ) {}
98
+ end
99
+
95
100
  def only_positives
96
101
  end
97
102
 
@@ -1 +1 @@
1
- 1.0.1
1
+ 1.0.2
@@ -101,6 +101,36 @@ describe Arachni::Element::Form do
101
101
  end
102
102
  end
103
103
 
104
+ describe '#audit' do
105
+ describe :each_mutation do
106
+ it 'ignores #mutation_with_original_values' do
107
+ had_mutation_with_original_values = false
108
+ each_mutation = proc do |mutation|
109
+ had_mutation_with_original_values ||=
110
+ mutation.mutation_with_original_values?
111
+ end
112
+
113
+ subject.audit( 'stuff', each_mutation: each_mutation ) {}
114
+ subject.http.run
115
+
116
+ had_mutation_with_original_values.should be_false
117
+ end
118
+
119
+ it 'ignores mutation_with_sample_values' do
120
+ had_mutation_with_sample_values = false
121
+ each_mutation = proc do |mutation|
122
+ had_mutation_with_sample_values ||=
123
+ mutation.mutation_with_sample_values?
124
+ end
125
+
126
+ subject.audit( 'stuff', each_mutation: each_mutation ) {}
127
+ subject.http.run
128
+
129
+ had_mutation_with_sample_values.should be_false
130
+ end
131
+ end
132
+ end
133
+
104
134
  describe '#name_or_id' do
105
135
  context 'when a #name is available' do
106
136
  it 'returns it' do
@@ -221,6 +221,14 @@ describe Arachni::Report do
221
221
  end
222
222
  end
223
223
 
224
+ describe '#to_afr' do
225
+ it 'returns the object in AFR format' do
226
+ @report_file = report.save
227
+
228
+ IO.binread( @report_file ).should == report.to_afr
229
+ end
230
+ end
231
+
224
232
  describe '#to_h' do
225
233
  it 'returns the object as a hash' do
226
234
  report.to_h.should == {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arachni
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tasos Laskos
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-07 00:00:00.000000000 Z
11
+ date: 2014-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler