arachni 0.2.4 → 0.3

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 (79) hide show
  1. data/CHANGELOG.md +33 -0
  2. data/README.md +2 -4
  3. data/Rakefile +15 -4
  4. data/bin/arachni +0 -0
  5. data/bin/arachni_web +0 -0
  6. data/bin/arachni_web_autostart +0 -0
  7. data/bin/arachni_xmlrpc +0 -0
  8. data/bin/arachni_xmlrpcd +0 -0
  9. data/bin/arachni_xmlrpcd_monitor +0 -0
  10. data/lib/arachni.rb +1 -1
  11. data/lib/framework.rb +36 -6
  12. data/lib/http.rb +12 -5
  13. data/lib/module/auditor.rb +482 -59
  14. data/lib/module/base.rb +17 -0
  15. data/lib/module/manager.rb +26 -2
  16. data/lib/module/trainer.rb +1 -12
  17. data/lib/module/utilities.rb +12 -0
  18. data/lib/parser/auditable.rb +8 -3
  19. data/lib/parser/elements.rb +11 -0
  20. data/lib/parser/page.rb +3 -1
  21. data/lib/parser/parser.rb +130 -18
  22. data/lib/rpc/xml/server/dispatcher.rb +21 -0
  23. data/lib/spider.rb +141 -82
  24. data/lib/ui/cli/cli.rb +2 -3
  25. data/lib/ui/web/addon_manager.rb +273 -0
  26. data/lib/ui/web/addons/autodeploy.rb +172 -0
  27. data/lib/ui/web/addons/autodeploy/lib/manager.rb +291 -0
  28. data/lib/ui/web/addons/autodeploy/views/index.erb +124 -0
  29. data/lib/ui/web/addons/sample.rb +78 -0
  30. data/lib/ui/web/addons/sample/views/index.erb +4 -0
  31. data/lib/ui/web/addons/scheduler.rb +139 -0
  32. data/lib/ui/web/addons/scheduler/views/index.erb +131 -0
  33. data/lib/ui/web/addons/scheduler/views/options.erb +93 -0
  34. data/lib/ui/web/dispatcher_manager.rb +80 -13
  35. data/lib/ui/web/instance_manager.rb +87 -0
  36. data/lib/ui/web/scheduler.rb +166 -0
  37. data/lib/ui/web/server.rb +142 -202
  38. data/lib/ui/web/server/public/js/jquery-ui-timepicker.js +985 -0
  39. data/lib/ui/web/server/public/plugins/sample/style.css +0 -0
  40. data/lib/ui/web/server/public/style.css +42 -0
  41. data/lib/ui/web/server/views/addon.erb +15 -0
  42. data/lib/ui/web/server/views/addons.erb +46 -0
  43. data/lib/ui/web/server/views/dispatchers.erb +1 -1
  44. data/lib/ui/web/server/views/instance.erb +9 -11
  45. data/lib/ui/web/server/views/layout.erb +14 -1
  46. data/lib/ui/web/server/views/welcome.erb +7 -6
  47. data/lib/ui/web/utilities.rb +134 -0
  48. data/modules/audit/code_injection_timing.rb +6 -2
  49. data/modules/audit/code_injection_timing/payloads.txt +2 -2
  50. data/modules/audit/os_cmd_injection_timing.rb +7 -3
  51. data/modules/audit/os_cmd_injection_timing/payloads.txt +1 -1
  52. data/modules/audit/sqli_blind_rdiff.rb +18 -233
  53. data/modules/audit/sqli_blind_rdiff/payloads.txt +5 -0
  54. data/modules/audit/sqli_blind_timing.rb +9 -2
  55. data/path_extractors/anchors.rb +1 -1
  56. data/path_extractors/forms.rb +1 -1
  57. data/path_extractors/frames.rb +1 -1
  58. data/path_extractors/generic.rb +1 -1
  59. data/path_extractors/links.rb +1 -1
  60. data/path_extractors/meta_refresh.rb +1 -1
  61. data/path_extractors/scripts.rb +1 -1
  62. data/path_extractors/sitemap.rb +1 -1
  63. data/plugins/proxy/server.rb +3 -2
  64. data/plugins/waf_detector.rb +0 -3
  65. metadata +37 -34
  66. data/lib/anemone/cookie_store.rb +0 -35
  67. data/lib/anemone/core.rb +0 -371
  68. data/lib/anemone/exceptions.rb +0 -5
  69. data/lib/anemone/http.rb +0 -144
  70. data/lib/anemone/page.rb +0 -338
  71. data/lib/anemone/page_store.rb +0 -160
  72. data/lib/anemone/storage.rb +0 -34
  73. data/lib/anemone/storage/base.rb +0 -75
  74. data/lib/anemone/storage/exceptions.rb +0 -15
  75. data/lib/anemone/storage/mongodb.rb +0 -89
  76. data/lib/anemone/storage/pstore.rb +0 -50
  77. data/lib/anemone/storage/redis.rb +0 -90
  78. data/lib/anemone/storage/tokyo_cabinet.rb +0 -57
  79. data/lib/anemone/tentacle.rb +0 -40
