arachni 1.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -0
  3. data/README.md +2 -2
  4. data/arachni.gemspec +1 -1
  5. data/components/checks/active/code_injection_php_input_wrapper.rb +8 -3
  6. data/components/checks/active/file_inclusion.rb +7 -3
  7. data/components/checks/active/path_traversal.rb +7 -3
  8. data/components/checks/passive/grep/cookie_set_for_parent_domain.rb +5 -3
  9. data/components/plugins/cookie_collector.rb +1 -1
  10. data/components/plugins/proxy.rb +4 -3
  11. data/components/plugins/vector_feed.rb +1 -1
  12. data/components/reporters/html/default/issue.erb +5 -0
  13. data/components/reporters/stdout.rb +4 -0
  14. data/lib/arachni/browser.rb +25 -6
  15. data/lib/arachni/browser/element_locator.rb +1 -1
  16. data/lib/arachni/browser/javascript/taint_tracer.rb +3 -3
  17. data/lib/arachni/browser/javascript/taint_tracer/frame.rb +1 -1
  18. data/lib/arachni/browser/javascript/taint_tracer/frame/called_function.rb +1 -1
  19. data/lib/arachni/browser/javascript/taint_tracer/sink/base.rb +1 -1
  20. data/lib/arachni/check/auditor.rb +2 -0
  21. data/lib/arachni/component/manager.rb +2 -2
  22. data/lib/arachni/component/options/base.rb +2 -2
  23. data/lib/arachni/element/base.rb +2 -2
  24. data/lib/arachni/element/cookie.rb +4 -4
  25. data/lib/arachni/element/form.rb +1 -1
  26. data/lib/arachni/element/generic_dom.rb +1 -1
  27. data/lib/arachni/framework.rb +9 -1
  28. data/lib/arachni/http/client.rb +2 -0
  29. data/lib/arachni/http/request.rb +2 -2
  30. data/lib/arachni/http/response.rb +1 -1
  31. data/lib/arachni/issue.rb +2 -2
  32. data/lib/arachni/option_group.rb +1 -1
  33. data/lib/arachni/option_groups/input.rb +1 -1
  34. data/lib/arachni/option_groups/scope.rb +1 -1
  35. data/lib/arachni/page.rb +1 -1
  36. data/lib/arachni/page/dom/transition.rb +3 -3
  37. data/lib/arachni/parser.rb +3 -1
  38. data/lib/arachni/platform/list.rb +1 -1
  39. data/lib/arachni/report.rb +1 -1
  40. data/lib/arachni/rpc/client/instance/framework.rb +6 -6
  41. data/lib/arachni/rpc/client/instance/service.rb +7 -7
  42. data/lib/arachni/rpc/server/dispatcher.rb +18 -5
  43. data/lib/arachni/rpc/server/dispatcher/node.rb +13 -6
  44. data/lib/arachni/rpc/server/framework/distributor.rb +1 -1
  45. data/lib/arachni/rpc/server/framework/master.rb +1 -1
  46. data/lib/arachni/rpc/server/framework/multi_instance.rb +2 -2
  47. data/lib/arachni/rpc/server/instance.rb +11 -3
  48. data/lib/arachni/ruby/hash.rb +7 -6
  49. data/lib/arachni/state/framework.rb +1 -0
  50. data/lib/version +1 -1
  51. data/spec/arachni/browser_spec.rb +25 -0
  52. data/spec/arachni/component/manager_spec.rb +1 -1
  53. data/spec/arachni/element/cookie_spec.rb +3 -3
  54. data/spec/arachni/http/request_spec.rb +3 -3
  55. data/spec/arachni/option_groups/scope_spec.rb +2 -2
  56. data/spec/arachni/parser_spec.rb +7 -0
  57. data/spec/arachni/reporter/manager_spec.rb +1 -1
  58. data/spec/arachni/rpc/server/dispatcher/node_spec.rb +2 -0
  59. data/spec/arachni/rpc/server/framework_spec.rb +1 -1
  60. data/spec/arachni/ruby/hash_spec.rb +8 -8
  61. data/spec/support/servers/checks/passive/grep/cookie_set_for_parent_domain.rb +1 -1
  62. data/spec/support/shared/element/capabilities/inputtable.rb +2 -2
  63. data/ui/cli/utilities.rb +3 -0
  64. metadata +4 -4
