arachni 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/Gemfile +2 -0
- data/README.md +1 -1
- data/components/checks/active/code_injection_php_input_wrapper.rb +3 -6
- data/components/checks/active/file_inclusion.rb +3 -6
- data/components/checks/active/path_traversal.rb +3 -6
- data/components/checks/active/source_code_disclosure.rb +3 -6
- data/components/checks/active/xss_dom_inputs.rb +5 -3
- data/lib/arachni/browser.rb +1 -0
- data/lib/arachni/browser_cluster.rb +6 -0
- data/lib/arachni/browser_cluster/jobs/browser_provider.rb +4 -0
- data/lib/arachni/browser_cluster/jobs/resource_exploration.rb +4 -0
- data/lib/arachni/browser_cluster/jobs/resource_exploration/event_trigger.rb +5 -0
- data/lib/arachni/browser_cluster/jobs/resource_exploration/result.rb +6 -0
- data/lib/arachni/browser_cluster/jobs/taint_trace.rb +5 -0
- data/lib/arachni/browser_cluster/jobs/taint_trace/event_trigger.rb +6 -0
- data/lib/arachni/browser_cluster/worker.rb +5 -1
- data/lib/arachni/element/capabilities/auditable/dom.rb +1 -1
- data/lib/arachni/element/capabilities/with_auditor/output.rb +1 -1
- data/lib/arachni/element/form.rb +15 -0
- data/lib/arachni/page.rb +4 -0
- data/lib/arachni/page/dom.rb +22 -5
- data/lib/arachni/report.rb +13 -7
- data/lib/arachni/state/audit.rb +1 -1
- data/lib/arachni/support/profiler.rb +46 -17
- data/lib/arachni/ui/foo/output.rb +5 -0
- data/lib/version +1 -1
- data/spec/arachni/element/form_spec.rb +30 -0
- data/spec/arachni/report_spec.rb +8 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1ab8801aa396dbd2a6aa10c911a91777b046542
|
4
|
+
data.tar.gz: 2251a40388dec9fc771bc8aa51ddc7680bb4f825
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ccf69071cb3b2ddb1d880041979ac24d8d2f0d61662eadae5ad77544cbd226d47aa746e8505022d03b466290bece49410efc61957d0fc3fbd9359e5361d0b198
|
7
|
+
data.tar.gz: 8d3f66447ef08172a43b29605b1f611131a0565a06ba70c706ee199d191043ee78c93b1eb8bef80d95e7215950e54a1ad3d650e3d6d440cc9fb5ab2babbb21f1
|
data/CHANGELOG.md
CHANGED
@@ -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
data/README.md
CHANGED
@@ -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.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.
|
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.
|
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.
|
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.
|
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.
|
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
|
-
|
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: {
|
data/lib/arachni/browser.rb
CHANGED
@@ -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
|
@@ -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
|
@@ -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.
|
@@ -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,
|
data/lib/arachni/element/form.rb
CHANGED
@@ -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
|
data/lib/arachni/page.rb
CHANGED
data/lib/arachni/page/dom.rb
CHANGED
@@ -69,9 +69,16 @@ class DOM
|
|
69
69
|
@url = url.freeze
|
70
70
|
end
|
71
71
|
|
72
|
-
def digest=(
|
73
|
-
return @digest = nil if !
|
74
|
-
|
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.
|
274
|
-
|
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
|
data/lib/arachni/report.rb
CHANGED
@@ -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,
|
147
|
+
IO.binwrite( location, to_afr )
|
148
148
|
|
149
|
-
|
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
|
-
|
152
|
-
f.write [metadata, metadata.size].pack( 'a*N' )
|
153
|
-
end
|
159
|
+
afr << [metadata, metadata.size].pack( 'a*N' )
|
154
160
|
|
155
|
-
|
161
|
+
afr
|
156
162
|
end
|
157
163
|
|
158
164
|
# @return [Hash]
|
data/lib/arachni/state/audit.rb
CHANGED
@@ -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
|
64
|
-
klass
|
65
|
-
namespaces
|
66
|
-
|
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
|
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],
|
data/lib/version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
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
|
data/spec/arachni/report_spec.rb
CHANGED
@@ -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.
|
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-
|
11
|
+
date: 2014-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|