@@ -0,0 +1,93 @@
1
+
2
+
3
+ <div style="display: none" id="dialog_options_<%=job.id%>" title="Options">
4
+
5
+ <div class="left options">
6
+ <fieldset>
7
+ <legend>Auditor</legend>
8
+ <p>
9
+ Audit links: <input disabled type="checkbox" name="audit_links" <% if opts['audit_links'] == true %> checked="checked" <% end %> />
10
+ </p>
11
+ <p>
12
+ Audit forms: <input disabled type="checkbox" name="audit_forms" <% if opts['audit_forms'] == true %> checked="checked" <% end %> />
13
+ </p>
14
+ <p>
15
+ Audit cookies: <input disabled type="checkbox" name="audit_cookies" <% if opts['audit_cookies'] == true %> checked="checked" <% end %> />
16
+ </p>
17
+ <p>
18
+ Audit headers: <input disabled type="checkbox" name="audit_headers" <% if opts['audit_headers'] == true %> checked="checked" <% end %> />
19
+ </p>
20
+ <p>
21
+ Cookies to exclude: <textarea disabled rows="2" cols="20" name="exclude_cookies"><%=opts['exclude_cookies']%></textarea>
22
+ <br/>(Newline separated)
23
+ </p>
24
+ </fieldset>
25
+
26
+ <fieldset>
27
+ <legend>HTTP options</legend>
28
+ <p>
29
+ Cocurrent HTTP request limit: <label for="http_req_limit"></label>
30
+ <input disabled id="http_req_limit" name="http_req_limit"/>
31
+ <div id="slider"></div>
32
+ <br/>
33
+ </p>
34
+ <p>
35
+ HTTP harvest last: <input disabled type="checkbox" name="http_harvest_last" <% if opts['http_harvest_last'] == true %> checked="checked" <% end %> />
36
+ </p>
37
+ <p>
38
+ Cookie jar: <input disabled type="file" name="cookiejar" size="25" />
39
+ </p>
40
+ <p>
41
+ User agent: <input disabled name="user_agent" value="<%=opts['user_agent']%>"/>
42
+ </p>
43
+ <p>
44
+ Authorized by: <input disabled name="authed_by" value="<%=opts['authed_by']%>"/>
45
+ </p>
46
+
47
+ </fieldset>
48
+ </div>
49
+
50
+ <div class="right options">
51
+
52
+ <fieldset>
53
+ <legend>Crawler options</legend>
54
+ <p>
55
+ Exclude rules: <textarea disabled rows="2" cols="20" name="exclude"><% if opts['exclude']%><%=opts['exclude'].join( "\r\n" )%><%end%></textarea>
56
+ <br/>(Newline separated)
57
+ </p>
58
+ <p>
59
+ Include rules: <textarea disabled rows="2" cols="20" name="include"><% if opts['include']%><%=opts['include'].join( "\r\n" )%><%end%></textarea>
60
+ <br/>(Newline separated)
61
+ </p>
62
+ <p>
63
+ Redundant rules: <textarea disabled rows="2" cols="20" name="redundant"><%=format_redundants( opts['redundant'] )%></textarea>
64
+ <br/>(Newline separated)
65
+ <br/>(<em>regexp:counter</em>)
66
+ </p>
67
+ <p>
68
+ Depth: <input disabled name="depth_limit" value="<%=opts['depth_limit']%>"/>
69
+ <br/>(Default: infinite)
70
+ </p>
71
+ <p>
72
+ Link count limit: <input disabled name="link_count_limit" value="<%=opts['link_count_limit']%>"/>
73
+ <br/>(Default: infinite)
74
+ </p>
75
+ <p>
76
+ Redirect limit: <input disabled name="redirect_limit" value="<%=opts['redirect_limit']%>"/>
77
+ <br/>(Default: infinite)
78
+ </p>
79
+ <p>
80
+ Follow subdomain: <input disabled type="checkbox" name="follow_subdomains" <% if opts['follow_subdomains'] == true %> checked="checked" <% end %> />
81
+ </p>
82
+ <p>
83
+ Obey robot.txt file: <input disabled type="checkbox" name="obey_robots_txt" <% if opts['obey_robots_txt'] == true %> checked="checked" <% end %> />
84
+ </p>
85
+ <p>
86
+ Spider first: <input disabled type="checkbox" name="spider_first" <% if opts['spider_first'] == true %> checked="checked" <% end %> />
87
+ </p>
88
+ </fieldset>
89
+
90
+ </div>
91
+
92
+ </div>
93
+
@@ -15,9 +15,7 @@ module UI
15
15
  module Web
