arachni 1.0.4 → 1.0.5

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -0
  3. data/README.md +8 -4
  4. data/bin/arachni_console +1 -1
  5. data/components/checks/active/no_sql_injection.rb +4 -4
  6. data/components/checks/passive/common_directories/directories.txt +1 -0
  7. data/components/checks/passive/common_files/filenames.txt +1 -0
  8. data/components/plugins/login_script.rb +156 -0
  9. data/components/reporters/plugin_formatters/html/login_script.rb +48 -0
  10. data/components/reporters/plugin_formatters/stdout/login_script.rb +23 -0
  11. data/components/reporters/plugin_formatters/xml/login_script.rb +26 -0
  12. data/components/reporters/xml/schema.xsd +17 -0
  13. data/lib/arachni/browser.rb +7 -4
  14. data/lib/arachni/browser/javascript.rb +40 -4
  15. data/lib/arachni/browser/javascript/proxy.rb +1 -1
  16. data/lib/arachni/browser_cluster/worker.rb +14 -4
  17. data/lib/arachni/check/auditor.rb +24 -7
  18. data/lib/arachni/check/manager.rb +6 -0
  19. data/lib/arachni/framework.rb +54 -6
  20. data/lib/arachni/http/client.rb +41 -23
  21. data/lib/arachni/http/headers.rb +5 -1
  22. data/lib/arachni/http/message.rb +0 -7
  23. data/lib/arachni/http/request.rb +40 -32
  24. data/lib/arachni/http/response.rb +8 -1
  25. data/lib/arachni/platform/manager.rb +7 -0
  26. data/lib/arachni/rpc/server/framework/multi_instance.rb +1 -1
  27. data/lib/arachni/session.rb +88 -58
  28. data/lib/arachni/state/framework.rb +34 -5
  29. data/lib/arachni/support/profiler.rb +2 -0
  30. data/lib/arachni/uri.rb +2 -1
  31. data/lib/version +1 -1
  32. data/spec/arachni/browser/javascript_spec.rb +15 -0
  33. data/spec/arachni/check/manager_spec.rb +17 -0
  34. data/spec/arachni/framework_spec.rb +4 -2
  35. data/spec/arachni/http/client_spec.rb +1 -1
  36. data/spec/arachni/session_spec.rb +80 -37
  37. data/spec/arachni/state/framework_spec.rb +34 -1
  38. data/spec/arachni/uri_spec.rb +7 -0
  39. data/spec/components/plugins/login_script_spec.rb +157 -0
  40. data/spec/support/servers/plugins/login_script.rb +13 -0
  41. data/ui/cli/output.rb +26 -9
  42. metadata +11 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 99e76bd9a28d81d3b89c8a4544dad6a6ccbe5c54
4
- data.tar.gz: 4c204ffb2b1b72f3820cda0b58681a073c9234de
3
+ metadata.gz: 113357f2e377065a79df18200488cc13fe744b6d
4
+ data.tar.gz: 41739b4e27d567d15f67f9ed86c571c24143c3a0
5
5
  SHA512:
6
- metadata.gz: 514fcc4191723fcfd0ef82355f19555ed4d21efab9cb8f6e3fd7a388aff526e8550919dbc16c18137f7310d22c30614ad165a63d0f399de36c8ddecdad9cb6e0
7
- data.tar.gz: 1eca14df793d96453809d737ad229f36632eab832e1482801ec6a1a98f78de7f6f2ee30992f694b00056658ad9e23e788496af3c0da18fbdc6d953f738859d4d
6
+ metadata.gz: 0418e763e4b5577d1d6856cbbf3cdc242ba04525e10de155b4b86484e6208acdf78cea104e0ce9e75a44aab73fb8e7d40c10be0459d58811b8f7a83b6b4971e1
7
+ data.tar.gz: 2ab357a8d52233a026374d1f0bd09ba03d8ebffa9d939d8a97f51bf76c638e95362c1f080b6ed78c54e630d1a13a0c4ddd90dbe61555259dddef762d3a3385e3
@@ -1,5 +1,47 @@
1
1
  # ChangeLog
2
2
 
