arachni 1.0.5 → 1.0.6

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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -0
  3. data/README.md +9 -2
  4. data/components/checks/active/code_injection.rb +5 -5
  5. data/components/checks/active/code_injection_timing.rb +3 -3
  6. data/components/checks/active/no_sql_injection_differential.rb +3 -2
  7. data/components/checks/active/os_cmd_injection.rb +11 -5
  8. data/components/checks/active/os_cmd_injection_timing.rb +11 -4
  9. data/components/checks/active/path_traversal.rb +2 -2
  10. data/components/checks/active/sql_injection.rb +1 -1
  11. data/components/checks/active/sql_injection/patterns/mssql +1 -0
  12. data/components/checks/active/sql_injection_differential.rb +3 -2
  13. data/components/checks/active/unvalidated_redirect.rb +3 -3
  14. data/components/checks/passive/common_directories/directories.txt +2 -0
  15. data/components/checks/passive/common_files/filenames.txt +1 -0
  16. data/lib/arachni/browser.rb +17 -1
  17. data/lib/arachni/check/auditor.rb +5 -2
  18. data/lib/arachni/check/base.rb +30 -5
  19. data/lib/arachni/element/capabilities/analyzable/differential.rb +2 -5
  20. data/lib/arachni/element/capabilities/auditable.rb +3 -1
  21. data/lib/arachni/element/capabilities/with_dom.rb +1 -0
  22. data/lib/arachni/element/capabilities/with_node.rb +1 -1
  23. data/lib/arachni/element/cookie.rb +2 -2
  24. data/lib/arachni/element/form.rb +1 -1
  25. data/lib/arachni/element/header.rb +2 -2
  26. data/lib/arachni/element/link_template.rb +1 -1
  27. data/lib/arachni/framework.rb +21 -1144
  28. data/lib/arachni/framework/parts/audit.rb +282 -0
  29. data/lib/arachni/framework/parts/browser.rb +132 -0
  30. data/lib/arachni/framework/parts/check.rb +86 -0
  31. data/lib/arachni/framework/parts/data.rb +158 -0
  32. data/lib/arachni/framework/parts/platform.rb +34 -0
  33. data/lib/arachni/framework/parts/plugin.rb +61 -0
  34. data/lib/arachni/framework/parts/report.rb +128 -0
  35. data/lib/arachni/framework/parts/scope.rb +40 -0
  36. data/lib/arachni/framework/parts/state.rb +457 -0
  37. data/lib/arachni/http/client.rb +33 -30
  38. data/lib/arachni/http/request.rb +6 -2
  39. data/lib/arachni/issue.rb +55 -1
  40. data/lib/arachni/platform/manager.rb +25 -21
  41. data/lib/arachni/state/framework.rb +7 -1
  42. data/lib/arachni/utilities.rb +10 -0
  43. data/lib/version +1 -1
  44. data/spec/arachni/browser_spec.rb +13 -0
  45. data/spec/arachni/check/auditor_spec.rb +1 -0
  46. data/spec/arachni/check/base_spec.rb +80 -0
  47. data/spec/arachni/element/cookie_spec.rb +2 -2
  48. data/spec/arachni/framework/parts/audit_spec.rb +391 -0
  49. data/spec/arachni/framework/parts/browser_spec.rb +26 -0
  50. data/spec/arachni/framework/parts/check_spec.rb +24 -0
  51. data/spec/arachni/framework/parts/data_spec.rb +187 -0
  52. data/spec/arachni/framework/parts/platform_spec.rb +62 -0
  53. data/spec/arachni/framework/parts/plugin_spec.rb +41 -0
  54. data/spec/arachni/framework/parts/report_spec.rb +66 -0
  55. data/spec/arachni/framework/parts/scope_spec.rb +86 -0
  56. data/spec/arachni/framework/parts/state_spec.rb +528 -0
  57. data/spec/arachni/framework_spec.rb +17 -1344
  58. data/spec/arachni/http/client_spec.rb +12 -7
  59. data/spec/arachni/issue_spec.rb +35 -0
  60. data/spec/arachni/platform/manager_spec.rb +2 -3
  61. data/spec/arachni/state/framework_spec.rb +15 -0
  62. data/spec/components/checks/active/code_injection_timing_spec.rb +5 -5
  63. data/spec/components/checks/active/no_sql_injection_differential_spec.rb +4 -0
  64. data/spec/components/checks/active/os_cmd_injection_spec.rb +20 -7
  65. data/spec/components/checks/active/os_cmd_injection_timing_spec.rb +5 -5
  66. data/spec/components/checks/active/sql_injection_differential_spec.rb +4 -0
  67. data/spec/components/checks/active/sql_injection_spec.rb +2 -3
  68. data/spec/support/servers/arachni/browser.rb +31 -0
  69. data/spec/support/servers/checks/active/code_injection.rb +1 -1
  70. data/spec/support/servers/checks/active/no_sql_injection_differential.rb +36 -34
  71. data/spec/support/servers/checks/active/os_cmd_injection.rb +6 -12
  72. data/spec/support/servers/checks/active/os_cmd_injection_timing.rb +9 -4
  73. data/spec/support/servers/checks/active/sql_injection.rb +1 -1
  74. data/spec/support/servers/checks/active/sql_injection_differential.rb +37 -34
  75. data/spec/support/shared/element/capabilities/with_node.rb +25 -0
  76. data/spec/support/shared/framework.rb +26 -0
  77. data/ui/cli/output.rb +2 -0
  78. data/ui/cli/rpc/server/dispatcher/option_parser.rb +1 -1
  79. metadata +32 -4
  80. data/components/checks/active/sql_injection/patterns/coldfusion +0 -1
