arachni 0.2.4 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
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,172 @@
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
+ module Arachni
12
+ module UI
13
+ module Web
14
+ module Addons
15
+
16
+ #
17
+ #
18
+ # Auto-deploy add-on.
19
+ #
20
+ # Allows users to automatically convert any SSH enabled Linux box into an Arachni Dispatcher.
21
+ #
22
+ # @author: Tasos "Zapotek" Laskos
23
+ # <tasos.laskos@gmail.com>
24
+ # <zapotek@segfault.gr>
25
+ #
26
+ # @version: 0.1
27
+ #
28
+ class AutoDeploy < Base
29
+
30
+ def run
31
+
32
+ settings.helpers do
33
+ require File.dirname( __FILE__ ) + '/autodeploy/lib/manager'
34
+
35
+ def autodeploy
36
+ @@autodeploy ||= Manager.new( Options.instance, settings )
37
+ end
38
+
39
+ end
40
+
41
+ get "/" do
42
+ present :index, :deployments => autodeploy.list,
43
+ :root => current_addon.path_root, :show_output => false, :ret => {}
44
+
45
+ end
46
+
47
+ post "/" do
48
+
49
+ if !params[:host] || params[:host].empty? || !params[:username] ||
50
+ params[:username].empty? || !params[:password] || params[:password].empty? ||
51
+ !params[:port] || params[:port].empty? ||
52
+ !params[:dispatcher_port] || params[:dispatcher_port].empty?
53
+
54
+ flash[:err] = "Please fill in all the fields."
55
+
56
+ present :index, :deployments => autodeploy.list,
57
+ :root => current_addon.path_root, :show_output => false,
58
+ :ret => {}
59
+ else
60
+ deployment = Manager::Deployment.new( :host => params[:host],
61
+ :port => params[:port], :user => params[:username],
62
+ :dispatcher_port => params[:dispatcher_port] )
63
+
64
+ settings.log.autodeploy_setup_started( env, autodeploy.get_url( deployment ) )
65
+ channel = autodeploy.setup( deployment, params[:password] )
66
+
67
+ present :index, :deployments => autodeploy.list,
68
+ :root => current_addon.path_root, :channel => channel,
69
+ :show_output => true, :ret => {}
70
+ end
71
+
72
+ end
73
+
74
+ get '/channel/:channel' do
75
+ content_type :json
76
+ autodeploy.output( params[:channel] ).to_json
77
+ end
78
+
79
+ get '/channel/:channel/finalize' do
80
+
81
+ deployment = autodeploy.finalize_setup( params[:channel] )
82
+ log.autodeploy_deployment_saved( env,
83
+ "ID: #{deployment.id} [#{autodeploy.get_url( deployment )}]" )
84
+
85
+ flash[:ok] = "Deployment was successful."
86
+
87
+ present :index, :deployments => autodeploy.list, :ret => {},
88
+ :root => current_addon.path_root, :show_output => false
89
+ end
90
+
91
+
92
+ post '/:id' do
93
+
94
+ ret = {}
95
+ if !params[:password] || params[:password].empty?
96
+ flash[:err] = "The password field is required."
97
+ else
98
+ if params[:action] == 'delete'
99
+
100
+ ret = autodeploy.delete( params[:id], params[:password] )
101
+
102
+ if ret[:code]
103
+ flash[:err] = "Uninstall process aborted because the last command failed.<br/>" +
104
+ " Please ensure that the password is correct and the network is up."
105
+ else
106
+ log.autodeploy_deployment_deleted( env, params[:id] )
107
+ flash[:ok] = "Uninstall process was successful."
108
+ end
109
+
110
+ elsif params[:action] == 'run'
111
+ deployment = autodeploy.get( params[:id] )
112
+ ret = autodeploy.run( deployment, params[:password] )
113
+
114
+ url = 'https://' + deployment.host + ':' + deployment.dispatcher_port
115
+
116
+ if settings.dispatchers.alive?( url )
117
+ flash[:ok] = "Dispatcher is up and running."
118
+ DispatcherManager::Dispatcher.first_or_create( :url => url )
119
+ settings.log.autodeploy_dispatcher_enabled( env,
120
+ "ID: #{deployment.id} [#{autodeploy.get_url( deployment )}]" )
121
+
122
+ ret = {}
123
+ else
124
+ flash[:err] = "Could not run the Dispatcher.<br/>" +
125
+ " Please ensure that the password is correct and the network is up."
126
+ end
127
+ elsif params[:action] == 'shutdown'
128
+ deployment = autodeploy.get( params[:id] )
129
+ ret = autodeploy.shutdown( deployment, params[:password] )
130
+
131
+ if ret[:code] == 0 && !settings.dispatchers.alive?( url )
132
+ flash[:ok] = "Dispatcher has been shutdown."
133
+ settings.log.autodeploy_dispatcher_shutdown( env,
134
+ "ID: #{deployment.id} [#{autodeploy.get_url( deployment )}]" )
135
+
136
+ ret = {}
137
+ else
138
+ flash[:err] = "Could not shutdown the Dispatcher.<br/>" +
139
+ " Please ensure that the password is correct and the network is up."
140
+ end
141
+
142
+
143
+ end
144
+ end
145
+
146
+ present :index, :deployments => autodeploy.list,
147
+ :root => current_addon.path_root, :ret => ret, :show_output => false
148
+ end
149
+
150
+
151
+ end
152
+
153
+ def title
154
+ "Auto-deploy [#{Manager.new( Options.instance, settings ).list.size}]"
155
+ end
156
+
157
+ def self.info
158
+ {
159
+ :name => 'Auto-deploy',
160
+ :description => %q{Enables you to automatically convert any SSH enabled Linux box into an Arachni Dispatcher.},
161
+ :author => 'Tasos "Zapotek" Laskos <tasos.laskos@gmail.com> ',
162
+ :version => '0.1'
163
+ }
164
+ end
165
+
166
+
167
+ end
168
+
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,291 @@
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 'net/ssh'
13
+ require 'digest/md5'
14
+
15
+
16
+ module Arachni
17
+ module UI
18
+ module Web
19
+ module Addons
20
+
21
+ class AutoDeploy
22
+
23
+ #
24
+ #
25
+ # @author: Tasos "Zapotek" Laskos
26
+ # <tasos.laskos@gmail.com>
27
+ # <zapotek@segfault.gr>
28
+ # @version: 0.1
29
+ #
30
+ class Manager
31
+
32
+ include Utilities
33
+
34
+ ARCHIVE_PATH = 'https://github.com/downloads/Zapotek/arachni/'
35
+ ARCHIVE_NAME = 'arachni-v0.3-autodeploy'
36
+ ARCHIVE_EXT = '.tar.gz'
37
+
38
+ EXEC = 'arachni_xmlrpcd'
39
+
40
+ class Deployment
41
+ include DataMapper::Resource
42
+
43
+ property :id, Serial
44
+ property :host, String
45
+ property :port, String
46
+ property :dispatcher_port, String
47
+ property :user, String
48
+ property :created_at, DateTime, :default => Time.now
49
+ end
50
+
51
+ #
52
+ # Initializes the Scheduler and starts the clock.
53
+ #
54
+ #
55
+ def initialize( opts, settings )
56
+ @opts = opts
57
+ @settings = settings
58
+
59
+ DataMapper::setup( :default, "sqlite3://#{@settings.db}/default.db" )
60
+ DataMapper.finalize
61
+
62
+ Deployment.auto_upgrade!
63
+ end
64
+
65
+ def setup( deployment, password )
66
+
67
+ @@setup ||= {}
68
+ url = get_url( deployment )
69
+ @@setup[url] ||= {}
70
+
71
+ Thread.new {
72
+ @@setup[url][:deployment] ||= deployment
73
+ @@setup[url][:status] = 'working'
74
+
75
+ begin
76
+ session = ssh( deployment, password )
77
+ rescue Exception => e
78
+ @@setup[url][:status] = 'failed'
79
+ @@setup[url][:output] = e.class.name + ': ' + e.to_s + "\n" + e.backtrace.join( "\n" )
80
+ @@setup[url][:code] = 1
81
+ return
82
+ end
83
+
84
+
85
+ wget = 'wget --output-document=' + ARCHIVE_NAME + '-' + deployment.dispatcher_port +
86
+ ARCHIVE_EXT + ' ' + ARCHIVE_PATH + ARCHIVE_NAME + ARCHIVE_EXT
87
+ ret = ssh_exec!( deployment, session, wget )
88
+
89
+ if ret[:code] != 0
90
+ @@setup[url][:status] = 'failed'
91
+ return
92
+ end
93
+
94
+ mkdir = 'mkdir ' + ARCHIVE_NAME + '-' + deployment.dispatcher_port
95
+ ret = ssh_exec!( deployment, session, mkdir )
96
+
97
+ if ret[:code] != 0
98
+ @@setup[url][:status] = 'failed'
99
+ return
100
+ end
101
+
102
+
103
+ tar = 'tar xvf ' + ARCHIVE_NAME + '-' + deployment.dispatcher_port + ARCHIVE_EXT +
104
+ ' -C ' + ARCHIVE_NAME + '-' + deployment.dispatcher_port
105
+ ret = ssh_exec!( deployment, session, tar )
106
+
107
+ if ret[:code] != 0
108
+ @@setup[url][:status] = 'failed'
109
+ return
110
+ end
111
+
112
+
113
+ chmod = 'chmod +x ' + ARCHIVE_NAME + '-' + deployment.dispatcher_port + '/' +
114
+ ARCHIVE_NAME + '/' + EXEC
115
+ ret = ssh_exec!( deployment, session, chmod )
116
+
117
+ if ret[:code] != 0
118
+ @@setup[url][:status] = 'failed'
119
+ return
120
+ end
121
+
122
+ @@setup[url][:status] = 'finished'
123
+ }
124
+
125
+ return get_url( deployment )
126
+ end
127
+
128
+ def output( channel )
129
+ return @@setup[channel]
130
+ end
131
+
132
+ def finalize_setup( channel )
133
+ @@setup[channel][:deployment].save
134
+ return @@setup[channel][:deployment]
135
+ end
136
+
137
+ def uninstall( deployment, password )
138
+
139
+ begin
140
+ session = ssh( deployment, password )
141
+ rescue Exception => e
142
+ return {
143
+ :output => e.class.name + ': ' + e.to_s + "\n" + e.backtrace.join( "\n" ),
144
+ :status => 'failed',
145
+ :code => 1
146
+ }
147
+ end
148
+
149
+ out = "\n" + rm = "rm -rf #{ARCHIVE_NAME}-#{deployment.dispatcher_port}*"
150
+ ret = ssh_exec!( deployment, session, rm )
151
+ out += "\n" + ret[:stdout] + "\n" + ret[:stderr]
152
+
153
+ return { :output => out, :code => ret[:code], :status => 'failed', } if ret[:code] != 0
154
+
155
+ return { :output => out }
156
+ end
157
+
158
+ def run( deployment, password )
159
+ begin
160
+ session = ssh( deployment, password )
161
+ rescue Exception => e
162
+ return {
163
+ :output => e.class.name + ': ' + e.to_s + "\n" + e.backtrace.join( "\n" ),
164
+ :status => 'failed',
165
+ :code => 1
166
+ }
167
+ end
168
+
169
+ session.exec!( 'nohup ./' + ARCHIVE_NAME + '-' + deployment.dispatcher_port + '/' +
170
+ ARCHIVE_NAME + '/' + EXEC + ' --port=' + deployment.dispatcher_port +
171
+ ' > arachni-xmlrpcd-startup.log 2>&1 &' )
172
+
173
+ sleep( 5 )
174
+ { :code => 0 }
175
+ end
176
+
177
+ def shutdown( deployment, password )
178
+
179
+ url = "https://#{deployment.host}:#{deployment.dispatcher_port}"
180
+ proc = @settings.dispatchers.connect( url ).proc_info
181
+
182
+ begin
183
+ session = ssh( deployment, password )
184
+ rescue Exception => e
185
+ return {
186
+ :output => e.class.name + ': ' + e.to_s + "\n" + e.backtrace.join( "\n" ),
187
+ :status => 'failed',
188
+ :code => 1
189
+ }
190
+ end
191
+
192
+ ssh_exec!( deployment, session, 'kill -9 -' + proc['pgrp'] )
193
+ end
194
+
195
+
196
+ def list
197
+ Deployment.all.reverse
198
+ end
199
+
200
+ def get( id )
201
+ Deployment.get( id )
202
+ end
203
+
204
+ def delete( id, password )
205
+ deployment = get( id )
206
+ ret = uninstall( deployment, password )
207
+ return ret if ret[:code]
208
+ deployment.destroy
209
+ return ret
210
+ end
211
+
212
+ def ssh( deployment, password )
213
+ @@ssh ||= {}
214
+ @@ssh[get_url( deployment ) + '$' + Digest::MD5.hexdigest( password ) ] ||=
215
+ Net::SSH.start( deployment.host, deployment.user,
216
+ {
217
+ :port => deployment.port,
218
+ :password => password
219
+ }
220
+ )
221
+ end
222
+
223
+ def get_url( deployment )
224
+ deployment.user + '@' + deployment.host + ':' + deployment.port.to_s +
225
+ '$' + deployment.dispatcher_port.to_s
226
+ end
227
+
228
+ def ssh_exec!( deployment, ssh, command )
229
+
230
+ stdout_data = ""
231
+ stderr_data = ""
232
+
233
+ exit_code = nil
234
+ exit_signal = nil
235
+
236
+ @@setup ||= {}
237
+
238
+ url = get_url( deployment )
239
+
240
+ @@setup[url] ||= {}
241
+ @@setup[url][:code] = 0
242
+ @@setup[url][:output] ||= ''
243
+ @@setup[url][:output] += "\n" + command + "\n"
244
+
245
+ ssh.open_channel do |channel|
246
+ channel.exec(command) do |ch, success|
247
+ unless success
248
+ abort "FAILED: couldn't execute command (ssh.channel.exec)"
249
+ end
250
+
251
+ channel.on_data {
252
+ |ch, data|
253
+ stdout_data += data
254
+ @@setup[url][:output] += data
255
+ }
256
+
257
+ channel.on_extended_data {
258
+ |ch, type, data|
259
+ stderr_data += data
260
+ @@setup[url][:output] += data
261
+ }
262
+
263
+ channel.on_request( "exit-status" ) {
264
+ |ch, data|
265
+ exit_code = data.read_long
266
+ @@setup[url][:code] = data.read_long
267
+ }
268
+
269
+ channel.on_request( "exit-signal" ) {
270
+ |ch, data|
271
+ exit_signal = data.read_long
272
+ }
273
+
274
+ end
275
+ end
276
+
277
+ ssh.loop
278
+ return {
279
+ :stdout => stdout_data,
280
+ :stderr => stderr_data,
281
+ :code => exit_code,
282
+ :signal => exit_signal
283
+ }
284
+ end
285
+
286
+ end
287
+ end
288
+ end
289
+ end
290
+ end
291
+ end