@@ -69,7 +69,7 @@ module Master
69
69
  return false
70
70
  end
71
71
 
72
- instance_info = instance_info.symbolize_keys
72
+ instance_info = instance_info.my_symbolize_keys
73
73
 
74
74
  fail "Instance info does not contain a 'url' key." if !instance_info[:url]
75
75
  fail "Instance info does not contain a 'token' key." if !instance_info[:token]
@@ -86,7 +86,7 @@ module MultiInstance
86
86
  # @return [Hash]
87
87
  # Progress data.
88
88
  def progress( opts = {}, &block )
89
- opts = opts.symbolize_keys
89
+ opts = opts.my_symbolize_keys
90
90
 
91
91
  include_statistics = opts[:statistics].nil? ? true : opts[:statistics]
92
92
  include_slaves = opts[:slaves].nil? ? true : opts[:slaves]
@@ -153,7 +153,7 @@ module MultiInstance
153
153
  slave_data.compact!
154
154
 
155
155
  slave_data.each do |slave|
156
- slave = slave.symbolize_keys
156
+ slave = slave.my_symbolize_keys
157
157
 
158
158
  if include_errors
159
159
  data[:errors] |= slave[:errors]
@@ -532,7 +532,7 @@ class Instance
532
532
  end
533
533
 
534
534
  # Normalize this sucker to have symbols as keys.
535
- opts = opts.symbolize_keys( false )
535
+ opts = opts.my_symbolize_keys( false )
536
536
 
537
537
  slaves = opts.delete(:slaves) || []
538
538
  spawn_count = opts[:spawns]
@@ -750,7 +750,7 @@ class Instance
750
750
  parsed[q.to_sym] = nil
751
751
 
752
752
  when Hash
753
- parsed.merge!( q.symbolize_keys )
753
+ parsed.merge!( q.my_symbolize_keys )
754
754
  end
755
755
  end
756
756
 
@@ -758,7 +758,7 @@ class Instance
758
758
  parsed[w.to_sym] = nil
759
759
 
760
760
  when Hash
761
- parsed.merge!( w.symbolize_keys )
761
+ parsed.merge!( w.my_symbolize_keys )
762
762
  end
763
763
  end
764
764
 
@@ -806,6 +806,14 @@ class Instance
806
806
 
807
807
  # Starts RPC service.
808
808
  def run
809
+ Reactor.global.on_error do |_, e|
810
+ print_error "Arachni::Reactor: #{e}"
811
+
812
+ e.backtrace.each do |l|
813
+ print_error "Arachni::Reactor: #{l}"
814
+ end
815
+ end
816
+
809
817
  print_status 'Starting the server...'
810
818
  @server.start
811
819
  end
@@ -19,10 +19,11 @@ class Hash
19
19
  #
20
20
  # @return [Hash]
21
21
  # Hash with +self+'s keys recursively converted to strings.
22
- def stringify_keys( recursively = true )
22
+ def my_stringify_keys( recursively = true )
23
23
  stringified = {}
24
24
  each do |k, v|
25
- stringified[k.to_s] = (recursively && v.is_a?( Hash ) ? v.stringify_keys : v)
25
+ stringified[k.to_s] = (recursively && v.is_a?( Hash ) ?
26
+ v.my_stringify_keys : v)
26
27
  end
27
28
  stringified
28
29
  end
@@ -34,20 +35,20 @@ class Hash
34
35
  #
35
36
  # @return [Hash]
36
37
  # Hash with +self+'s keys recursively converted to symbols.
37
- def symbolize_keys( recursively = true )
38
+ def my_symbolize_keys( recursively = true )
38
39
  symbolize = {}
39
40
  each do |k, v|
40
41
  k = k.respond_to?(:to_sym) ? k.to_sym : k
41
42
 
42
43
  symbolize[k] = (recursively && v.is_a?( Hash ) ?
43
- v.symbolize_keys : v)
44
+ v.my_symbolize_keys : v)
44
45
  end
45
46
  symbolize
46
47
  end
47
48
 
48
49
  # @return [Hash]
