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
File without changes
@@ -307,6 +307,48 @@ li ol, li ul {
307
307
  text-decoration: none;
308
308
  }
309
309
 
310
+ #nav ul ul {
311
+ position:absolute;
312
+ display: none; /* Hide off-screen when not needed (this is more accessible than display:none;) */
313
+ background: none;
314
+ margin-left: -6px
315
+ }
316
+
317
+ #nav ul li:hover ul li{
318
+ list-style: none;
319
+ margin: 0;
320
+ height: 50px;
321
+ background: none;
322
+ }
323
+
324
+ #nav li:hover ul { /* Display the dropdown on hover */
325
+ display: block; /* Bring back on-screen when needed */
326
+ background: none;
327
+
328
+ -moz-border-radius-bottomleft: 10px;
329
+ -moz-border-radius-bottomright: 10px;
330
+ -webkit-border-radius-bottomright: 10px;
331
+ -webkit-border-radius-bottomleft: 10px;
332
+ }
333
+
334
+ #nav li:hover a{ /* These create persistent hover states, meaning the top-most link stays 'hovered' even when your cursor has moved down the list. */
335
+ }
336
+
337
+ #nav li:hover ul a{ /* The persistent hover state does however create a global style for links even before they're hovered. Here we undo these effects. */
338
+ text-decoration: none;
339
+ background: #202020;
340
+ -moz-border-radius-bottomleft: 10px;
341
+ -moz-border-radius-bottomright: 10px;
342
+ -webkit-border-radius-bottomright: 10px;
343
+ -webkit-border-radius-bottomleft: 10px;
344
+ height: 10px
345
+ }
346
+
347
+ #nav li:hover ul li a:hover{ /* Here we define the most explicit hover states--what happens when you hover each individual link. */
348
+ background: #333;
349
+ }
350
+
351
+
310
352
  #page-intro {
311
353
  height: 150px;
312
354
  padding: 50px 20px 0;
@@ -0,0 +1,15 @@
1
+
2
+ <div id="page-intro">
3
+ <h2><%=escape( addon['name'] )%> v<%=escape( addon['version'] )%></h2>
4
+ <p>
5
+ <%=escape( addon['description'] )%>
6
+ <br/>
7
+ <i>By <%=escape( addon['author'] )%></i>
8
+ </p>
9
+ </div>
10
+
11
+ <%= erb :flash, {:layout => false} %>
12
+
13
+
14
+ <%= erb tpl, {:layout => false}, tpl_args %>
15
+
@@ -0,0 +1,46 @@
1
+
2
+ <div id="page-intro">
3
+ <form action="/addons" method="post">
4
+
5
+ <h2>Add-ons</h2>
6
+ <p>This page allows you to enable add-ons in order to extend the functionality of the WebUI.
7
+ <br/><br/>
8
+ </p>
9
+
10
+ <% if !addons.available.empty? %>
11
+ <%= csrf_tag %>
12
+ <input type="submit" value="Save" />
13
+ <% end %>
14
+
15
+ </div>
16
+ <%= erb :flash, {:layout => false} %>
17
+
18
+ <% if !addons.available.empty? %>
19
+ <table>
20
+ <tr>
21
+ <th>Name</th>
22
+ <th>Description</th>
23
+ <th>Author</th>
24
+ <th>Version</th>
25
+ <th>Enable</th>
26
+ </tr>
27
+ <% addons.available.each do |addon| %>
28
+ <tr>
29
+
30
+ <td><%=escape( addon['name'] )%></td>
31
+ <td><%=escape( addon['description'] )%></td>
32
+ <td><%=escape( addon['author'] )%></td>
33
+ <td><%=escape( addon['version'] )%></td>
34
+
35
+ <td>
36
+ <input type="checkbox" class="audit" name="addons[<%=addon['filename']%>]"
37
+ <% if addons.enabled.include?( addon['filename'] ) %>
38
+ checked="checked" <% end %> />
39
+ </td>
40
+ </tr>
41
+ <% end %>
42
+ </table>
43
+ </form>
44
+ <% else %>
45
+ <span class="notice"> There are no available add-ons at the moment.</span>
46
+ <% end %>
@@ -21,7 +21,7 @@
21
21
  </h2>
