arachni 1.0.5 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,187 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arachni::Framework::Parts::Data do
4
+ include_examples 'framework'
5
+
6
+ describe '#data' do
7
+ it "returns #{Arachni::Data::Framework}" do
8
+ subject.data.should be_kind_of Arachni::Data::Framework
9
+ end
10
+ end
11
+
12
+ describe '#sitemap' do
13
+ it 'returns a hash with covered URLs and HTTP status codes' do
14
+ Arachni::Framework.new do |f|
15
+ f.options.url = "#{@url}/"
16
+ f.options.audit.elements :links, :forms, :cookies
17
+ f.checks.load :taint
18
+
19
+ f.run
20
+ f.sitemap.should == { "#{@url}/" => 200 }
21
+ end
22
+ end
23
+ end
24
+
25
+ describe '#push_to_page_queue' do
26
+ let(:page) { Arachni::Page.from_url( @url + '/train/true' ) }
27
+
28
+ it 'pushes it to the page audit queue and returns true' do
29
+ subject.options.audit.elements :links, :forms, :cookies
30
+ subject.checks.load :taint
31
+
32
+ subject.page_queue_total_size.should == 0
33
+ subject.push_to_page_queue( page ).should be_true
34
+ subject.run
35
+
36
+ subject.report.issues.size.should == 1
37
+ subject.page_queue_total_size.should > 0
38
+ end
39
+
40
+ it 'updates the #sitemap with the DOM URL' do
41
+ subject.options.audit.elements :links, :forms, :cookies
42
+ subject.checks.load :taint
43
+
44
+ subject.sitemap.should be_empty
45
+
46
+ page = Arachni::Page.from_url( @url + '/link' )
47
+ page.dom.url = @url + '/link/#/stuff'
48
+
49
+ subject.push_to_page_queue page
50
+ subject.sitemap.should include @url + '/link/#/stuff'
51
+ end
52
+
53
+ it "passes it to #{Arachni::ElementFilter}#update_from_page_cache" do
54
+ page = Arachni::Page.from_url( @url + '/link' )
55
+
56
+ Arachni::ElementFilter.should receive(:update_from_page_cache).with(page)
57
+
58
+ subject.push_to_page_queue page
59
+ end
60
+
61
+ context 'when the page has already been seen' do
62
+ it 'ignores it' do
63
+ page = Arachni::Page.from_url( @url + '/stuff' )
64
+
65
+ subject.page_queue_total_size.should == 0
66
+ subject.push_to_page_queue( page )
67
+ subject.push_to_page_queue( page )
68
+ subject.push_to_page_queue( page )
69
+ subject.page_queue_total_size.should == 1
70
+ end
71
+
72
+ it 'returns false' do
73
+ page = Arachni::Page.from_url( @url + '/stuff' )
74
+
75
+ subject.page_queue_total_size.should == 0
76
+ subject.push_to_page_queue( page ).should be_true
77
+ subject.push_to_page_queue( page ).should be_false
78
+ subject.push_to_page_queue( page ).should be_false
79
+ subject.page_queue_total_size.should == 1
80
+ end
81
+ end
82
+
83
+ context 'when #accepts_more_pages?' do
84
+ context false do
85
+ it 'returns false' do
86
+ subject.stub(:accepts_more_pages?) { false }
87
+ subject.push_to_page_queue( page ).should be_false
88
+ end
89
+ end
90
+
91
+ context true do
92
+ it 'returns true' do
93
+ subject.stub(:accepts_more_pages?) { true }
94
+ subject.push_to_page_queue( page ).should be_true
95
+ end
96
+ end
97
+ end
98
+
99
+ context "when #{Arachni::Page::Scope}#out? is true" do
100
+ it 'returns false' do
101
+ Arachni::Page::Scope.any_instance.stub(:out?) { true }
102
+ subject.push_to_page_queue( page ).should be_false
103
+ end
104
+ end
105
+
106
+ context "when #{Arachni::URI::Scope}#redundant? is true" do
107
+ it 'returns false' do
108
+ Arachni::Page::Scope.any_instance.stub(:redundant?) { true }
109
+ subject.push_to_page_queue( page ).should be_false
110
+ end
111
+ end
112
+
113
+ context "when #{Arachni::Page::Scope}#auto_redundant? is true" do
114
+ it 'returns false' do
115
+ Arachni::Page::Scope.any_instance.stub(:auto_redundant?) { true }
116
+ subject.push_to_page_queue( page ).should be_false
117
+ end
118
+ end
119
+ end
120
+
121
+ describe '#push_to_url_queue' do
122
+ it 'pushes a URL to the URL audit queue' do
123
+ subject.options.audit.elements :links, :forms, :cookies
124
+ subject.checks.load :taint
125
+
126
+ subject.url_queue_total_size.should == 0
127
+ subject.push_to_url_queue( @url + '/link' ).should be_true
128
+ subject.run
129
+
130
+ subject.report.issues.size.should == 1
131
+ subject.url_queue_total_size.should == 3
132
+ end
133
+
134
+ context 'when the URL has already been seen' do
135
+ it 'returns false' do
136
+ subject.push_to_url_queue( @url + '/link' ).should be_true
137
+ subject.push_to_url_queue( @url + '/link' ).should be_false
138
+ end
139
+
140
+ it 'ignores it' do
141
+ subject.url_queue_total_size.should == 0
142
+ subject.push_to_url_queue( @url + '/link' )
143
+ subject.push_to_url_queue( @url + '/link' )
144
+ subject.push_to_url_queue( @url + '/link' )
145
+ subject.url_queue_total_size.should == 1
146
+ end
147
+ end
148
+
149
+ context 'when #accepts_more_pages?' do
150
+ context false do
151
+ it 'returns false' do
152
+ subject.stub(:accepts_more_pages?) { false }
153
+ subject.push_to_url_queue( @url ).should be_false
154
+ end
155
+ end
156
+
157
+ context true do
158
+ it 'returns true' do
159
+ subject.stub(:accepts_more_pages?) { true }
160
+ subject.push_to_url_queue( @url ).should be_true
161
+ end
162
+ end
163
+ end
164
+
165
+ context "when #{Arachni::URI::Scope}#out? is true" do
166
+ it 'returns false' do
167
+ Arachni::URI::Scope.any_instance.stub(:out?) { true }
168
+ subject.push_to_url_queue( @url ).should be_false
169
+ end
170
+ end
171
+
172
+ context "when #{Arachni::URI::Scope}#redundant? is true" do
173
+ it 'returns false' do
174
+ Arachni::URI::Scope.any_instance.stub(:redundant?) { true }
175
+ subject.push_to_url_queue( @url ).should be_false
176
+ end
177
+ end
178
+
179
+ context "when #{Arachni::URI::Scope}#auto_redundant? is true" do
180
+ it 'returns false' do
181
+ Arachni::URI::Scope.any_instance.stub(:auto_redundant?) { true }
182
+ subject.push_to_url_queue( @url ).should be_false
183
+ end
184
+ end
185
+ end
186
+
187
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arachni::Framework::Parts::Platform do
4
+ include_examples 'framework'
5
+
6
+ describe '#list_platforms' do
7
+ it 'returns information about all valid platforms' do
8
+ subject.list_platforms.should == {
9
+ 'Operating systems' => {
10
+ unix: 'Generic Unix family',
11
+ linux: 'Linux',
12
+ bsd: 'Generic BSD family',
13
+ aix: 'IBM AIX',
14
+ solaris: 'Solaris',
15
+ windows: 'MS Windows'
16
+ },
17
+ 'Databases' => {
18
+ sql: 'Generic SQL family',
19
+ access: 'MS Access',
20
+ db2: 'DB2',
21
+ emc: 'EMC',
22
+ firebird: 'Firebird',
23
+ frontbase: 'Frontbase',
24
+ hsqldb: 'HSQLDB',
25
+ informix: 'Informix',
26
+ ingres: 'IngresDB',
27
+ interbase: 'InterBase',
28
+ maxdb: 'SaP Max DB',
29
+ mssql: 'MSSQL',
30
+ mysql: 'MySQL',
31
+ oracle: 'Oracle',
32
+ pgsql: 'Postgresql',
33
+ sqlite: 'SQLite',
34
+ sybase: 'Sybase',
35
+ nosql: 'Generic NoSQL family',
36
+ mongodb: 'MongoDB'
37
+ },
38
+ 'Web servers' => {
39
+ apache: 'Apache',
40
+ iis: 'IIS',
41
+ jetty: 'Jetty',
42
+ nginx: 'Nginx',
43
+ tomcat: 'TomCat'
44
+ },
45
+ 'Programming languages' => {
46
+ asp: 'ASP',
47
+ aspx: 'ASP.NET',
48
+ jsp: 'JSP',
49
+ perl: 'Perl',
50
+ php: 'PHP',
51
+ python: 'Python',
52
+ ruby: 'Ruby'
53
+ },
54
+ 'Frameworks' => {
55
+ rack: 'Rack'
56
+ }
57
+ }
58
+
59
+ end
60
+ end
61
+
62
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arachni::Framework::Parts::Plugin do
4
+ include_examples 'framework'
5
+
6
+ describe '#plugins' do
7
+ it 'provides access to the plugin manager' do
8
+ subject.plugins.is_a?( Arachni::Plugin::Manager ).should be_true
9
+ subject.plugins.available.sort.should ==
10
+ %w(wait bad with_options distributable loop default suspendable).sort
11
+ end
12
+ end
13
+
14
+ describe '#list_plugins' do
15
+ it 'returns info on all plugins' do
16
+ subject.list_plugins.size.should == subject.plugins.available.size
17
+
18
+ info = subject.list_plugins.find { |p| p[:options].any? }
19
+ plugin = subject.plugins[info[:shortname]]
20
+
21
+ plugin.info.each do |k, v|
22
+ if k == :author
23
+ info[k].should == [v].flatten
24
+ next
25
+ end
26
+
27
+ info[k].should == v
28
+ end
29
+
30
+ info[:shortname].should == plugin.shortname
31
+ end
32
+
33
+ context 'when a pattern is given' do
34
+ it 'uses it to filter out plugins that do not match it' do
35
+ subject.list_plugins( 'bad|foo' ).size == 2
36
+ subject.list_plugins( 'boo' ).size == 0
37
+ end
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arachni::Framework::Parts::Report do
4
+ include_examples 'framework'
5
+
6
+ describe '#reporters' do
7
+ it 'provides access to the reporter manager' do
8
+ subject.reporters.is_a?( Arachni::Reporter::Manager ).should be_true
9
+ subject.reporters.available.sort.should == %w(afr foo).sort
10
+ end
11
+ end
12
+
13
+ describe '#list_reporters' do
14
+ it 'returns info on all reporters' do
15
+ subject.list_reporters.size.should == subject.reporters.available.size
16
+
17
+ info = subject.list_reporters.find { |p| p[:options].any? }
18
+ report = subject.reporters[info[:shortname]]
19
+
20
+ report.info.each do |k, v|
21
+ if k == :author
22
+ info[k].should == [v].flatten
23
+ next
24
+ end
25
+
26
+ info[k].should == v
27
+ end
28
+
29
+ info[:shortname].should == report.shortname
30
+ end
31
+
32
+ context 'when a pattern is given' do
33
+ it 'uses it to filter out reporters that do not match it' do
34
+ subject.list_reporters( 'foo' ).size == 1
35
+ subject.list_reporters( 'boo' ).size == 0
36
+ end
37
+ end
38
+ end
39
+
40
+ describe '#report_as' do
41
+ before( :each ) do
42
+ reset_options
43
+ @new_framework = Arachni::Framework.new
44
+ end
45
+
46
+ context 'when passed a valid reporter name' do
47
+ it 'returns the reporter as a string' do
48
+ json = @new_framework.report_as( :json )
49
+ JSON.load( json )['issues'].size.should == @new_framework.report.issues.size
50
+ end
51
+
52
+ context 'which does not support the \'outfile\' option' do
53
+ it 'raises Arachni::Component::Options::Error::Invalid' do
54
+ expect { @new_framework.report_as( :stdout ) }.to raise_error Arachni::Component::Options::Error::Invalid
55
+ end
56
+ end
57
+ end
58
+
59
+ context 'when passed an invalid reporter name' do
60
+ it 'raises Arachni::Component::Error::NotFound' do
61
+ expect { @new_framework.report_as( :blah ) }.to raise_error Arachni::Component::Error::NotFound
62
+ end
63
+ end
64
+ end
65
+
66
+ end
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arachni::Framework::Parts::Scope do
4
+ include_examples 'framework'
5
+
6
+ describe '#page_limit_reached?' do
7
+ context "when the #{Arachni::OptionGroups::Scope}#page_limit has" do
8
+ context 'been reached' do
9
+ it 'returns true' do
10
+ Arachni::Framework.new do |f|
11
+ f.options.url = web_server_url_for :framework_multi
12
+ f.options.audit.elements :links
13
+ f.options.scope.page_limit = 10
14
+
15
+ f.page_limit_reached?.should be_false
16
+ f.run
17
+ f.page_limit_reached?.should be_true
18
+
19
+ f.sitemap.size.should == 10
20
+ end
21
+ end
22
+ end
23
+
24
+ context 'not been reached' do
25
+ it 'returns false' do
26
+ Arachni::Framework.new do |f|
27
+ f.options.url = web_server_url_for :framework
28
+ f.options.audit.elements :links
29
+ f.options.scope.page_limit = 100
30
+
31
+ f.checks.load :taint
32
+
33
+ f.page_limit_reached?.should be_false
34
+ f.run
35
+ f.page_limit_reached?.should be_false
36
+ end
37
+ end
38
+ end
39
+
40
+ context 'not been set' do
41
+ it 'returns false' do
42
+ Arachni::Framework.new do |f|
43
+ f.options.url = web_server_url_for :framework
44
+ f.options.audit.elements :links
45
+
46
+ f.checks.load :taint
47
+
48
+ f.page_limit_reached?.should be_false
49
+ f.run
50
+ f.page_limit_reached?.should be_false
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ describe '#accepts_more_pages?' do
58
+ context 'when #page_limit_reached? and #crawl?' do
59
+ it 'return true' do
60
+ subject.stub(:page_limit_reached?) { false }
61
+ subject.stub(:crawl?) { true }
62
+
63
+ subject.accepts_more_pages?.should be_true
64
+ end
65
+ end
66
+
67
+ context 'when #page_limit_reached?' do
68
+ context true do
69
+ it 'returns false' do
70
+ subject.stub(:page_limit_reached?) { true }
71
+ subject.accepts_more_pages?.should be_false
72
+ end
73
+ end
74
+ end
75
+
76
+ context 'when #crawl?' do
77
+ context false do
78
+ it 'returns false' do
79
+ subject.stub(:crawl?) { false }
80
+ subject.accepts_more_pages?.should be_false
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ end
@@ -0,0 +1,528 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arachni::Framework::Parts::State do
4
+ include_examples 'framework'
5
+
6
+ describe '#scanning?' do
7
+ it "delegates to #{Arachni::State::Framework}#scanning?" do
8
+ subject.state.stub(:scanning?) { :stuff }
9
+ subject.scanning?.should == :stuff
10
+ end
11
+ end
12
+
13
+ describe '#done?' do
14
+ it "delegates to #{Arachni::State::Framework}#done?" do
15
+ subject.state.stub(:done?) { :stuff }
16
+ subject.done?.should == :stuff
17
+ end
18
+ end
19
+
20
+ describe '#paused?' do
21
+ it "delegates to #{Arachni::State::Framework}#paused?" do
22
+ subject.state.stub(:paused?) { :stuff }
23
+ subject.paused?.should == :stuff
24
+ end
25
+ end
26
+
27
+ describe '#state' do
28
+ it "returns #{Arachni::State::Framework}" do
29
+ subject.state.should be_kind_of Arachni::State::Framework
30
+ end
31
+ end
32
+
33
+ describe '#abort' do
34
+ it 'aborts the system' do
35
+ @options.paths.checks = fixtures_path + '/taint_check/'
36
+
37
+ Arachni::Framework.new do |f|
38
+ f.options.url = web_server_url_for :framework_multi
39
+ f.options.audit.elements :links
40
+
41
+ f.plugins.load :wait
42
+ f.checks.load :taint
43
+
44
+ t = Thread.new do
45
+ f.run
46
+ end
47
+
48
+ sleep 0.1 while Arachni::Data.issues.size < 2
49
+
50
+ f.abort
51
+ t.join
52
+
53
+ Arachni::Data.issues.size.should < 500
54
+ end
55
+ end
56
+
57
+ it 'sets #status to :aborted' do
58
+ Arachni::Framework.new do |f|
59
+ f.options.url = web_server_url_for :framework_multi
60
+ f.options.audit.elements :links
61
+ f.checks.load :taint
62
+
63
+ t = Thread.new do
64
+ f.run
65
+ end
66
+ sleep 0.1 while f.status != :scanning
67
+
68
+ f.abort
69
+ f.status.should == :aborted
70
+
71
+ t.join
72
+ f.status.should == :aborted
73
+ end
74
+ end
75
+ end
76
+
77
+ describe '#suspend' do
78
+ it 'suspends the system' do
79
+ @options.paths.checks = fixtures_path + '/taint_check/'
80
+
81
+ Arachni::Framework.new do |f|
82
+ f.options.url = web_server_url_for :framework_multi
83
+ f.options.audit.elements :links
84
+
85
+ f.plugins.load :wait
86
+ f.checks.load :taint
87
+
88
+ t = Thread.new do
89
+ f.run
90
+ end
91
+
92
+ sleep 0.1 while Arachni::Data.issues.size < 2
93
+
94
+ @snapshot = f.suspend
95
+ t.join
96
+
97
+ Arachni::Data.issues.size.should < 500
98
+ end
99
+
100
+ Arachni::Snapshot.load( @snapshot ).should be_true
101
+ end
102
+
103
+ it 'sets #status to :suspended' do
104
+ Arachni::Framework.new do |f|
105
+ f.options.url = web_server_url_for :framework_multi
106
+ f.options.audit.elements :links
107
+ f.checks.load :taint
108
+
109
+ t = Thread.new do
110
+ f.run
111
+ end
112
+ sleep 0.1 while f.status != :scanning
113
+
114
+ @snapshot = f.suspend
115
+ f.status.should == :suspended
116
+
117
+ t.join
118
+ f.status.should == :suspended
119
+ end
120
+ end
121
+
122
+ it 'suspends plugins' do
123
+ Arachni::Options.plugins['suspendable'] = {
124
+ 'my_option' => 'my value'
125
+ }
126
+
127
+ Arachni::Framework.new do |f|
128
+ f.options.url = web_server_url_for :framework_multi
129
+ f.options.audit.elements :links
130
+
131
+ f.checks.load :taint
132
+ f.plugins.load :suspendable
133
+
134
+ t = Thread.new do
135
+ f.run
136
+ end
137
+
138
+ sleep 0.1 while f.status != :scanning
139
+
140
+ f.suspend
141
+ t.join
142
+
143
+ Arachni::State.plugins.runtime[:suspendable][:data].should == 1
144
+ end
145
+ end
146
+
147
+ it 'waits for the BrowserCluster jobs to finish'
148
+
149
+ context "when #{Arachni::OptionGroups::Snapshot}#save_path" do
150
+ context 'is a directory' do
151
+ it 'stores the snapshot under it' do
152
+ @options.paths.checks = fixtures_path + '/taint_check/'
153
+ @options.snapshot.save_path = Dir.tmpdir
154
+
155
+ Arachni::Framework.new do |f|
156
+ f.options.url = web_server_url_for :framework_multi
157
+ f.options.audit.elements :links
158
+
159
+ f.plugins.load :wait
160
+ f.checks.load :taint
161
+
162
+ t = Thread.new do
163
+ f.run
164
+ end
165
+
166
+ sleep 0.1 while Arachni::Data.issues.size < 2
167
+
168
+ @snapshot = f.suspend
169
+ t.join
170
+
171
+ Arachni::Data.issues.size.should < 500
172
+ end
173
+
174
+ File.dirname( @snapshot ).should == Dir.tmpdir
175
+ Arachni::Snapshot.load( @snapshot ).should be_true
176
+ end
177
+ end
178
+
179
+ context 'is a file path' do
180
+ it 'stores the snapshot there' do
181
+ @options.paths.checks = fixtures_path + '/taint_check/'
182
+ @options.snapshot.save_path = "#{Dir.tmpdir}/snapshot"
183
+
184
+ Arachni::Framework.new do |f|
185
+ f.options.url = web_server_url_for :framework_multi
186
+ f.options.audit.elements :links
187
+
188
+ f.plugins.load :wait
189
+ f.checks.load :taint
190
+
191
+ t = Thread.new do
192
+ f.run
193
+ end
194
+
195
+ sleep 0.1 while Arachni::Data.issues.size < 2
196
+
197
+ @snapshot = f.suspend
198
+ t.join
199
+
200
+ Arachni::Data.issues.size.should < 500
201
+ end
202
+
203
+ @snapshot.should == "#{Dir.tmpdir}/snapshot"
204
+ Arachni::Snapshot.load( @snapshot ).should be_true
205
+ end
206
+ end
207
+ end
208
+ end
209
+
210
+ describe '#restore' do
211
+ it 'restores a suspended scan' do
212
+ @options.paths.checks = fixtures_path + '/taint_check/'
213
+
214
+ logged_issues = 0
215
+ Arachni::Framework.new do |f|
216
+ f.options.url = web_server_url_for :framework_multi
217
+ f.options.audit.elements :links
218
+
219
+ f.plugins.load :wait
220
+ f.checks.load :taint
221
+
222
+ Arachni::Data.issues.on_new do
223
+ logged_issues += 1
224
+ end
225
+
226
+ t = Thread.new do
227
+ f.run
228
+ end
229
+
230
+ sleep 0.1 while logged_issues < 200
231
+
232
+ @snapshot = f.suspend
233
+ t.join
234
+
235
+ logged_issues.should < 500
236
+ end
237
+
238
+ reset_options
239
+ @options.paths.checks = fixtures_path + '/taint_check/'
240
+
241
+ Arachni::Framework.new do |f|
242
+ f.restore @snapshot
243
+
244
+ Arachni::Data.issues.on_new do
245
+ logged_issues += 1
246
+ end
247
+ f.run
248
+
249
+ # logged_issues.should == 500
250
+ Arachni::Data.issues.size.should == 500
251
+
252
+ f.report.plugins[:wait][:results].should == { 'stuff' => true }
253
+ end
254
+ end
255
+
256
+ it 'restores options' do
257
+ options_hash = nil
258
+
259
+ Arachni::Framework.new do |f|
260
+ f.options.url = @url + '/with_ajax'
261
+ f.options.audit.elements :links, :forms, :cookies
262
+ f.options.datastore.my_custom_option = 'my custom value'
263
+ options_hash = f.options.update( f.options.to_rpc_data ).to_h.deep_clone
264
+
265
+ f.checks.load :taint
266
+
267
+ t = Thread.new { f.run }
268
+
269
+ sleep 0.1 while f.browser_cluster.done?
270
+ @snapshot = f.suspend
271
+
272
+ t.join
273
+ end
274
+
275
+ Arachni::Framework.restore( @snapshot ) do |f|
276
+ f.options.to_h.should == options_hash.merge( checks: ['taint'] )
277
+ f.browser_job_skip_states.should be_any
278
+ end
279
+ end
280
+
281
+ it 'restores BrowserCluster skip states' do
282
+ Arachni::Framework.new do |f|
283
+ f.options.url = @url + '/with_ajax'
284
+ f.options.audit.elements :links, :forms, :cookies
285
+
286
+ f.checks.load :taint
287
+
288
+ t = Thread.new { f.run }
289
+
290
+ sleep 0.1 while f.browser_cluster.done?
291
+ @snapshot = f.suspend
292
+
293
+ t.join
294
+ end
295
+
296
+ Arachni::Framework.restore( @snapshot ) do |f|
297
+ f.browser_job_skip_states.should be_any
298
+ end
299
+ end
300
+
301
+ it 'restores loaded checks' do
302
+ Arachni::Framework.new do |f|
303
+ f.options.url = @url
304
+ f.checks.load :taint
305
+
306
+ t = Thread.new { f.run }
307
+ sleep 0.1 while f.status != :scanning
308
+
309
+ @snapshot = f.suspend
310
+
311
+ t.join
312
+ end
313
+
314
+ Arachni::Framework.restore( @snapshot ) do |f|
315
+ f.checks.loaded.should == ['taint']
316
+ end
317
+ end
318
+
319
+ it 'restores loaded plugins' do
320
+ Arachni::Framework.new do |f|
321
+ f.options.url = @url
322
+ f.plugins.load :wait
323
+
324
+ t = Thread.new { f.run }
325
+ sleep 0.1 while f.status != :scanning
326
+
327
+ @snapshot = f.suspend
328
+ t.join
329
+ end
330
+
331
+ Arachni::Framework.restore( @snapshot ) do |f|
332
+ f.plugins.loaded.should == ['wait']
333
+ end
334
+ end
335
+
336
+ it 'restores plugin states' do
337
+ Arachni::Options.plugins['suspendable'] = {
338
+ 'my_option' => 'my value'
339
+ }
340
+
341
+ Arachni::Framework.new do |f|
342
+ f.options.url = web_server_url_for :framework_multi
343
+ f.options.audit.elements :links
344
+
345
+ f.checks.load :taint
346
+ f.plugins.load :suspendable
347
+
348
+ t = Thread.new do
349
+ f.run
350
+ end
351
+
352
+ sleep 0.1 while f.status != :scanning
353
+
354
+ @snapshot = f.suspend
355
+ t.join
356
+
357
+ Arachni::State.plugins.runtime[:suspendable][:data].should == 1
358
+ end
359
+
360
+ Arachni::Framework.restore( @snapshot ) do |f|
361
+ t = Thread.new do
362
+ f.run
363
+ end
364
+
365
+ sleep 0.1 while f.status != :scanning
366
+
367
+ f.plugins.jobs[:suspendable][:instance].counter.should == 2
368
+
369
+ f.abort
370
+ t.join
371
+ end
372
+ end
373
+ end
374
+
375
+ describe '#pause' do
376
+ it 'pauses the system' do
377
+ Arachni::Framework.new do |f|
378
+ f.options.url = @url + '/elem_combo'
379
+ f.options.audit.elements :links, :forms, :cookies
380
+ f.checks.load :taint
381
+
382
+ t = Thread.new do
383
+ f.run
384
+ end
385
+
386
+ f.pause
387
+
388
+ sleep 10
389
+
390
+ f.running?.should be_true
391
+ t.kill
392
+ end
393
+ end
394
+
395
+ it 'returns an Integer request ID' do
396
+ Arachni::Framework.new do |f|
397
+ f.options.url = @url + '/elem_combo'
398
+ f.options.audit.elements :links, :forms, :cookies
399
+ f.checks.load :taint
400
+
401
+ t = Thread.new do
402
+ f.run
403
+ end
404
+
405
+ f.pause.should be_kind_of Integer
406
+
407
+ sleep 10
408
+
409
+ f.running?.should be_true
410
+ t.kill
411
+ end
412
+ end
413
+
414
+ it 'sets #status to :paused' do
415
+ Arachni::Framework.new do |f|
416
+ f.options.url = @url + '/elem_combo'
417
+ f.options.audit.elements :links, :forms, :cookies
418
+ f.checks.load :taint
419
+
420
+ t = Thread.new do
421
+ f.run
422
+ end
423
+ sleep 0.1 while f.status != :scanning
424
+
425
+ f.pause
426
+ f.status.should == :paused
427
+
428
+ t.kill
429
+ end
430
+ end
431
+ end
432
+
433
+ describe '#resume' do
434
+ it 'resumes the system' do
435
+ Arachni::Framework.new do |f|
436
+ f.options.url = @url + '/elem_combo'
437
+ f.options.audit.elements :links, :forms, :cookies
438
+ f.checks.load :taint
439
+
440
+ t = Thread.new do
441
+ f.run
442
+ end
443
+
444
+ id = f.pause
445
+
446
+ sleep 10
447
+
448
+ f.running?.should be_true
449
+ f.resume id
450
+ t.join
451
+ end
452
+ end
453
+
454
+ it 'sets #status to scanning' do
455
+ Arachni::Framework.new do |f|
456
+ f.options.url = @url + '/elem_combo'
457
+ f.options.audit.elements :links, :forms, :cookies
458
+ f.checks.load :taint
459
+
460
+ t = Thread.new do
461
+ f.run
462
+ end
463
+
464
+ id = f.pause
465
+ f.status.should == :paused
466
+
467
+ f.resume id
468
+ Timeout.timeout( 5 ) do
469
+ sleep 0.1 while f.status != :scanning
470
+ end
471
+ t.join
472
+ end
473
+ end
474
+ end
475
+
476
+ describe '#clean_up' do
477
+ it 'stops the #plugins' do
478
+ Arachni::Framework.new do |f|
479
+ f.options.url = @url + '/elem_combo'
480
+ f.plugins.load :wait
481
+
482
+ f.plugins.run
483
+ f.clean_up
484
+ f.plugins.jobs.should be_empty
485
+ end
486
+ end
487
+
488
+ it 'sets the status to cleanup' do
489
+ Arachni::Framework.new do |f|
490
+ f.options.url = @url + '/elem_combo'
491
+
492
+ f.clean_up
493
+ f.status.should == :cleanup
494
+ end
495
+ end
496
+
497
+ it 'clears the page queue' do
498
+ Arachni::Framework.new do |f|
499
+ f.options.url = @url + '/elem_combo'
500
+ f.push_to_page_queue Arachni::Page.from_url( f.options.url )
501
+
502
+ f.data.page_queue.should_not be_empty
503
+ f.clean_up
504
+ f.data.page_queue.should be_empty
505
+ end
506
+ end
507
+
508
+ it 'clears the URL queue' do
509
+ Arachni::Framework.new do |f|
510
+ f.options.url = @url + '/elem_combo'
511
+ f.push_to_url_queue f.options.url
512
+
513
+ f.data.url_queue.should_not be_empty
514
+ f.clean_up
515
+ f.data.url_queue.should be_empty
516
+ end
517
+ end
518
+
519
+ it 'sets #running? to false' do
520
+ Arachni::Framework.new do |f|
521
+ f.options.url = @url + '/elem_combo'
522
+ f.clean_up
523
+ f.should_not be_running
524
+ end
525
+ end
526
+ end
527
+
528
+ end