49
50
  # Hash with +self+'s keys and values recursively converted to strings.
50
- def stringify
51
+ def my_stringify
51
52
  apply_recursively(:to_s)
52
53
  end
53
54
 
@@ -79,7 +80,7 @@ class Hash
79
80
  # @return [Hash]
80
81
  # Self with the keys and values converted to lower-case strings.
81
82
  def downcase
82
- stringify_keys.inject({}) do |h, (k, v)|
83
+ my_stringify_keys.inject({}) do |h, (k, v)|
83
84
  k = k.downcase if k.is_a?( String )
84
85
  v = v.downcase if v.is_a?( String )
85
86
  h[k] = v
@@ -100,6 +100,7 @@ class Framework
100
100
  suspending_plugins: 'Suspending plugins.',
101
101
  saving_snapshot: 'Saving snapshot at: %s',
102
102
  snapshot_location: 'Snapshot location: %s',
103
+ browser_cluster_startup: 'Initialising the browser cluster.',
103
104
  browser_cluster_shutdown: 'Shutting down the browser cluster.',
104
105
  clearing_queues: 'Clearing the audit queues.',
105
106
  waiting_for_plugins: 'Waiting for the plugins to finish.',
@@ -1 +1 @@
1
- 1.0
1
+ 1.0.1
@@ -1797,6 +1797,20 @@ describe Arachni::Browser do
1797
1797
 
1798
1798
  transition.options[:cookies].should == cookie
1799
1799
  end
1800
+
1801
+ context 'when auditing existing cookies' do
1802
+ it 'preserves the HttpOnly attribute' do
1803
+ @browser.goto( @url )
1804
+ @browser.cookies.size.should == 1
1805
+
1806
+ cookies = { @browser.cookies.first.name => 'updated' }
1807
+ @browser.goto( @url, cookies: cookies )
1808
+
1809
+ @browser.cookies.first.value == 'updated'
1810
+ @browser.cookies.first.should be_http_only
1811
+ end
1812
+ end
1813
+
1800
1814
  end
1801
1815
 
1802
1816
  describe :take_snapshot do
@@ -2269,6 +2283,17 @@ describe Arachni::Browser do
2269
2283
  cookie.name.should == 'This name should be updated; and properly escaped'
2270
2284
  cookie.value.should == 'This value should be updated; and properly escaped'
2271
2285
  end
2286
+
2287
+ it 'preserves the HttpOnly attribute' do
2288
+ @browser.load @url
2289
+ @browser.cookies.first.should be_http_only
2290
+ end
2291
+
2292
+ context 'when no page is available' do
2293
+ it 'returns an empty Array' do
2294
+ @browser.cookies.should be_empty
2295
+ end
2296
+ end
2272
2297
  end
2273
2298
 
2274
2299
  describe '#snapshot_id' do
@@ -301,7 +301,7 @@ describe Arachni::Component::Manager do
301
301
  'opt_opt' => 'opt_opt value',
302
302
  'default_opt' => 'value2'
303
303
  }
304
- @components.prepare_options( c, @components[c], opts ).should == opts.symbolize_keys
304
+ @components.prepare_options( c, @components[c], opts ).should == opts.my_symbolize_keys
305
305
  end
306
306
 
307
307
  context 'with missing options' do
@@ -199,7 +199,7 @@ describe Arachni::Element::Cookie do
199
199
 
200
200
  describe '#encode' do
201
201
  it 'encodes the string in a way that makes is suitable to be included in a cookie header' do
202
- described_class.encode( 'some stuff ;%=' ).should == 'some+stuff+%3B%25='
202
+ described_class.encode( 'some stuff \'";%=' ).should == 'some+stuff+%27%22%3B%25='
203
203
  end
204
204
  end
205
205
 
@@ -214,7 +214,7 @@ describe Arachni::Element::Cookie do
214
214
  )
215
215
 
216
216
  c.to_set_cookie.should ==
217
- 'blah%3Dha%25=some+stuff+%3B; Path=/; Domain=.127.0.0.2; Secure; HttpOnly'
217
+ 'blah%3Dha%25=some+stuff+%3B; Path=/; Domain=127.0.0.2; Secure; HttpOnly'
218
218
  described_class.from_set_cookie( url, c.to_set_cookie ).first.should == c