22
22
 
23
23
  <%if !dispatcher_stats['running_jobs'].empty? %>
24
- <form action="/dispatchers/<%=sanitize_url( d_url.dup )%>/shutdown_all" method="post">
24
+ <form action="/dispatchers/<%=remove_proto( d_url.dup )%>/shutdown_all" method="post">
25
25
  <%= csrf_tag %>
26
26
  <input type="submit" value="Shutdown all" />
27
27
  </form>
@@ -1,6 +1,6 @@
1
1
 
2
2
  <div id="page-intro">
3
- <h2 id="page_header">Attached to instance @<%=sanitize_url( params['url'] )%></h2>
3
+ <h2 id="page_header">Attached to instance @<%=remove_proto( params['url'] )%></h2>
4
4
  <p id="page_description">
5
5
  This page allows you to see what's going on at the other end of the wire (i.e. get status messages directly from the remote scanner).
6
6
  <br/>
@@ -11,20 +11,20 @@
11
11
  <%if !shutdown %>
12
12
 
13
13
  <%if !paused %>
14
- <form action="/instance/<%=sanitize_url( params['url'] )%>/pause" method="post">
14
+ <form action="/instance/<%=remove_proto( params['url'] )%>/pause" method="post">
15
15
  <%= csrf_tag %>
16
16
  <input type="submit" value="Pause" />
17
17
  </form>
18
18
  <%end%>
19
19
 
20
20
  <%if paused %>
21
- <form action="/instance/<%=sanitize_url( params['url'] )%>/resume" method="post">
21
+ <form action="/instance/<%=remove_proto( params['url'] )%>/resume" method="post">
22
22
  <%= csrf_tag %>
23
23
  <input type="submit" value="Resume" />
24
24
  </form>
25
25
  <%end%>
26
26
 
27
- <form action="/instance/<%=sanitize_url( params['url'] )%>/shutdown" method="post">
27
+ <form action="/instance/<%=remove_proto( params['url'] )%>/shutdown" method="post">
28
28
  <%= csrf_tag %>
29
29
  <input type="submit" value="Shutdown" />
30
30
  </form>
@@ -39,9 +39,9 @@
39
39
  <h3>Scan statisics</h3>
40
40
  <div class="left">
41
41
  <ul>
42
- <li>Pages audited: <span id="audited">0</span></li>
43
- <li>Pages crawled: <span id="crawled">0</span></li>
42
+ <li>Pages discovered: <span id="crawled">0</span></li>
44
43
  <li>Progress: <span id="percentage">0</span>%</li>
44
+ <li>Runtime: <span id="runtime">00:00:00</span></li>
45
45
  </ul>
46
46
  </div>
47
47
  <div>
@@ -120,15 +120,14 @@
120
120
  function setStats( stats ){
121
121
  if( stats == undefined ){ return }
122
122
 
123
- document.getElementById( 'audited' ).innerHTML = stats.auditmap_size;
124
123
  document.getElementById( 'crawled' ).innerHTML = stats.sitemap_size;
125
124
  document.getElementById( 'current_page' ).innerHTML = stats.current_page;
126
125
  document.getElementById( 'average_res_time' ).innerHTML = stats.average_res_time;
127
126
  document.getElementById( 'time_out_count' ).innerHTML = stats.time_out_count;
128
127
  document.getElementById( 'max_concurrency' ).innerHTML = stats.max_concurrency;
129
128
 
130
- percentage = (stats.auditmap_size / stats.sitemap_size) * 100
131
- document.getElementById( 'percentage' ).innerHTML = parseInt( percentage );
129
+ document.getElementById( 'runtime' ).innerHTML = stats.time;
130
+ document.getElementById( 'percentage' ).innerHTML = parseInt( stats.progress );
132
131
  }