@@ -396,26 +396,31 @@ describe Arachni::HTTP::Client do
396
396
  called.should be_false
397
397
  end
398
398
 
399
- context 'when the callback creates new requests and nested callbacks' do
399
+ context 'when the callback creates new requests' do
400
400
  it 'run these too' do
401
401
  called = false
402
402
  subject.after_run do
403
- subject.after_run { called = true }
403
+ subject.get do
404
+ called = true
405
+ end
404
406
  end
405
407
  subject.run
408
+ called.should be_true
409
+
410
+ called = false
411
+ subject.run
406
412
  called.should be_false
413
+ end
414
+ end
407
415
 
416
+ context 'when the callback creates new callbacks' do
417
+ it 'run these too' do
408
418
  called = false
409
419
  subject.after_run do
410
- subject.get
411
420
  subject.after_run { called = true }
412
421
  end
413
422
  subject.run
414
423
  called.should be_true
415
-
416
- called = false
417
- subject.run
418
- called.should be_false
419
424
  end
420
425
  end
421
426
  end
@@ -29,6 +29,24 @@ describe Arachni::Issue do
29
29
  issue.name.should == "Check name \u2713"
30
30
  end
31
31
 
32
+ describe '#recheck' do
33
+ it 'rechecks the issue' do
34
+ Arachni::Options.paths.checks = fixtures_path + '/taint_check/'
35
+ Arachni::Options.audit.elements :links, :forms, :cookies
36
+
37
+ issue = nil
38
+ Arachni::Framework.new do |f|
39
+ f.options.url = "#{web_server_url_for( :auditor )}/link"
40
+ f.checks.load :taint
41
+
42
+ f.run
43
+ issue = f.report.issues.first.variations.first
44
+ end
45
+
46
+ issue.recheck.should == issue
47
+ end
48
+ end
49
+
32
50
  describe '#to_rpc_data' do
33
51
  let(:issue) { issue_with_variations }
34
52
  let(:data) { issue.to_rpc_data }
@@ -79,6 +97,12 @@ describe Arachni::Issue do
79
97
  it "restores 'variation'" do
80
98
  restored_issue.variation?.should == issue.variation?
81
99
  end
100
+
101
+ it 'restores variation parent' do
102
+ restored_issue.variations.each do |v|
103
+ v.parent.should == restored_issue
104
+ end
105
+ end
82
106
  end
83
107
 
84
108
  [:page=, :referring_page=, :vector=].each do |m|
@@ -607,6 +631,10 @@ describe Arachni::Issue do
607
631
  end
608
632
  root.variations.should be_nil
609
633
  end
634
+
635
+ it 'has a #parent' do
636
+ issue.as_variation.parent.should == issue
637
+ end
610
638
  end
611
639
 
612
640
  describe '#to_solo!' do
@@ -645,6 +673,13 @@ describe Arachni::Issue do
645
673
  variation.vector.affected_input_name.should be_true