219
219
 
220
220
  c = described_class.new(
@@ -226,7 +226,7 @@ describe Arachni::Element::Cookie do
226
226
 
227
227
  described_class.from_set_cookie( url, c.to_set_cookie ).first.should == c
228
228
  c.to_set_cookie.should ==
229
- 'blah%3Dha%25=some+stuff+%3B; Path=/stuff; Domain=.127.0.0.2'
229
+ 'blah%3Dha%25=some+stuff+%3B; Path=/stuff; Domain=127.0.0.2'
230
230
  end
231
231
  end
232
232
 
@@ -450,12 +450,12 @@ describe Arachni::HTTP::Request do
450
450
  described_class.new(
451
451
  url: url,
452
452
  proxy: 'http://stuff/',
453
- proxy_type: 'http'
453
+ proxy_type: :http
454
454
  )
455
455
  end
456
456
 
457
457
  it 'forwards it' do
458
- subject.options[:proxytype].should == 'http'
458
+ subject.options[:proxytype].should == :http
459
459
  end
460
460
  end
461
461
  end
@@ -486,7 +486,7 @@ describe Arachni::HTTP::Request do
486
486
  context "and #{Arachni::OptionGroups::HTTP}#proxy_type" do
487
487
  it 'forwards it' do
488
488
  Arachni::Options.http.proxy_type = 'http'
489
- subject.options[:proxytype].should == 'http'
489
+ subject.options[:proxytype].should == :http
490
490
  end
491
491
  end
492
492
  end
@@ -214,14 +214,14 @@ describe Arachni::OptionGroups::Scope do
214
214
  values = { /redundant_path_patterns/ => 1 }
215
215
  subject.redundant_path_patterns = values
216
216
 
217
- data['redundant_path_patterns'].should == values.stringify
217
+ data['redundant_path_patterns'].should == values.my_stringify
218
218
  end
219
219
 
220
220
  it "converts 'url_rewrites' to strings" do
221
221
  values = { /url_rewrites/ => 'test' }
222
222
  subject.url_rewrites = values
223
223
 
224
- data['url_rewrites'].should == values.stringify
224
+ data['url_rewrites'].should == values.my_stringify
225
225
  end
226
226
 
227
227
  %w(exclude_path_patterns exclude_content_patterns include_path_patterns).each do |k|
@@ -517,6 +517,13 @@ describe Arachni::Parser do
517
517
  subject.link_vars.should == { 'id' => '13' }
518
518
  end
519
519
  end
520
+
521
+ context 'when the URL cannot be parsed' do
522
+ it 'returns an empty array' do
523
+ subject.url = nil
524
+ subject.link_vars.should == {}
525
+ end
526
+ end
520
527
  end
521
528
 
522
529
  end
@@ -23,7 +23,7 @@ describe Arachni::Reporter::Manager do
23
23
  options = { 'outfile' => 'stuff' }
24
24
  reporter = @reporters.run( :foo, report, options )
25
25
 
26
- reporter.options.should == options.symbolize_keys(false)
26
+ reporter.options.should == options.my_symbolize_keys(false)
27
27
  end
28
28
  end
29
29
  end
@@ -97,6 +97,8 @@ describe Arachni::RPC::Server::Dispatcher::Node do
97
97
  c = @get_node.call
98
98
 
99
99
  n.add_neighbour( c.url )
100
+ sleep 1
101
+
100
102
  c.neighbours.should == [n.url]
101
103
  n.neighbours.should == [c.url]
102
104
 
@@ -226,7 +226,7 @@ describe 'Arachni::RPC::Server::Framework' do
226
226
  data.keys.sort.should == @progress_keys
227
227
 
228
228
  data[:statistics].keys.should == instance.framework.statistics.keys
229
- data[:messages].should be_any
229
+ data[:messages].should be_empty
230
230
  data[:status].should be_true
231
231
  data[:busy].nil?.should be_false
232
232
  data[:issues].should be_any
@@ -23,14 +23,14 @@ describe Hash do
23
23
  }
24
24
  end
25
25
 
26
- describe '#stringify_keys' do
26
+ describe '#my_stringify_keys' do
27
27
  it 'recursively converts keys to strings' do