3
+ ## 1.0.5 _(November 14, 2014)_
4
+
5
+ - Executables
6
+ - `arachni_console` -- Require the UI::Output interface after Arachni.
7
+ - Error log
8
+ - Redacted HTTP authentication credentials.
9
+ - `Session`
10
+ - Added `#record_login_sequence`, allowing for arbitrary login sequences to
11
+ be stored and replayed.
12
+ - `URI`
13
+ - `#domain` -- Fixed `nil` error on missing host.
14
+ - `.query_parameters` -- Recode query string before parsing to fix encoding errors.
15
+ - `UI::Output`
16
+ - `#log_error` -- Store errors in memory, as well as in logfile.
17
+ - `RPC::Server::Framework::MultiInstance`
18
+ - `#errors` -- Return errors from memory buffer instead of logfile, to
19
+ prevent "Too many open file" exceptions.
20
+ - ` Framework`
21
+ - `#audit_page` -- Keep track of checked elements at the `Framework` level
22
+ too and remove them from pages.
23
+ - `Browser`
24
+ - Fixed `nil` error on failed process spawn.
25
+ - `Javascript` -- Updated to preload and cache script sources to avoid
26
+ hitting the disk in order to prevent "Too many open file" exceptions.
27
+ - `#run_without_elements` -- Runs a script but unwraps `Watir` elements.
28
+ - `Proxy` -- Updated to use `#run_without_elements`.
29
+ - `BrowserCluster::Worker`
30
+ - Print error message on failure to respawn.
31
+ - `Check::Auditor` -- Updated audit helpers to mark elements as audited at the
32
+ check component level, to avoid sending redundant workload to the analysis
33
+ classes only to be ignored there.
34
+ - `#skip?` -- Optimized redundant issue checks.
35
+ - Checks
36
+ - Active
37
+ - `no_sql_injection` -- Updated payloads to be per platform.
38
+ - Passive
39
+ - `common_files` -- Added more filenames. [PR #504]
40
+ - Plugins
41
+ - Added
42
+ - `login_script` -- Exposes a Watir WebDriver interface to an external
43
+ script in order to allow for arbitrary login sequences.
44
+
3
45
  ## 1.0.4 _(October 25, 2014)_
4
46
 
5
47
  - CLI options
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  <table>
4
4
  <tr>
5
5
  <th>Version</th>
6
- <td>1.0.4</td>
6
+ <td>1.0.5</td>
7
7
  </tr>
8
8
  <tr>
9
9
  <th>Homepage</th>
@@ -121,7 +121,7 @@ you with its findings.
121
121
  - Proxy authentication.
122
122
  - Site authentication (Automated form-based, Cookie-Jar, Basic-Digest, NTLMv1 and others).
123
123
  - Automatic log-out detection and re-login during the scan (when the initial
124
- login was performed via the `autologin` or `proxy` plugins).
124
+ login was performed via the `autologin`, `login_script` or `proxy` plugins).
125
125
  - Custom 404 page detection.
126
126
  - UI abstraction:
