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,124 @@
1
+
2
+ <div>
3
+
4
+ <form action="<%=root%>/" method="post">
5
+ <h2>Perform a new deployment</h2>
6
+ <br/>
7
+
8
+ <fieldset>
9
+ <legend>SSH options:</legend>
10
+ Host: <input name="host" />
11
+ Port: <input name="port" value="22" size="4" />
12
+ Username: <input name="username" />
13
+ Password (will not be stored): <input name="password" type="password" />
14
+ </fieldset>
15
+ <br/>
16
+
17
+ <fieldset>
18
+ <legend>Dispatcher options:</legend>
19
+ Port: <input name="dispatcher_port" value="7331" />
20
+ </fieldset>
21
+ <br/>
22
+
23
+ <%= csrf_tag %>
24
+ <input type="submit" value="Add" />
25
+ </form>
26
+
27
+ <% if show_output || !ret.empty? %>
28
+ <br/>
29
+ <h3>Output</h3>
30
+ <b>Status: <span id="status"><%=ret[:status]%></span></b>
31
+ <br/>
32
+ <pre id="output" style="max-height: 400px; overflow: scroll"><%=ret[:output]%></pre>
33
+ <% end %>
34
+
35
+ </div>
36
+
37
+
38
+ <% if !deployments.empty? %>
39
+ <br/>
40
+ <br/>
41
+
42
+ <i>(Shutting down a Dispatcher will terminate all its running scans.)</i>
43
+ <table>
44
+ <tr>
45
+ <th>ID</th>
46
+ <th>Host</th>
47
+ <th>SSH Port</th>
48
+ <th>Dispatcher port</th>
49
+ <th>Username</th>
50
+ <th>Password</th>
51
+ <th>Running?</th>
52
+ <th>Created at</th>
53
+ <th>Action</th>
54
+ </tr>
55
+ <% deployments.each do |dep| %>
56
+ <tr>
57
+
58
+ <form action="<%=root%>/<%=dep.id%>" method="post">
59
+ <td><%=dep.id%></td>
60
+ <td><%=dep.host%></td>
61
+ <td><%=dep.port%></td>
62
+ <td><%=dep.dispatcher_port%></td>
63
+ <td><%=dep.user%></td>
64
+ <td><input name="password" type="password" /></td>
65
+ <td><%=is_alive = dispatchers.alive?( 'https://' + dep.host + ':' + dep.dispatcher_port )%></td>
66
+ <td><%=dep.created_at%></td>
67
+ <td>
68
+ <%= csrf_tag %>
69
+ <input type="hidden" name="id" value="<%=dep.id%>">
70
+
71
+ <% if !is_alive%>
72
+ <input type="radio" name="action" value="run"> Run <br/>
73
+ <%else%>
74
+ <input type="radio" name="action" value="shutdown"> Shutdown <br/>
75
+ <%end%>
76
+ <input type="radio" name="action" value="delete"> Uninstall & Delete <br/>
77
+
78
+ <input type="submit" value="Submit">
79
+ </td>
80
+ </form>
81
+ </tr>
82
+ <% end %>
83
+ </table>
84
+ <% else %>
85
+ <p class="notice">There are no deployments at the moment.</p>
86
+ <% end %>
87
+
88
+ <% if show_output%>
89
+ <script type="text/javascript">
90
+ //<![CDATA[
91
+
92
+ function updateOutput() {
93
+ if( !document.getElementById( 'output' ) ) return;
94
+
95
+ var output_url = "<%=root%>/channel/<%=channel%>";
96
+ $.getJSON( output_url, function(data) {
97
+ if( data.status == 'finished' ) {
98
+ window.location.replace( "<%=root%>/channel/<%=channel%>/finalize" );
99
+ } if( data.status == 'failed' ) {
100
+ document.getElementById( 'status' ).innerHTML = data.status;
101
+ obj = document.getElementById( 'output' );
102
+ obj.innerHTML = data.output;
103
+ } else {
104
+
105
+ document.getElementById( 'status' ).innerHTML = data.status;
106
+
107
+ obj = document.getElementById( 'output' );
108
+ obj.innerHTML = data.output;
109
+ obj.scrollTop = obj.scrollHeight;
110
+ }
111
+ });
112
+ }
113
+
114
+ $( document ).ready(function() {
115
+
116
+ updateOutput( );
117
+ setInterval( function() {
118
+ updateOutput( );
119
+ }, 1500 );
120
+
121
+ })
122
+ //]]>
123
+ </script>
124
+ <%end%>
@@ -0,0 +1,78 @@
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
+ # Sample add-on, see the code for examples.
19
+ #
20
+ # @author: Tasos "Zapotek" Laskos
21
+ # <tasos.laskos@gmail.com>
22
+ # <zapotek@segfault.gr>
23
+ #
24
+ # @see http://www.sinatrarb.com/intro.html
25
+ #
26
+ # @version: 0.1
27
+ #
28
+ class Sample < Base
29
+
30
+ #
31
+ # This method gets fired when the plugin is loaded.
32
+ #
33
+ def run
34
+
35
+ #
36
+ # You can work with get/post/put/delete handlers just like
37
+ # when using Sinatra.
38
+ #
39
+ get '/' do
40
+
41
+ #
42
+ # From inside the block you have access to regular Sinatra stuff
43
+ # like sessions, helpers etc.
44
+ #
45
+
46
+ # session => Direct access to the session, *be careful!*.
47
+ # settings => Direct access to the Sinatra methods, attributes, etc.
48
+
49
+ # You can treat 'present' just like 'erb' with a default layout.
50
+ present :index, :msg => 'world'
51
+ end
52
+
53
+ end
54
+
55
+ #
56
+ # This optional method allows you to specify the title which will be
57
+ # used for the menu (in case you want it to be dynamic).
58
+ #
59
+ def title
60
+ 'Sample'
61
+ end
62
+
63
+ def self.info
64
+ {
65
+ :name => 'Sample add-on',
66
+ :description => %q{This add-on serves as an example/tutorial.},
67
+ :author => 'Tasos "Zapotek" Laskos <tasos.laskos@gmail.com> ',
68
+ :version => '0.1'
69
+ }
70
+ end
71
+
72
+
73
+ end
74
+
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,4 @@
1
+
2
+ <p>
3
+ Hello <%=msg%>!
4
+ </p>
@@ -0,0 +1,139 @@
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
+ # Scheduler add-on.
19
+ #
20
+ # @author: Tasos "Zapotek" Laskos
21
+ # <tasos.laskos@gmail.com>
22
+ # <zapotek@segfault.gr>
23
+ #
24
+ # @version: 0.1
25
+ #
26
+ class Scheduler < Base
27
+
28
+ def run
29
+
30
+ get "/" do
31
+ present :index,
32
+ :jobs => scheduler.jobs( :order => :created_at.desc ),
33
+ # we need to get our context via "addons.running['scheduler']"
34
+ # which is, essentially, this class.
35
+ :root => current_addon.path_root
36
+ end
37
+
38
+ post '/' do
39
+ valid = true
40
+
41
+ begin
42
+ URI.parse( params['url'] )
43
+ rescue
44
+ valid = false
45
+ end
46
+
47
+ if !params['url'] || params['url'].empty? || !valid
48
+ flash[:err] = "Invalid URL."
49
+ elsif !params['dispatcher'] || params['dispatcher'].empty?
50
+ flash[:err] = "Please select a Dispatcher."
51
+ else
52
+
53
+ session['opts']['settings']['url'] = params[:url]
54
+
55
+ unescape_hash( session['opts'] )
56
+ session['opts']['settings']['audit_links'] = true if session['opts']['settings']['audit_links']
57
+ session['opts']['settings']['audit_forms'] = true if session['opts']['settings']['audit_forms']
58
+ session['opts']['settings']['audit_cookies'] = true if session['opts']['settings']['audit_cookies']
59
+ session['opts']['settings']['audit_headers'] = true if session['opts']['settings']['audit_headers']
60
+
61
+ opts = {}
62
+ opts['settings'] = prep_opts( session['opts']['settings'] )
63
+ opts['plugins'] = YAML::load( session['opts']['plugins'] )
64
+ opts['modules'] = session['opts']['modules']
65
+
66
+ if params[:datetime] && !params[:datetime].empty?
67
+
68
+ job = Arachni::UI::Web::Scheduler::Job.new(
69
+ :dispatcher => params[:dispatcher],
70
+ :url => params[:url],
71
+ :opts => opts.to_yaml,
72
+ :owner_addr => env['REMOTE_ADDR'],
73
+ :owner_host => env['REMOTE_HOST'],
74
+ :created_at => Time.now
75
+ )
76
+
77
+ begin
78
+ job.datetime = parse_datetime( params[:datetime] )
79
+
80
+ if !job.valid?
81
+ flash[:err] = 'Job holds invalid data, skipping...'
82
+ else
83
+ job.save
84
+ flash[:ok] = "Job saved."
85
+ end
86
+ rescue Exception => e
87
+ flash[:err] = 'Could not parse date (' + e.to_s + ').'
88
+ end
89
+
90
+ else
91
+ flash[:err] = 'Date cannot be empty.'
92
+ end
93
+ end
94
+
95
+ present :index,
96
+ :jobs => scheduler.jobs( :order => :created_at.desc ),
97
+ # we need to get our context via "addons.running['scheduler']"
98
+ # which is, essentially, this class.
99
+ :root => current_addon.path_root
100
+
101
+
102
+ end
103
+
104
+ post '/delete' do
105
+ scheduler.delete_all
106
+ log.scheduler_jobs_deleted( env )
107
+
108
+ redirect addons.running['scheduler'].path_root + '/'
109
+ end
110
+
111
+ post '/:id/delete' do
112
+ scheduler.delete( params[:id] )
113
+ log.scheduler_job_deleted( env, params[:id] )
114
+
115
+ redirect addons.running['scheduler'].path_root + '/'
116
+ end
117
+
118
+ end
119
+
120
+ def title
121
+ "Scheduler [#{settings.scheduler.jobs.size}]"
122
+ end
123
+
124
+ def self.info
125
+ {
126
+ :name => 'Scheduler',
127
+ :description => %q{Schedules and runs scan jobs.},
128
+ :author => 'Tasos "Zapotek" Laskos <tasos.laskos@gmail.com> ',
129
+ :version => '0.1'
130
+ }
131
+ end
132
+
133
+
134
+ end
135
+
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,131 @@
1
+
2
+ <% if !jobs.empty? %>
3
+ <form action="<%=root%>/delete" method="post">
4
+ <%= csrf_tag %>
5
+ <input type="submit" value="Delete all" />
6
+ </form>
7
+ <% end %>
8
+
9
+ <div>
10
+
11
+ <form action="<%=root%>/" method="post">
12
+ <h2>Schedule a scan</h2>
13
+
14
+ <i>You can configure the scan parameters just like you normally would.</i>
15
+ <br/>
16
+
17
+ Select a Dispatcher:
18
+ <select name="dispatcher">
19
+ <% if !dispatchers.first_alive%>
20
+ <option value="">None available, please add a Dispatcher to continue.</option>
21
+ <%else%>
22
+ <% dispatcher_stats.each_pair do |d_url, stats| %>
23
+ <% next if !dispatchers.alive?( d_url ) %>
24
+ <option value="<%=d_url%>">
25
+ @<%=escape( d_url )%> - <%=stats['running_jobs'].size%> running scans,
26
+ <%=i=0;stats['running_jobs'].each{ |job| i+= proc_mem( job['proc']['rss'] ).to_i }; i.to_s%>MB RAM usage.
27
+ </option>
28
+ <%end%>
29
+ <%end%>
30
+ </select>
31
+
32
+ URL: <input name="url" value="<%=session['opts']['settings']['url']%>" size="50" <% if !dispatchers.first_alive%> disabled="disabled"<%end%> />
33
+ Schedule for: <input id="datetime" name="datetime" <% if !dispatchers.first_alive%> disabled="disabled"<%end%> />
34
+
35
+ <%= csrf_tag %>
36
+ <input type="submit" value="Add" <% if !dispatchers.first_alive%> disabled="disabled"<%end%> />
37
+
38
+ </form>
39
+ </div>
40
+
41
+
42
+ <% if !jobs.empty? %>
43
+ <table>
44
+ <tr>
45
+ <th>ID</th>
46
+ <th>Dispatcher</th>
47
+ <th>Target</th>
48
+ <th>Starts at</th>
49
+ <th>Created by</th>
50
+ <th>Created at</th>
51
+ </tr>
52
+ <% jobs.each do |job| %>
53
+ <tr>
54
+
55
+
56
+ <td><%=job.id%></td>
57
+ <td><%=job.dispatcher%></td>
58
+ <td><%=job.url%></td>
59
+ <td><%=job.datetime%></td>
60
+ <td><%=job.owner_host%> (<%=job.owner_addr%>)</td>
61
+ <td><%=job.created_at%></td>
62
+ <td>
63
+ <form action="<%=root%>/<%=job.id%>/delete" method="post">
64
+ <%= csrf_tag %>
65
+ <input type="submit" value="Delete" />
66
+ </form>
67
+
68
+ <form action="#" onsubmit="showDialog( '#dialog_options_<%=job.id%>' ); return;" >
69
+ <input type="submit" value="Options" />
70
+ </form>
71
+
72
+ <form action="#" onsubmit="showDialog( '#dialog_modules_<%=job.id%>' ); return;" >
73
+ <input type="submit" value="Modules" />
74
+ </form>
75
+
76
+ <form action="#" onsubmit="showDialog( '#dialog_plugins_<%=job.id%>' ); return;" >
77
+ <input type="submit" value="Plugins" />
78
+ </form>
79
+
80
+ </td>
81
+ </tr>
82
+ <tr>
83
+
84
+ <% stored_opts = YAML::load( job.opts ); opts = stored_opts['settings'] %>
85
+
86
+ <%=partial :options, :job => job, :opts => opts %>
87
+
88
+ <div style="display: none" id="dialog_modules_<%=job.id%>" title="Modules">
89
+ <p>
90
+ <ul>
91
+ <% stored_opts['modules'].each do |name| %>
92
+ <li><%=name%></li>
93
+ <%end%>
94
+ </ul>
95
+ </p>
96
+
97
+ </div>
98
+
99
+ <div style="display: none" id="dialog_plugins_<%=job.id%>" title="Plugins">
100
+ <p>
101
+ <ul>
102
+ <% stored_opts['plugins'].each do |plugin| %>
103
+ <li><%=plugin[0]%></li>
104
+ <%end%>
105
+ </ul>
106
+ </p>
107
+
108
+ </div>
109
+
110
+
111
+ </tr>
112
+ <% end %>
113
+ </table>
114
+ <% else %>
115
+ <p class="notice"> There are no scheduled scans at the moment.</p>
116
+ <% end %>
117
+
118
+ <script type="text/javascript">
119
+ //<![CDATA[
120
+
121
+ $('#datetime').datetimepicker();
122
+
123
+ function showDialog( id ){
124
+ $( id ).dialog({
125
+ height: 500,
126
+ width: 1000,
127
+ modal: true
128
+ });
129
+ }
130
+ //]]>
131
+ </script>