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,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>