16
16
 
17
17
  #
18
- #
19
- # Provides nice little wrapper for the Arachni::Report::Manager while also handling<br/>
20
- # conversions, storing etc.
18
+ # Provides methods for dispatcher management.
21
19
  #
22
20
  # @author: Tasos "Zapotek" Laskos
23
21
  # <tasos.laskos@gmail.com>
@@ -44,10 +42,23 @@ class DispatcherManager
44
42
  Dispatcher.auto_upgrade!
45
43
  end
46
44
 
47
- def new( opts )
48
- Dispatcher.create( :url => opts[:url] )
45
+ #
46
+ # Puts a new dispatcher in the DB.
47
+ #
48
+ # @param [String] url URL of the dispatcher
49
+ #
50
+ def new( url )
51
+ Dispatcher.first_or_create( :url => url )
49
52
  end
50
53
 
54
+ #
55
+ # Provides an easy way to connect to a dispatcher and caches connections
56
+ # to reduce overhead.
57
+ #
58
+ # @param [String] url
59
+ #
60
+ # @return [Arachni::RPC::XML::Client::Dispatcher]
61
+ #
51
62
  def connect( url )
52
63
  @@cache ||= {}
53
64
 
@@ -59,20 +70,68 @@ class DispatcherManager
59
70
  return @@cache[url] = tmp
60
71
  end
61
72
  rescue Exception => e
62
- return nil
73
+ # ap e
74
+ # ap e.backtrace
75
+ return nil
63
76
  end
64
77
  end
65
78
 
66
- def alive?( url )
67
- begin
68
- return connect( url ).alive?
69
- rescue
70
- return false
71
- end
79
+ #
80
+ # Checks wether the dispatcher is alive.
81
+ #
82
+ # @param [String] url URL of the dispatcher
83
+ #
84
+ def alive?( url, tries = 5 )
85
+ tries.times {
86
+ begin
87
+ return connect( url ).alive?
88
+ rescue Exception => e
89
+ # ap e
90
+ # ap e.backtrace
91
+ end
92
+ }
93
+
94
+ return false
95
+ end
96
+
97
+ def first_alive
98
+ all.each {
99
+ |dispatcher|
100
+ return dispatcher if alive?( dispatcher.url )
101
+ }
102
+
103
+ return nil
72
104
  end
73
105
 
74
106
  #
75
- # Returns the paths of all saved report files as an array
107
+ # Provides statistics about running jobs etc using the dispatcher
108
+ #
109
+ # @return [Hash]
110
+ #
111
+ def stats
112
+ stats_h = {}
113
+ all.each {
114
+ |dispatcher|
115
+
116
+ begin
117
+ stats_h[dispatcher['url']] = connect( dispatcher['url'] ).stats
118
+ stats_h[dispatcher['url']]['running_jobs'].each {
119
+ |job|
120
+ begin
121
+ instance = @settings.instances.port_to_url( job['port'], dispatcher['url'] )
122
+ job['paused'] = @settings.instances.connect( instance ).framework.paused?
123
+ rescue
124
+ end
125
+ }
126
+ rescue
127
+ end
128
+ }
129
+
130
+ return stats_h
131
+ end
132
+
133
+ #
134
+ # Returns all dispatchers stored in the DB.
76
135
  #