127
127
  - [Command-line Interface](https://github.com/Arachni/arachni/wiki/Executables).
@@ -419,7 +419,10 @@ Active checks engage the web application via its inputs.
419
419
  - Path XSS (`xss_path`).
420
420
  - XSS in event attributes of HTML elements (`xss_event`).
421
421
  - XSS in HTML tags (`xss_tag`).
422
- - XSS in "script" context (`xss_script_context`).
422
+ - XSS in script context (`xss_script_context`).
423
+ - DOM XSS (`xss_dom`).
424
+ - DOM XSS inputs (`xss_dom_inputs`).
425
+ - DOM XSS script context (`xss_dom_script_context`).
423
426
  - Source code disclosure (`source_code_disclosure`)
424
427
 
425
428
  ##### Passive
@@ -475,7 +478,8 @@ core remains lean and makes it easy for anyone to add arbitrary functionality.
475
478
 
476
479
  - Passive Proxy (`proxy`) -- Analyzes requests and responses between the web app and
477
480
  the browser assisting in AJAX audits, logging-in and/or restricting the scope of the audit.
478
- - Form based AutoLogin (`autologin`).
481
+ - Form based login (`autologin`).
482
+ - Script based login (`login_script`).
479
483
  - Dictionary attacker for HTTP Auth (`http_dicattack`).
480
484
  - Dictionary attacker for form based authentication (`form_dicattack`).
481
485
  - Cookie collector (`cookie_collector`) -- Keeps track of cookies while establishing a timeline of changes.
@@ -7,8 +7,8 @@
7
7
  web site for more information on licensing and terms of use.
8
8
  =end
9
9
 
10
- require_relative '../ui/cli/output'
11
10
  require_relative '../lib/arachni'
11
+ require_relative '../ui/cli/output'
12
12
  require 'irb'
13
13
  require 'irb/completion'
14
14
 
@@ -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::NoSqlInjection < Arachni::Check::Base
12
12
 
13
13
  def self.error_patterns
@@ -31,7 +31,7 @@ class Arachni::Checks::NoSqlInjection < Arachni::Check::Base
31
31
  # Prepares the payloads that will hopefully cause the webapp to output SQL
32
32
  # error messages if included as part of an SQL query.
33
33
  def self.payloads
34
- @payloads ||= [ '\';.")' ]
34
+ @payloads ||= { mongodb: '\';.")' }
35
35
  end
36
36
 
37
37
  def self.options
@@ -57,8 +57,8 @@ NoSQL injection check, uses known DB errors to identify vulnerabilities.
57
57
  elements: [Element::Link, Element::Form, Element::Cookie,
58
58
  Element::Header, Element::LinkTemplate ],
59
59
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
60
- version: '0.1',
61
- platforms: options[:regexp].keys,
60
+ version: '0.1.1',
61
+ platforms: payloads.keys,
62
62
 
63
63
  issue: {
64
64
  name: %q{NoSQL Injection},
@@ -258,6 +258,7 @@ network
258
258
  xamp
259
259
  xampp
260
260
  lamp
261
+ phpmyadmin
261
262
  AD
262
263
  AE
263
264
  AF
@@ -19,6 +19,7 @@ config.php
19
19
  php.ini
20
20
  error_log
21
21
  elmah.axd
22
+ server-status
22
23
  WEB-INF (copy)/web.xml
23
24
  WEB-INF - Copy/web.xml
24
25
  Copy of WEB-INF/web.xml
@@ -0,0 +1,156 @@
1
+ =begin
2
+ Copyright 2010-2014 Tasos Laskos <tasos.laskos@arachni-scanner.com>
3
+
4
+ This file is part of the Arachni Framework project and is subject to
5
+ redistribution and commercial restrictions. Please see the Arachni Framework
6
+ web site for more information on licensing and terms of use.
7
+ =end
8
+
9
+ # Automated login plugin using a custom login script.
10
+ #
11
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
12
+ class Arachni::Plugins::LoginScript < Arachni::Plugin::Base
13
+
14
+ STATUSES = {
15
+ success: 'Login was successful.',
16
+ failure: 'The script was executed successfully, but the login check failed.',
17
+ error: 'A runtime error was encountered while executing the login script.',
18
+ missing_check: 'No session check was provided, either via interface options or the script.'
19
+ }
20
+
21
+ def prepare
22
+ script = IO.read( @options[:script] )
23
+ @script = proc { |browser| eval script }
24
+
25
+ framework_pause
26
+ print_info 'System paused.'
27
+ end
28
+
29
+ def run
30
+ session.record_login_sequence do |browser|
31
+ print_info 'Running the script.'
32
+ @script.call browser ? browser.watir : nil
33
+ print_info 'Execution completed.'
34
+ end
35
+
36
+ begin
37
+ session.login
38
+ rescue => e
39
+ set_status :error
40
+ print_exception e
41
+ return
42
+ end
43
+
44
+ if !session.logged_in?
45
+ set_status :failure, :error
46
+ return
47
+ end
48
+
49
+ cookies = http.cookies.inject({}){ |h, c| h.merge!( c.simple ) }
50
+
51
+ set_status :success, :ok, { 'cookies' => cookies }
52
+
53
+ print_info 'Cookies set to:'
54
+ cookies.each do |name, val|
55
+ print_info " * #{name.inspect} = #{val.inspect}"
56
+ end
57
+
58
+ rescue Arachni::Session::Error::NoLoginCheck
59
+ set_status :missing_check, :error
60
+ rescue => e
61
+ set_status :error
62
+ print_exception e
63
+ end
64
+
65
+ def clean_up
66
+ if @failed
67
+ print_info 'Aborting the scan.'
68
+ framework_abort
69
+ return
70
+ end
71
+
72
+ framework_resume
73
+ end
74
+
75
+ def set_status( status, type = nil, extra = {} )
76
+ type ||= status
77
+
78
+ register_results(
79
+ {
80
+ 'status' => status.to_s,
81
+ 'message' => STATUSES[status]
82
+ }.merge( extra )
83
+ )
84
+
85
+ @failed = true if type == :error
86
+ send "print_#{type}", STATUSES[status]
87
+ end
88
+
89
+ def self.info
90
+ {
91
+ name: 'Login script',
92
+ description: %q{
93
+ Loads and sets an external script as the system's login sequence, to be executed
94
+ prior to the scan and whenever a log-out is detected.
95
+
96
+ The script needn't necessarily perform an actual login operation. If another
97
+ process is used to manage sessions, the script can be used to communicate with
98
+ that process and, for example, load and set cookies from a shared cookie-jar.
99
+
100
+ **With browser (slow):**
101
+
102
+ If a [browser](http://watirwebdriver.com/) is available, it will be exposed to
103
+ the script via the `browser` variable. Otherwise, that variable will have a
104
+ value of `nil`.
105
+
106
+ browser.goto 'http://testfire.net/bank/login.aspx'
107
+
108
+ form = browser.form( id: 'login' )
109
+ form.text_field( name: 'uid' ).set 'jsmith'
110
+ form.text_field( name: 'passw' ).set 'Demo1234'
111
+
112
+ form.submit
113
+
114
+ # You can also configure the session check from the script, dynamically,
115
+ # if you don't want to set static options via the user interface.
116
+ framework.options.session.check_url = browser.url
117
+ framework.options.session.check_pattern = /Sign Off|MY ACCOUNT/
118
+
119
+ **Without browser (fast):**
120
+
121
+ If a real browser environment is not required for the login operation, then
122
+ using the system-wide HTTP interface is preferable, as it will be much faster
123
+ and consume much less resources.
124
+
125
+ response = http.post( 'http://testfire.net/bank/login.aspx',
126
+ parameters: {
127
+ 'uid' => 'jsmith',
128
+ 'passw' => 'Demo1234'
129
+ },
130
+ mode: :sync,
131
+ update_cookies: true
132
+ )
133
+
134
+ framework.options.session.check_url = to_absolute( response.headers.location, response.url )
135
+ framework.options.session.check_pattern = /Sign Off|MY ACCOUNT/
136
+
137
+ **From cookie-jar:**
138
+
139
+ If an external process is used to manage sessions, you can keep Arachni in sync
140
+ by loading cookies from a shared Netscape-style cookie-jar file.
141
+
142
+ http.cookie_jar.load 'cookies.txt'
143
+ },
144
+ author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
145
+ version: '0.1',
146
+ options: [
147
+ Options::Path.new( :script,
148
+ required: true,
149
+ description: 'Script that includes the login sequence.'
150
+ ),
151
+ ],
152
+ priority: 0 # run before any other plugin
153
+ }
154
+ end
155
+
156
+ end
@@ -0,0 +1,48 @@
1
+ =begin
2
+ Copyright 2010-2014 Tasos Laskos <tasos.laskos@arachni-scanner.com>
3
+
4
+ This file is part of the Arachni Framework project and is subject to
5
+ redistribution and commercial restrictions. Please see the Arachni Framework
6
+ web site for more information on licensing and terms of use.
7
+ =end
8
+
9
+ class Arachni::Reporters::HTML
10
+
11
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
12
+ class PluginFormatters::LoginScript < Arachni::Plugin::Formatter
13
+ include TemplateUtilities
14
+
15
+ def run
16
+ ERB.new( tpl ).result( binding )
17
+ end
18
+
19
+ def tpl
20
+ <<-HTML
21
+ <% if results['status'] == 'success' %>
22
+ <p class="alert alert-success">
23
+ <%= results['message'] %>
24
+ </p>
25
+
26
+ <h3>Cookies set to:</h3>
27
+
28
+ <dl class="dl-horizontal">
29
+ <% results['cookies'].each do |k, v| %>
30
+ <dt>
31
+ <code><%= escapeHTML( k ) %></code>
32
+ </dt>
33
+ <dd>
34
+ <code><%= escapeHTML( v ) %></code>
35
+ </dd>
36
+ <% end %>
37
+ </dl>
38
+ <% else %>
39
+ <p class="alert alert-danger">
40
+ <%= results['message'] %>
41
+ </p>
42
+ <% end %>
43
+ HTML
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,23 @@
1
+ =begin
2
+ Copyright 2010-2014 Tasos Laskos <tasos.laskos@arachni-scanner.com>
3
+
4
+ This file is part of the Arachni Framework project and is subject to
5
+ redistribution and commercial restrictions. Please see the Arachni Framework
6
+ web site for more information on licensing and terms of use.
7
+ =end
8
+
9
+ class Arachni::Reporters::Stdout
10
+
11
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
12
+ class PluginFormatters::LoginScript < Arachni::Plugin::Formatter
13
+
14
+ def run
15
+ print_ok results['message']
16
+
17
+ return if !results['cookies']
18
+ print_info 'Cookies set to:'
19
+ results['cookies'].each_pair { |name, val| print_info " * #{name} = #{val}" }
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ =begin
2
+ Copyright 2010-2014 Tasos Laskos <tasos.laskos@arachni-scanner.com>
3
+
4
+ This file is part of the Arachni Framework project and is subject to
5
+ redistribution and commercial restrictions. Please see the Arachni Framework
6
+ web site for more information on licensing and terms of use.
7
+ =end
8
+
9
+ class Arachni::Reporters::XML
10
+
11
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
12
+ class PluginFormatters::LoginScript < Arachni::Plugin::Formatter
13
+
14
+ def run( xml )
15
+ xml.message results['message']
16
+ xml.status results['status']
17
+
18
+ if results['cookies']
19
+ xml.cookies {
20
+ results['cookies'].each { |name, value| xml.cookie name: name, value: value }
21
+ }
22
+ end
23
+ end
24
+
25
+ end
26
+ end
@@ -25,6 +25,7 @@
25
25
  <xs:choice minOccurs="0" maxOccurs="9">
26
26
  <xs:element name="healthmap" type="plugin_healthmap" maxOccurs="1"/>
27
27
  <xs:element name="autologin" type="plugin_autologin" maxOccurs="1"/>
28
+ <xs:element name="login_script" type="plugin_login_script" maxOccurs="1"/>
28
29
  <xs:element name="content_types" type="plugin_content_types" maxOccurs="1"/>
29
30
  <xs:element name="cookie_collector" type="plugin_cookie_collector" maxOccurs="1"/>
30
31
  <xs:element name="form_dicattack" type="plugin_form_dicattack" maxOccurs="1"/>
@@ -187,6 +188,22 @@
187
188
  </xs:all>
188
189
  </xs:complexType>
189
190
 
191
+ <xs:complexType name="plugin_login_script">
192
+ <xs:all>
193
+ <xs:element name="name" type="xs:string"/>
194
+ <xs:element name="description" type="xs:string"/>
195
+ <xs:element name="results" type="plugin_login_script_results"/>
196
+ </xs:all>
197
+ </xs:complexType>
198
+
199
+ <xs:complexType name="plugin_login_script_results">
200
+ <xs:all>
201
+ <xs:element name="status" type="xs:string"/>
202
+ <xs:element name="message" type="xs:string"/>
203
+ <xs:element name="cookies" type="cookies" minOccurs="0"/>
204
+ </xs:all>
205
+ </xs:complexType>
206
+
190
207
  <xs:complexType name="plugin_healthmap">
191
208
  <xs:all>
192
209
  <xs:element name="name" type="xs:string"/>
@@ -820,7 +820,7 @@ class Browser
820
820
  c[:value] = Cookie.decode( c[:value].to_s )
821
821
  c[:httponly] = !js_cookies.include?( original_name )
822
822
 
823
- Cookie.new c.merge( url: @last_url )
823
+ Cookie.new c.merge( url: @last_url || url )
824
824
  end
825
825
  end
826
826
 
@@ -1007,8 +1007,10 @@ class Browser
1007
1007
  print_debug 'Spawn timed-out.'
1008
1008
  end
1009
1009
 
1010
- last_attempt_output = IO.read( @process.io.stdout )
1011
- print_debug last_attempt_output
1010
+ if @process.io.stdout
1011
+ last_attempt_output = IO.read( @process.io.stdout )
1012
+ print_debug last_attempt_output
1013
+ end
1012
1014
 
1013
1015
  if done
1014
1016
  print_debug 'PhantomJS is ready.'
@@ -1046,12 +1048,13 @@ class Browser
1046
1048
  end
1047
1049
 
1048
1050
  @process = nil
1051
+ @watir = nil
1049
1052
  @pid = nil
1050
1053
  @browser_url = nil
1051
1054
  end
1052
1055
 
1053
1056
  def browser_alive?
1054
- @process && @process.alive?
1057
+ @watir && @process && @process.alive?
1055
1058
  rescue Errno::ECHILD
1056
1059
  false
1057
1060
  end