646
674
  variation.to_solo!( parent ).vector.affected_input_name.should be_true
647
675
  end
676
+
677
+ it 'skips #parent' do
678
+ parent = issue.with_variations
679
+ variation = issue.as_variation
680
+
681
+ variation.to_solo!( parent ).parent.should be_nil
682
+ end
648
683
  end
649
684
 
650
685
  describe '#to_solo' do
@@ -276,7 +276,6 @@ describe Arachni::Platform::Manager do
276
276
  describe '#db' do
277
277
  it 'returns the database list' do
278
278
  platforms.db.should be_kind_of Arachni::Platform::List
279
- platforms.db.valid.sort.should == described_class::DB.sort
280
279
  end
281
280
  end
282
281
 
@@ -385,11 +384,11 @@ describe Arachni::Platform::Manager do
385
384
  it 'returns all valid platforms' do
386
385
  platforms.valid.sort.should ==
387
386
  [:unix, :linux, :bsd, :solaris, :windows,
388
- :coldfusion, :db2, :emc, :informix, :interbase, :mssql, :mysql,
387
+ :db2, :emc, :informix, :interbase, :mssql, :mysql,
389
388
  :oracle, :firebird, :maxdb, :pgsql, :sqlite, :apache, :iis, :nginx,
390
389
  :tomcat, :asp, :aspx, :jsp, :perl, :php, :python, :ruby, :rack,
391
390
  :sybase, :frontbase, :ingres, :hsqldb, :access, :jetty, :mongodb,
392
- :aix].sort
391
+ :aix, :sql, :nosql].sort
393
392
  end
394
393
  end
395
394
 
@@ -508,6 +508,21 @@ describe Arachni::State::Framework do
508
508
  end
509
509
  end
510
510
 
511
+ describe '#done?' do
512
+ context 'when #status is :done' do
513
+ it 'returns true' do
514
+ subject.status = :done
515
+ subject.should be_done
516
+ end
517
+ end
518
+
519
+ context 'when not done' do
520
+ it 'returns false' do
521
+ subject.should_not be_done
522
+ end
523
+ end
524
+ end
525
+
511
526
  describe '#aborted' do
512
527
  it 'sets the #status to :aborted' do
513
528
  subject.aborted
@@ -14,11 +14,11 @@ describe name_from_filename do
14
14
 
15
15
  def issue_count_per_element
16
16
  {
17
- Element::Form => 3,
18
- Element::Link => 3,
19
- Element::Cookie => 3,
20
- Element::Header => 2,
21
- Element::LinkTemplate => 3
17
+ Element::Form => 4,
18
+ Element::Link => 4,
19
+ Element::Cookie => 4,
20
+ Element::Header => 3,
21
+ Element::LinkTemplate => 4
22
22
  }
23
23
  end
24
24
 
@@ -3,6 +3,10 @@ require 'spec_helper'
3
3
  describe name_from_filename do
4
4
  include_examples 'check'
5
5
 
6
+ def self.platforms
7
+ [:nosql]
8
+ end
9
+
6
10
  def self.elements
7
11
  [ Element::Form, Element::Link, Element::Cookie ]
8
12
  end
@@ -12,14 +12,27 @@ describe name_from_filename do
12
12
  Element::LinkTemplate ]
13
13
  end
14
14
 