77
136
  # @return [Array]
78
137
  #
@@ -80,6 +139,9 @@ class DispatcherManager
80
139
  Dispatcher.all( *args )
81
140
  end
82
141
 
142
+ #
143
+ # Removed all dispatchers from the DB.
144
+ #
83
145
  def delete_all
84
146
  all.each {
85
147
  |report|
@@ -88,6 +150,11 @@ class DispatcherManager
88
150
  all.destroy
89
151
  end
90
152
 
153
+ #
154
+ # Removed a dispatcher from the DB.
155
+ #
156
+ # @param [Integer] id
157
+ #
91
158
  def delete( id )
92
159
  Dispatcher.get( id ).destroy
93
160
  end
@@ -0,0 +1,87 @@
1
+ =begin
2
+ Arachni
3
+ Copyright (c) 2010-2011 Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
4
+
5
+ This is free software; you can copy and distribute and modify
6
+ this program under the term of the GPL v2.0 License
7
+ (See LICENSE file for details)
8
+
9
+ =end
10
+
11
+ require Arachni::Options.instance.dir['lib'] + 'rpc/xml/client/instance'
12
+ require Arachni::Options.instance.dir['lib'] + 'ui/web/utilities'
13
+
14
+ module Arachni
15
+ module UI
16
+ module Web
17
+
18
+ #
19
+ # Provides methods for instance management.
20
+ #
21
+ # @author: Tasos "Zapotek" Laskos
22
+ # <tasos.laskos@gmail.com>
23
+ # <zapotek@segfault.gr>
24
+ # @version: 0.1
25
+ #
26
+ class InstanceManager
27
+
28
+ include Utilities
29
+
30
+ def initialize( opts, settings )
31
+ @opts = opts
32
+ @settings = settings
33
+ end
34
+
35
+ #
36
+ # Provides an easy way to connect to an instance and caches connections
37
+ # to reduce overhead.
38
+ #
39
+ # @param [String] url
40
+ # @param [Hash] session session of the current user (optional)
41
+ # @param [String] token authentication token (optional)
42
+ #
43
+ # @return [Arachni::RPC::XML::Client::Instance]
44
+ #
45
+ def connect( url, session = nil, token = nil )
46
+ url = 'https://' + url if !url.include?( 'https' )
47
+
48
+ @@connections ||= {}
49
+
50
+ begin
51
+ if @@connections[url] && @@connections[url].alive?
52
+ return @@connections[url]
53
+ end
54
+ rescue
55
+ end
56
+
57
+ begin
58
+
59
+ #
60
+ # Sync up the session authentication tokens with the ones in the
61
+ # class variables.
62
+ #
63
+ # This will allow users to still connect to instances even if they
64
+ # shutdown the WebUI or removed their cookies.
65
+ #
66
+
67
+ @@tokens ||= {}
68
+ session['tokens'] ||= {} if session
69
+ @@tokens[url] = token if token
70
+
71
+ session['tokens'].merge!( @@tokens ) if session
72
+ @@tokens.merge!( session['tokens'] ) if session
73
+ session['tokens'].merge!( @@tokens ) if session
74
+
75
+ tmp_token = session ? session['tokens'][url] : @@tokens[url]
76
+
77
+ return @@connections[url] =
78
+ Arachni::RPC::XML::Client::Instance.new( @opts, url, tmp_token )
79
+ rescue Exception => e
80
+ raise "Instance at #{url} has shutdown."
81
+ end
82
+ end
83
+
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,166 @@
1
+ =begin
2
+ Arachni
3
+ Copyright (c) 2010-2011 Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
4
+
5
+ This is free software; you can copy and distribute and modify
6
+ this program under the term of the GPL v2.0 License
7
+ (See LICENSE file for details)
8
+
9
+ =end
10
+
11
+ require 'datamapper'
12
+ require Arachni::Options.instance.dir['lib'] + 'rpc/xml/client/dispatcher'
13
+ require Arachni::Options.instance.dir['lib'] + 'ui/web/utilities'
14
+
15
+ module Arachni
16
+ module UI
17
+ module Web
18
+
19
+ #
20
+ # Schedules and executes scan jobs.
21
+ #
22
+ #
23
+ # @author: Tasos "Zapotek" Laskos
24
+ # <tasos.laskos@gmail.com>
25
+ # <zapotek@segfault.gr>
26
+ # @version: 0.1.1
27
+ #
28
+ class Scheduler
29
+
30
+ include Utilities
31
+
32
+ class Job
33
+ include DataMapper::Resource
34
+
35
+ property :id, Serial
36
+ property :dispatcher, String
37
+ property :url, String
38
+ property :opts, Text
39
+ property :datetime, DateTime
40
+
41
+ property :owner_addr, String
42
+ property :owner_host, String
43
+
44
+ property :created_at, DateTime
45
+ end
46
+
47
+ #
48
+ # Initializes the Scheduler and starts the clock.
49
+ #
50
+ #
51
+ def initialize( opts, settings )
52
+ @opts = opts
53
+ @settings = settings
54
+
55
+ DataMapper::setup( :default, "sqlite3://#{@settings.db}/default.db" )
56
+ DataMapper.finalize
57
+
58
+ Job.auto_upgrade!
59
+
60
+ begin
61
+ ticktock!
62
+ rescue Exception => e
63
+ ap e
64
+ ap e.backtrace
65
+ end
66
+ end
67
+
68
+ #
69
+ # Runs a job.
70
+ #
71
+ # @param [Job] job
72
+ # @param [Hash] Sinatra environment
73
+ # @param [Hash] Rack session
74
+ #
75
+ # @return [String] URL of the laucnhed scanner instance
76
+ #
77
+ def run( job, env = nil, session = nil )
78
+ instance = @settings.dispatchers.connect( job.dispatcher ).dispatch( job.url )
79
+ instance_url = @settings.instances.port_to_url( instance['port'], job.dispatcher )
80
+
81
+ env = {
82
+ 'REMOTE_ADDR' => job.owner_addr,
83
+ 'REMOTE_HOST' => job.owner_host
84
+ } if env.nil?
85
+
86
+ @settings.log.scheduler_instance_dispatched( env, instance_url )
87
+ @settings.log.scheduler_instance_owner_assigned( env, job.url )
88
+
89
+ arachni = @settings.instances.connect( instance_url, session, instance['token'] )
90
+
91
+ opts = YAML::load( job.opts )
92
+
93
+ arachni.opts.set( opts['settings'] )
94
+ arachni.modules.load( opts['modules'] )
95
+ arachni.plugins.load( opts['plugins'] )
96
+
97
+ arachni.framework.run
98
+
99
+ @settings.log.scheduler_scan_started( env, job.url )
100
+
101
+ return instance_url
102
+ end
103
+
104
+ #
105
+ # Runs a job and removed it from the DB.
106
+ #
107
+ # @param [Job] job
108
+ #
109
+ def run_and_destroy( job )
110
+ run( job )
111
+ job.destroy
112
+ end
113
+
114
+ #
115
+ # Returns all scheduled jobs.
116
+ #
117
+ # @return [Array]
118
+ #
119
+ def jobs( *args )
120
+ Job.all( *args )
121
+ end
122
+
123
+ #
124
+ # Removes all jobs.
125
+ #
126
+ def delete_all
127
+ jobs.destroy
128
+ end
129
+
130
+ #
131
+ # Removed a job.
132
+ #
133
+ # @param [Integer] id
134
+ #
135
+ def delete( id )
136
+ Job.get( id ).destroy
137
+ end
138
+
139
+
140
+ private
141
+
142
+ def ticktock!
143
+ @reaper ||= Thread.new {
144
+ while( true )
145
+ jobs.each {
146
+ |job|
147
+
148
+ begin
149
+ run_and_destroy( job ) if job.datetime <= Time.now
150
+ rescue Exception => e
151
+ ap e
152
+ ap e.backtrace
153
+ end
154
+
155
+ }
156
+
157
+ ::IO::select( nil, nil, nil, 5 )
158
+ end
159
+ }
160
+
161
+ end
162
+
163
+ end
164
+ end
165
+ end
166
+ end