133
132
 
134
133
  function updateProgressBar(){
@@ -136,8 +135,7 @@
136
135
  $.getJSON( stats_url, function(data) {
137
136
  if( data.stats == undefined ){ return }
138
137
  setStats( data.stats );
139
- percentage = (data.stats.auditmap_size / data.stats.sitemap_size) * 100
140
- setProgressBar( percentage );
138
+ setProgressBar( parseInt( data.stats.progress ) );
141
139
  });
142
140
  }
143
141
 
@@ -9,6 +9,7 @@
9
9
 
10
10
  <script type="text/javascript" src="/js/jquery-1.4.4.min.js"></script>
11
11
  <script type="text/javascript" src="/js/jquery-ui-1.8.9.custom.min.js"></script>
12
+ <script type="text/javascript" src="/js/jquery-ui-timepicker.js"></script>
12
13
 
13
14
  <script type="text/javascript">
14
15
  function checkAll( type ) {
@@ -37,6 +38,17 @@
37
38
  <li <% if selected_tab?( 'plugins' )%>class="selected" <%end%>><a href="/plugins">Plugins</a></li>
38
39
  <li <% if selected_tab?( 'settings' )%>class="selected" <%end%>><a href="/settings">Settings</a></li>
39
40
  <li <% if selected_tab?( 'reports' )%>class="selected" <%end%>><a href="/reports">Reports [<%=report_count%>]</a></li>
41
+ <li <% if selected_tab?( 'addons' )%>class="selected" <%end%>><a href="/addons">Add-ons <%if !addons.enabled.empty? %>&darr;<%end%> [<%=addons.enabled.size%>/<%=addons.available.size%>]</a>
42
+
43
+ <% if !addons.enabled.empty?%>
44
+ <ul>
45
+ <% addons.enabled.each do |name| %>
46
+ <li><a href="/addons/<%=escape( name )%>/"><%= escape( addons.by_name( name )['title'] ) %></a></li>
47
+ <%end%>
48
+ </ul>
49
+ <%end%>
50
+
51
+ </li>
40
52
  <li <% if selected_tab?( 'dispatchers' )%>class="selected" <%end%>><a href="/dispatchers">Dispatchers</a></li>
41
53
  <li <% if selected_tab?( 'log' )%>class="selected" <%end%>><a href="/log">Log</a></li>
42
54
  </ul>
@@ -55,7 +67,7 @@
55
67
  <div class="footer-content">
56
68
 
57
69
  <div class="footer-box">
58
- <h4><a href="https://github.com/Zapotek/arachni">About Arachni</a></h4>
70
+ <h4><a href="http://arachni.segfault.gr">About Arachni</a></h4>
59
71
  <p>
60
72
  Arachni is a feature-full, modular, high-performance Ruby framework aimed towards <br/>
61
73
  helping penetration testers and administrators evaluate the security of web applications.
@@ -77,6 +89,7 @@
77
89
 
78
90
  <h4>Interesting links</h4>
79
91
  <ul>
92
+ <li><a href="http://arachni.segfault.gr">Homepage</a></li>
80
93
  <li><a href="http://trainofthought.segfault.gr/category/projects/arachni/">News straight from the developer's blog</a></li>
81
94
  <li><a href="http://twitter.com/Zap0tek">Developer's Twitter feed</a></li>
82
95
  <li><a href="https://github.com/Zapotek/arachni/tree/experimental">The bleeding edge, Arachni's experimental branch</a></li>
@@ -14,10 +14,11 @@
14
14
  <p>
15
15
  It is a way to:
16
16
  <ul>
17
- <li>make working with Arachni easier</li>
18
- <li>make report management easier</li>
19
- <li>run and manage multiple scans at the same time <em>(each scan will try its best for maximum bandwidth utilization so it'll be like lions fighting in a cage -- make sure you have sufficient resources)</em></li>
20
- <li>work with and manage multiple Dispatchers</li>
17
+ <li>make working with Arachni easier;</li>
18
+ <li>make report management easier;</li>
19
+ <li>enable you to schedule scans;</li>
20
+ <li>run and manage multiple scans at the same time <em>(each scan will try its best for maximum bandwidth utilization so it'll be like lions fighting in a cage -- make sure you have sufficient resources)</em>;</li>
21
+ <li>work with, and manage, multiple Dispatchers.</li>
21
22
  </ul>
22
23
  </p>
23
24
 
@@ -25,8 +26,8 @@
25
26
  <p>
26
27
  It isn't:
27
28
  <ul>
28
- <li>too stable</li>
29
- <li>a way to make Arachni's goodies available to multiple users <em>(you could but it wouldn't be safe)</em></li>
29
+ <li>too stable;</li>
30
+ <li>a way to make Arachni's goodies available to multiple users <em>(you could but it wouldn't be safe)</em>.</li>
30
31
  </ul>
31
32
  </p>
32
33
 
@@ -0,0 +1,134 @@
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
+
15
+ #
16
+ # General utility methods.
17
+ #
18
+ # @author: Tasos "Zapotek" Laskos
19
+ # <tasos.laskos@gmail.com>
20
+ # <zapotek@segfault.gr>
21
+ # @version: 0.1
22
+ #
23
+ module Utilities
24
+
25
+ #
26
+ # Escapes HTML chars.
27
+ #
28
+ # @param [String] str
29
+ #
30
+ # @return [String]
31
+ #
32
+ # @see CGI.escapeHTML
33
+ #
34
+ def escape( str )
35
+ CGI.escapeHTML( str )
36
+ end
37
+
38
+ #
39
+ # Unescapes HTML chars.
40
+ #
41
+ # @param [String] str
42
+ #
43
+ # @return [String]
44
+ #
45
+ # @see CGI.unescapeHTML
46
+ #
47
+ def unescape( str )
48
+ CGI.unescapeHTML( str )
49
+ end
50
+
51
+ #
52
+ # Recursively escapes all HTML characters.
53
+ #
54
+ # @param [Hash] hash
55
+ #
56
+ # @return [Hash]
57
+ #
58
+ def escape_hash( hash )
59
+ hash.each_pair {
60
+ |k, v|
61
+ hash[k] = escape( hash[k] ) if hash[k].is_a?( String )
62
+ hash[k] = escape_hash( v ) if v.is_a? Hash
63
+ }
64
+
65
+ return hash
66
+ end
67
+
68
+ #
69
+ # Recursively unescapes all HTML characters.
70
+ #
71
+ # @param [Hash] hash
72
+ #
73
+ # @return [Hash]
74
+ #
75
+ def unescape_hash( hash )
76
+ hash.each_pair {
77
+ |k, v|
78
+ hash[k] = unescape( hash[k] ) if hash[k].is_a?( String )
79
+ hash[k] = unescape_hash( v ) if v.is_a? Hash
80
+ }
81
+
82
+ return hash
83
+ end
84
+
85
+ #
86
+ # Parses datetime strings such as 07/23/2011 15:34 into Time objects.
87
+ #
88
+ # @param [String] datetime
89
+ #
90
+ # @return [Time]
91
+ #
92
+ def parse_datetime( datetime )
93
+ date, time = datetime.split( ' ' )
94
+
95
+ month, day, year = date.split( '/' )
96
+ hour, minute = time.split( ':' )
97
+
98
+ Time.new( year, month, day, hour, minute )
99
+ end
100
+
101
+ #
102
+ # Constructs an instance URL by port using its dispatcher's url.
103
+ #
104
+ # @param [Integer] port
105
+ # @param [String] dispatcher_url URL of the dispatcher
106
+ # @param [Bool] no_scheme include scheme in the URL?
107
+ #
108
+ # @return [String]
109
+ #
110
+ def port_to_url( port, dispatcher_url, no_scheme = nil )
111
+ uri = URI( dispatcher_url )
112
+ uri.port = port.to_i
113
+ uri = uri.to_s
114
+
115
+ uri = remove_proto( uri ) if no_scheme
116
+ return uri
117
+ end
118
+
119
+ #
120
+ # Removes the protocol from URL string.
121
+ #
122
+ # @param [String] url
123
+ #
124
+ # @return [String]
125
+ #
126
+ def remove_proto( url )
127
+ url.gsub!( 'http://', '' )
128
+ escape( url.gsub( 'https://', '' ) )
129
+ end
130
+
131
+ end
132
+ end
133
+ end
134
+ end
@@ -20,7 +20,7 @@ module Modules
20
20
  # @author: Tasos "Zapotek" Laskos
21
21
  # <tasos.laskos@gmail.com>
22
22
  # <zapotek@segfault.gr>
23
- # @version: 0.2
23
+ # @version: 0.2.1
24
24
  #
25
25
  # @see http://cwe.mitre.org/data/definitions/94.html
26
26
  # @see http://php.net/manual/en/function.eval.php
@@ -63,6 +63,10 @@ class CodeInjectionTiming < Arachni::Module::Base
63
63
  audit_timeout( @@__injection_str, @__opts )
64
64
  end
65
65
 
66
+ def redundant
67
+ [ 'code_injection' ]
68
+ end
69
+
66
70
  def self.info
67
71
  {
68
72
  :name => 'Code injection (timing)',
@@ -76,7 +80,7 @@ class CodeInjectionTiming < Arachni::Module::Base
76
80
  Issue::Element::HEADER
77
81
  ],
78
82
  :author => 'Tasos "Zapotek" Laskos <tasos.laskos@gmail.com> ',
79
- :version => '0.1',
83
+ :version => '0.2.1',
80
84
  :references => {
81
85
  'PHP' => 'http://php.net/manual/en/function.eval.php',
82
86
  'Perl' => 'http://perldoc.perl.org/functions/eval.html',
@@ -1,4 +1,4 @@
1
- sleep(__TIME__);
2
- import time;time.sleep(__TIME__);
1
+ sleep(__TIME__/1000);
2
+ import time;time.sleep(__TIME__/1000);
3
3
  Thread.sleep(__TIME__);
4
4
  Thread.Sleep(__TIME__);
@@ -18,7 +18,7 @@ module Modules
18
18
  # @author: Tasos "Zapotek" Laskos
19
19
  # <tasos.laskos@gmail.com>
20
20
  # <zapotek@segfault.gr>
21
- # @version: 0.2
21
+ # @version: 0.2.1
22
22
  #
23
23
  # @see http://cwe.mitre.org/data/definitions/78.html
24
24
  # @see http://www.owasp.org/index.php/OS_Command_Injection
@@ -50,7 +50,7 @@ class OSCmdInjectionTiming < Arachni::Module::Base
50
50
 
51
51
  @__opts = {
52
52
  :format => [ Format::STRAIGHT ],
53
- :timeout => 4000,
53
+ :timeout => 10000,
54
54
  :timeout_divider => 1000
55
55
  }
56
56
 
@@ -60,6 +60,10 @@ class OSCmdInjectionTiming < Arachni::Module::Base
60
60
  audit_timeout( @@__injection_str, @__opts )
61
61
  end
62
62
 
63
+ def redundant
64
+ [ 'os_cmd_injection' ]
65
+ end
66
+
63
67
  def self.info
64
68
  {
65
69
  :name => 'OS command injection (timing)',
@@ -71,7 +75,7 @@ class OSCmdInjectionTiming < Arachni::Module::Base
71
75
  Issue::Element::HEADER
72
76
  ],
73
77
  :author => 'Tasos "Zapotek" Laskos <tasos.laskos@gmail.com> ',
74
- :version => '0.1',
78
+ :version => '0.2.1',
75
79
  :references => {
76
80
  'OWASP' => 'http://www.owasp.org/index.php/OS_Command_Injection'
77
81
  },