15
- def issue_count_per_element
16
- {
17
- Element::Form => 10,
18
- Element::Link => 10,
19
- Element::Cookie => 10,
20
- Element::Header => 9,
21
- Element::LinkTemplate => 10
15
+ def issue_count_per_element_per_platform
16
+ h = {}
17
+ [:unix, :bsd, :aix].each do |platform|
18
+ h[platform] = {
19
+ Element::Form => 22,
20
+ Element::Link => 22,
21
+ Element::Cookie => 22,
22
+ Element::Header => 19,
23
+ Element::LinkTemplate => 21
24
+ }
25
+ end
26
+
27
+ h[:windows] = {
28
+ Element::Form => 44,
29
+ Element::Link => 44,
30
+ Element::Cookie => 44,
31
+ Element::Header => 38,
32
+ Element::LinkTemplate => 44
22
33
  }
34
+
35
+ h
23
36
  end
24
37
 
25
38
  easy_test
@@ -14,11 +14,11 @@ describe name_from_filename do
14
14
 
15
15
  def issue_count_per_element
16
16
  {
17
- Element::Form => 5,
18
- Element::Link => 5,
19
- Element::Cookie => 5,
20
- Element::Header => 4,
21
- Element::LinkTemplate => 4
17
+ Element::Form => 14,
18
+ Element::Link => 14,
19
+ Element::Cookie => 14,
20
+ Element::Header => 14,
21
+ Element::LinkTemplate => 14
22
22
  }
23
23
  end
24
24
 
@@ -3,6 +3,10 @@ require 'spec_helper'
3
3
  describe name_from_filename do
4
4
  include_examples 'check'
5
5
 
6
+ def self.platforms
7
+ [:sql]
8
+ end
9
+
6
10
  def self.elements
7
11
  [ Element::Form, Element::Link, Element::Cookie ]
8
12
  end
@@ -4,9 +4,8 @@ describe name_from_filename do
4
4
  include_examples 'check'
5
5
 
6
6
  def self.platforms
7
- [:access, :coldfusion, :db2, :emc, :firebird, :frontbase, :hsqldb,
8
- :informix, :ingres, :interbase, :maxdb, :mssql, :mysql, :oracle,
9
- :pgsql, :sqlite, :sybase]
7
+ [:access, :db2, :emc, :firebird, :frontbase, :hsqldb, :informix, :ingres,
8
+ :interbase, :maxdb, :mssql, :mysql, :oracle, :pgsql, :sqlite, :sybase]
10
9
  end
11
10
 
12
11
  def self.elements
@@ -244,6 +244,37 @@ get '/fire_event/form/onsubmit' do
244
244
  EOHTML
245
245
  end
246
246
 
247
+ get '/fire_event/form/select' do
248
+ <<-EOHTML
249
+ <html>
250
+ <script>
251
+ function submitForm() {
252
+ document.getElementById("container-name").innerHTML =
253
+ document.getElementsByName("name")[0].value;
254
+
255
+ document.getElementById("container-email").innerHTML =
256
+ document.getElementById("email").value;
257
+ }
258
+ </script>
259
+
260
+ <body>
261
+ <form onsubmit="submitForm();return false;">
262
+ <textarea name="name" ></textarea>
263
+ <select name="email" id="email"/>
264
+ <option value="the.other.dude@abides.com">The other Dude</option>
265
+ <option value="the.dude@abides.com">The Dude</option>
266
+ </select>
267
+ </fom>
268
+
269
+ <div id="container-name">
270
+ </div>
271
+ <div id="container-email">
272
+ </div>
273
+ </body>
274
+ </html>
275
+ EOHTML
276
+ end
277
+
247
278
  get '/fire_event/form/image-input' do
248
279
  <<HTML
249
280
  <html>
@@ -2,7 +2,7 @@ require 'sinatra'
2
2
  require 'sinatra/contrib'
3
3
 
4
4
  REGEXP = {
5
- php: 'echo\s([0-9]+)\s?\+\s?([0-9]+);',
5
+ php: 'print\s([0-9]+)\s?\+\s?([0-9]+);',
6
6
  perl: 'print\s([0-9]+)\s?\+\s?([0-9]+);',
7
7
  python: 'print\s([0-9]+)\s?\+\s?([0-9]+)$',
8
8
  asp: 'Response.Write\(\s?([0-9]+)\s?\+\s?([0-9]+)\s?\)'
@@ -17,45 +17,47 @@ def get_result( str )
17
17
  end
18
18
  end
19
19
 
20
- get '/' do
21
- <<-EOHTML
22
- <a href="/link?input=default">Link</a>
23
- <a href="/form">Form</a>
24
- <a href="/cookie">Cookie</a>
25
- <a href="/header">Header</a>
26
- EOHTML
27
- end
20
+ [:nosql].each do |platform|
21
+ get "/#{platform}" do
22
+ <<-EOHTML
23
+ <a href="/#{platform}/link?input=default">Link</a>
24
+ <a href="/#{platform}/form">Form</a>
25
+ <a href="/#{platform}/cookie">Cookie</a>
26
+ <a href="/#{platform}/header">Header</a>
27
+ EOHTML
28
+ end
28
29
 
29
- get '/link' do
30
- <<-EOHTML
31
- <a href="/link/append?input=default">Link</a>
32
- EOHTML
33
- end
30
+ get "/#{platform}/link" do
31
+ <<-EOHTML
32
+ <a href="/#{platform}/link/append?input=default">Link</a>
33
+ EOHTML
34
+ end
34
35
 
35
- get '/link/append' do
36
- get_result( params['input'] )
37
- end
36
+ get "/#{platform}/link/append" do
37
+ get_result( params['input'] )
38
+ end
38
39
 
39
- get '/form' do
40
- <<-EOHTML
41
- <form action="/form/append">
42
- <input name='input' value='default' />
43
- </form>
44
- EOHTML
45
- end
40
+ get "/#{platform}/form" do
41
+ <<-EOHTML
42
+ <form action="/#{platform}/form/append">
43
+ <input name='input' value='default' />
44
+ </form>
45
+ EOHTML
46
+ end
46
47
 
47
- get '/form/append' do
48
- get_result( params['input'] )
49
- end
48
+ get "/#{platform}/form/append" do
49
+ get_result( params['input'] )
50
+ end
50
51
 
51
52
 
52
- get '/cookie' do
53
- <<-EOHTML
54
- <a href="/cookie/append">Cookie</a>
55
- EOHTML
56
- end
53
+ get "/#{platform}/cookie" do
54
+ <<-EOHTML
55
+ <a href="/#{platform}/cookie/append">Cookie</a>
56
+ EOHTML
57
+ end
57
58
 
58
- get '/cookie/append' do
59
- cookies['cookie'] ||= default
60
- get_result( cookies['cookie'] )
59
+ get "/#{platform}/cookie/append" do
60
+ cookies['cookie'] ||= default
61
+ get_result( cookies['cookie'] )
62
+ end
61
63
  end
@@ -1,5 +1,6 @@
1
1
  require 'sinatra'
2
2
  require 'sinatra/contrib'
3
+ require_relative '../check_server'
3
4
 
4
5
  STRINGS = {
5
6
  unix: '/bin/cat /etc/passwd',
@@ -26,19 +27,12 @@ multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional"
26
27
  ',
27
28
  }
28
29
 
29
- def exec( system, str, prefix = nil, postfix = nil )
30
- OUT[system] if "#{prefix} #{STRINGS[system]}#{postfix}" == str
31
- end
32
-
33
- def variations
34
- @@v ||= [ '', '&&', '|', ';' ]
35
- end
36
-
37
30
  def get_variations( system, str )
38
- (variations.map do |v|
39
- pre, post = v.split( '%s' )
40
- exec( system, str, pre, post )
41
- end | [ exec( system, str, "`", "`" ) ] ).compact.to_s
31
+ current_check.payloads[system].each do |payload|
32
+ return OUT[system] if payload == str
33
+ end
34
+
35
+ ''
42
36
  end
43
37
 
44
38
  STRINGS.keys.each do |platform|
@@ -1,5 +1,6 @@
1
1
  require 'sinatra'
2
2
  require 'sinatra/contrib'
3
+ require_relative '../check_server'
3
4
 
4
5
  REGEXP = {
5
6
  windows: 'ping \-n (\d+) localhost',
@@ -27,10 +28,14 @@ def variations
27
28
  end
28
29
 
29
30
  def get_variations( platform, str )
30
- variations.map do |v|
31
- pre, post = v.split( '%s' )
32
- exec( platform, str, pre, post )
33
- end.compact.to_s
31
+ # current_check.payloads[platform].each do |payload|
32
+ time = str.scan( Regexp.new( REGEXP[platform] ) ).flatten.first
33
+ return if !time
34
+
35
+ sleep( Integer( time ) - 1 )
36
+ # end
37
+
38
+ ''
34
39
  end
35
40
 
36
41
  REGEXP.keys.each do |platform|
@@ -11,7 +11,7 @@ end
11
11
  @@ignore ||= IO.read( File.dirname( __FILE__ ) + '/../../../../../components/checks/active/sql_injection/regexp_ignore.txt' )
12
12
 
13
13
  def variations
14
- @@variations ||= [ '\'`--', ')' ]
14
+ @@variations ||= [ '"\'`--', ')' ]
15
15
  end
16
16
 
17
17
  def get_variations( platform, str )