28
- with_symbols.stringify_keys.should == with_strings
28
+ with_symbols.my_stringify_keys.should == with_strings
29
29
  end
30
30
 
31
31
  context 'when the recursive is set to false' do
32
32
  it 'only converts the keys at depth 1' do
33
- with_symbols.stringify_keys( false ).should == {
33
+ with_symbols.my_stringify_keys( false ).should == {
34
34
  'stuff' => 'blah',
35
35
  'more' => {
36
36
  stuff: {
@@ -42,14 +42,14 @@ describe Hash do
42
42
  end
43
43
  end
44
44
 
45
- describe '#symbolize_keys' do
45
+ describe '#my_symbolize_keys' do
46
46
  it 'recursively converts keys to symbols' do
47
- with_strings.symbolize_keys.should == with_symbols
47
+ with_strings.my_symbolize_keys.should == with_symbols
48
48
  end
49
49
 
50
50
  context 'when the recursive is set to false' do
51
51
  it 'only converts the keys at depth 1' do
52
- with_strings.symbolize_keys( false ).should == {
52
+ with_strings.my_symbolize_keys( false ).should == {
53
53
  stuff: 'blah',
54
54
  more: {
55
55
  'stuff' => {
@@ -75,14 +75,14 @@ describe Hash do
75
75
  end
76
76
  end
77
77
 
78
- describe '#stringify' do
78
+ describe '#my_stringify' do
79
79
  it 'returns a Hash with keys and values recursively converted to strings' do
80
80
  {
81
81
  test: 'blah',
82
82
  another_hash: {
83
83
  stuff: 'test'
84
84
  }
85
- }.stringify.should == {
85
+ }.my_stringify.should == {
86
86
  'test' => 'blah',
87
87
  'another_hash' => {
88
88
  'stuff' => 'test'
@@ -4,7 +4,7 @@ require 'sinatra/contrib'
4
4
  get '/' do
5
5
  response.set_cookie( 'cookie', {
6
6
  value: 'value',
7
- domain: nil
7
+ domain: '.localhost'
8
8
  })
9
9
  response.set_cookie( 'cookie2', {
10
10
  value: 'value2',
@@ -15,7 +15,7 @@ shared_examples_for 'inputtable' do |options = {}|
15
15
  end
16
16
  end
17
17
 
18
- let(:sym_key_inputs) { inputs.symbolize_keys }
18
+ let(:sym_key_inputs) { inputs.my_symbolize_keys }
19
19
 
20
20
  let(:keys) do
21
21
  subject.inputs.keys
@@ -140,7 +140,7 @@ shared_examples_for 'inputtable' do |options = {}|
140
140
  context 'when it has the given inputs (names and values)' do
141
141
  it 'returns true' do
142
142
  subject.has_inputs?( subject.inputs ).should be_true
143
- subject.has_inputs?( subject.inputs.symbolize_keys ).should be_true
143
+ subject.has_inputs?( subject.inputs.my_symbolize_keys ).should be_true
144
144
  end
145
145
  end
146
146
  context 'when it does not have the given inputs' do
@@ -29,9 +29,12 @@ module Utilities
29
29
  issue_cnt = issues.count
30
30
  issues.each.with_index do |issue, i|
31
31
  meth = input = ''
32
+
32
33
  if issue.active?
33
34
  input = " input `#{issue.vector.affected_input_name}`"
34
35
  meth = " using #{issue.vector.method.to_s.upcase}"
36
+ elsif issue.vector.respond_to?( :inputs )
37
+ input = " with inputs `#{issue.vector.inputs.keys.join(', ')}`"
35
38
  end
36
39
 
37
40
  cnt = "#{i + 1} |".rjust( issue_cnt.to_s.size + 2 )
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.1
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-08-30 00:00:00.000000000 Z
11
+ date: 2014-09-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - '='
88
88
  - !ruby/object:Gem::Version
89
- version: 0.2.0
89
+ version: 0.2.1.1
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - '='
95
95
  - !ruby/object:Gem::Version
96
- version: 0.2.0
96
+ version: 0.2.1.1
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: typhoeus
99
99
  requirement: !ruby/object:Gem::Requirement