arachni 0.2.2.1 → 0.2.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +30 -0
- data/CONTRIBUTORS.md +1 -0
- data/README.md +28 -8
- data/Rakefile +1 -0
- data/bin/arachni_web_autostart +46 -0
- data/lib/anemone/page.rb +1 -0
- data/lib/arachni.rb +1 -1
- data/lib/framework.rb +8 -3
- data/lib/http.rb +9 -39
- data/lib/mixins/observable.rb +87 -0
- data/lib/module/auditor.rb +14 -0
- data/lib/module/base.rb +0 -14
- data/lib/nokogiri/xml/node.rb +42 -0
- data/lib/ui/cli/cli.rb +1 -1
- data/lib/ui/web/log.rb +21 -14
- data/lib/ui/web/report_manager.rb +100 -15
- data/lib/ui/web/server.rb +24 -33
- data/lib/ui/web/server/public/reports/demo.testfire.net:Sun Mar 20 02:48:10 2011.afr +104829 -0
- data/lib/ui/web/server/views/layout.erb +1 -1
- data/lib/ui/web/server/views/options.erb +10 -2
- data/lib/ui/web/server/views/plugins.erb +1 -1
- data/lib/ui/web/server/views/reports.erb +8 -4
- data/lib/ui/xmlrpc/xmlrpc.rb +1 -1
- data/metamodules/autothrottle.rb +2 -2
- data/metamodules/timeout_notice.rb +1 -1
- data/modules/audit/sqli_blind_rdiff.rb +1 -1
- data/modules/recon/common_files/filenames.txt +2 -0
- data/modules/recon/directory_listing.rb +1 -0
- data/modules/recon/interesting_responses.rb +3 -3
- data/path_extractors/generic.rb +5 -1
- data/plugins/autologin.rb +15 -4
- data/plugins/content_types.rb +2 -2
- data/plugins/cookie_collector.rb +9 -16
- data/plugins/profiler.rb +237 -0
- data/reports/html.rb +21 -6
- data/reports/html/default.erb +4 -2
- data/reports/plugin_formatters/html/autologin.rb +63 -0
- data/reports/plugin_formatters/html/profiler.rb +71 -0
- data/reports/plugin_formatters/html/profiler/template.erb +177 -0
- data/reports/plugin_formatters/stdout/autologin.rb +55 -0
- data/reports/plugin_formatters/stdout/profiler.rb +90 -0
- data/reports/plugin_formatters/xml/autologin.rb +68 -0
- data/reports/plugin_formatters/xml/profiler.rb +120 -0
- metadata +23 -68
data/reports/html.rb
CHANGED
@@ -111,12 +111,14 @@ class HTML < Arachni::Report::Base
|
|
111
111
|
}
|
112
112
|
}
|
113
113
|
|
114
|
+
@total_severities = 0
|
115
|
+
@total_elements = 0
|
116
|
+
@total_verifications = 0
|
114
117
|
@audit_store.issues.each_with_index {
|
115
118
|
|issue, i|
|
116
119
|
|
117
120
|
@graph_data[:severities][issue.severity] ||= 0
|
118
121
|
@graph_data[:severities][issue.severity] += 1
|
119
|
-
@total_severities ||= 0
|
120
122
|
@total_severities += 1
|
121
123
|
|
122
124
|
@graph_data[:issues][issue.name] ||= 0
|
@@ -124,19 +126,20 @@ class HTML < Arachni::Report::Base
|
|
124
126
|
|
125
127
|
@graph_data[:elements][issue.elem] ||= 0
|
126
128
|
@graph_data[:elements][issue.elem] += 1
|
127
|
-
@total_elements ||= 0
|
128
129
|
@total_elements += 1
|
129
130
|
|
130
131
|
verification = issue.verification ? 'Yes' : 'No'
|
131
132
|
@graph_data[:verification][verification] ||= 0
|
132
133
|
@graph_data[:verification][verification] += 1
|
133
|
-
@total_verifications ||= 0
|
134
134
|
@total_verifications += 1
|
135
135
|
|
136
136
|
issue.variations.each_with_index {
|
137
137
|
|variation, j|
|
138
138
|
|
139
139
|
if( variation['response'] && !variation['response'].empty? )
|
140
|
+
|
141
|
+
variation['response'] = variation['response'].force_encoding( 'utf-8' )
|
142
|
+
|
140
143
|
@audit_store.issues[i].variations[j]['escaped_response'] =
|
141
144
|
Base64.encode64( variation['response'] ).gsub( /\n/, '' )
|
142
145
|
end
|
@@ -158,17 +161,29 @@ class HTML < Arachni::Report::Base
|
|
158
161
|
|
159
162
|
@graph_data[:severities].each {
|
160
163
|
|severity, cnt|
|
161
|
-
|
164
|
+
begin
|
165
|
+
@graph_data[:severities][severity] = ((cnt/Float(@total_severities)) * 100).to_i
|
166
|
+
rescue
|
167
|
+
@graph_data[:severities][severity] = 0
|
168
|
+
end
|
162
169
|
}
|
163
170
|
|
164
171
|
@graph_data[:elements].each {
|
165
172
|
|elem, cnt|
|
166
|
-
|
173
|
+
begin
|
174
|
+
@graph_data[:elements][elem] = ((cnt/Float(@total_elements)) * 100).to_i
|
175
|
+
rescue
|
176
|
+
@graph_data[:elements][elem] = 0
|
177
|
+
end
|
167
178
|
}
|
168
179
|
|
169
180
|
@graph_data[:verification].each {
|
170
181
|
|verification, cnt|
|
171
|
-
|
182
|
+
begin
|
183
|
+
@graph_data[:verification][verification] = ((cnt/Float(@total_verifications)) * 100).to_i
|
184
|
+
rescue
|
185
|
+
@graph_data[:verification][verification] = 0
|
186
|
+
end
|
172
187
|
}
|
173
188
|
|
174
189
|
end
|
data/reports/html/default.erb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
<%# Encoding: utf-8%>
|
2
|
+
|
1
3
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
2
4
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
5
|
|
@@ -180,7 +182,7 @@
|
|
180
182
|
|
181
183
|
var verification;
|
182
184
|
$(document).ready(function() {
|
183
|
-
|
185
|
+
verification = new Highcharts.Chart({
|
184
186
|
chart: {
|
185
187
|
renderTo: 'chart-verification',
|
186
188
|
backgroundColor: '#ccc'
|
@@ -949,7 +951,7 @@
|
|
949
951
|
<p> </p>
|
950
952
|
|
951
953
|
<%@plugins.values.each do |plugin|%>
|
952
|
-
<p><%=plugin%></p>
|
954
|
+
<p><%=plugin.force_encoding( 'utf-8' )%></p>
|
953
955
|
<%end%>
|
954
956
|
</section>
|
955
957
|
|
@@ -0,0 +1,63 @@
|
|
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
|
+
|
13
|
+
module Reports
|
14
|
+
|
15
|
+
class HTML
|
16
|
+
module PluginFormatters
|
17
|
+
|
18
|
+
#
|
19
|
+
# HTML formatter for the results of the AutoLogin plugin
|
20
|
+
#
|
21
|
+
# @author: Tasos "Zapotek" Laskos
|
22
|
+
# <tasos.laskos@gmail.com>
|
23
|
+
# <zapotek@segfault.gr>
|
24
|
+
# @version: 0.1
|
25
|
+
#
|
26
|
+
class AutoLogin < Arachni::Plugin::Formatter
|
27
|
+
|
28
|
+
def initialize( plugin_data )
|
29
|
+
@results = plugin_data[:results]
|
30
|
+
@description = plugin_data[:description]
|
31
|
+
end
|
32
|
+
|
33
|
+
def run
|
34
|
+
return ERB.new( tpl ).result( binding )
|
35
|
+
end
|
36
|
+
|
37
|
+
def tpl
|
38
|
+
%q{
|
39
|
+
<h3>AutoLogin</h3>
|
40
|
+
<blockquote><pre><%=::Arachni::Reports::HTML.prep_description(@description)%></pre></blockquote>
|
41
|
+
|
42
|
+
<h4>Result</h4>
|
43
|
+
<blockquote><%=@results[:msg]%></blockquote>
|
44
|
+
|
45
|
+
<% if @results[:cookies].is_a?( Hash )%>
|
46
|
+
<h5>Cookies were set to:</h5>
|
47
|
+
<ul>
|
48
|
+
<% @results[:cookies].each_pair do |name, val|%>
|
49
|
+
<li><%=name%> = <%=val%></li>
|
50
|
+
<%end%>
|
51
|
+
<ul>
|
52
|
+
<%end%>
|
53
|
+
}
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,71 @@
|
|
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 'json'
|
12
|
+
|
13
|
+
module Arachni
|
14
|
+
|
15
|
+
module Reports
|
16
|
+
|
17
|
+
class HTML
|
18
|
+
module PluginFormatters
|
19
|
+
|
20
|
+
#
|
21
|
+
# HTML formatter for the results of the Profiler plugin
|
22
|
+
#
|
23
|
+
# @author: Tasos "Zapotek" Laskos
|
24
|
+
# <tasos.laskos@gmail.com>
|
25
|
+
# <zapotek@segfault.gr>
|
26
|
+
# @version: 0.1
|
27
|
+
#
|
28
|
+
class Profiler < Arachni::Plugin::Formatter
|
29
|
+
|
30
|
+
def initialize( plugin_data )
|
31
|
+
@results = plugin_data[:results]
|
32
|
+
@description = plugin_data[:description]
|
33
|
+
end
|
34
|
+
|
35
|
+
def run
|
36
|
+
|
37
|
+
@results['times'].each_with_index {
|
38
|
+
|itm, i|
|
39
|
+
@results['times'][i] = escape_hash( itm )
|
40
|
+
}
|
41
|
+
|
42
|
+
times = @results['times'].map{ |item| item['time'] }
|
43
|
+
total_time = 0
|
44
|
+
times.each {
|
45
|
+
|time|
|
46
|
+
total_time += time
|
47
|
+
}
|
48
|
+
|
49
|
+
avg_time = total_time / times.size
|
50
|
+
times.reject!{ |time| time < avg_time }
|
51
|
+
|
52
|
+
return ERB.new( IO.read( File.dirname( __FILE__ ) + '/profiler/template.erb' ) ).result( binding )
|
53
|
+
end
|
54
|
+
|
55
|
+
def escape_hash( hash )
|
56
|
+
hash.each_pair {
|
57
|
+
|k, v|
|
58
|
+
hash[k] = CGI.escape( v ) if v.is_a?( String )
|
59
|
+
hash[k] = escape_hash( v ) if v.is_a? Hash
|
60
|
+
}
|
61
|
+
|
62
|
+
return hash
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
<h3>Profiler</h3>
|
2
|
+
<blockquote><pre><%=::Arachni::Reports::HTML.prep_description(@description)%></pre></blockquote>
|
3
|
+
|
4
|
+
<script type="text/javascript">
|
5
|
+
|
6
|
+
var tooltip_data = <%=@results['times'].to_json%>;
|
7
|
+
var chart;
|
8
|
+
$(document).ready(function() {
|
9
|
+
chart = new Highcharts.Chart({
|
10
|
+
chart: {
|
11
|
+
renderTo: 'chart-response-times',
|
12
|
+
zoomType: 'x',
|
13
|
+
spacingRight: 20,
|
14
|
+
backgroundColor: '#ccc'
|
15
|
+
},
|
16
|
+
title: {
|
17
|
+
text: 'Response times exceeding the average (<%=times.size%> out of <%=@results['times'].size%> responses)'
|
18
|
+
},
|
19
|
+
subtitle: {
|
20
|
+
text: document.ontouchstart === undefined ?
|
21
|
+
'Click and drag in the plot area to zoom in' :
|
22
|
+
'Drag your finger over the plot to zoom in'
|
23
|
+
},
|
24
|
+
xAxis: {
|
25
|
+
title: {
|
26
|
+
text: null
|
27
|
+
}
|
28
|
+
},
|
29
|
+
yAxis: {
|
30
|
+
title: {
|
31
|
+
text: 'Seconds'
|
32
|
+
},
|
33
|
+
min: <%=times.min%>,
|
34
|
+
startOnTick: false,
|
35
|
+
showFirstLabel: false
|
36
|
+
},
|
37
|
+
tooltip: {
|
38
|
+
formatter: function() {
|
39
|
+
return 'URL: <b>' + unescape( tooltip_data[this.x]['url'] ) + '</b><br/>' +
|
40
|
+
'Response time: <b>' + this.y +'</b> seconds<br/>';
|
41
|
+
}
|
42
|
+
},
|
43
|
+
legend: {
|
44
|
+
enabled: false
|
45
|
+
},
|
46
|
+
plotOptions: {
|
47
|
+
area: {
|
48
|
+
fillColor: {
|
49
|
+
linearGradient: [0, 0, 0, 300],
|
50
|
+
stops: [
|
51
|
+
[0, 'rgba(0,0,0,0)'],
|
52
|
+
[1, 'rgba(2,0,0,0)']
|
53
|
+
]
|
54
|
+
},
|
55
|
+
lineWidth: 1,
|
56
|
+
marker: {
|
57
|
+
enabled: false,
|
58
|
+
states: {
|
59
|
+
hover: {
|
60
|
+
enabled: true,
|
61
|
+
radius: 5
|
62
|
+
}
|
63
|
+
}
|
64
|
+
},
|
65
|
+
shadow: false,
|
66
|
+
states: {
|
67
|
+
hover: {
|
68
|
+
lineWidth: 1
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}
|
72
|
+
},
|
73
|
+
|
74
|
+
series: [{
|
75
|
+
type: 'area',
|
76
|
+
pointInterval: 1,
|
77
|
+
data: <%=times.to_s%>
|
78
|
+
}]
|
79
|
+
});
|
80
|
+
|
81
|
+
|
82
|
+
});
|
83
|
+
</script>
|
84
|
+
|
85
|
+
|
86
|
+
<h4>Response time analysis</h4>
|
87
|
+
|
88
|
+
<strong>Average response time</strong>: <%=avg_time%> seconds <br/>
|
89
|
+
<strong>Max</strong>: <%=times.max%> seconds <br/>
|
90
|
+
<strong>Min</strong>: <%=@results['times'].map{ |item| item['time'] }.min%> seconds <br/>
|
91
|
+
<strong>Sample size</strong>: <%=@results['times'].size%> responses <br/>
|
92
|
+
|
93
|
+
<div id="chart-response-times" style="width: 1000px"></div>
|
94
|
+
|
95
|
+
<p> </p>
|
96
|
+
|
97
|
+
<h4>Inputs that affect output (Taint analysis)</h4>
|
98
|
+
<% @results['inputs'].each_with_index do |item, idx| %>
|
99
|
+
|
100
|
+
<h5>
|
101
|
+
<%=item['element']['type'].capitalize%>
|
102
|
+
|
103
|
+
<%if item['element']['name']%>
|
104
|
+
named '<%=item['element']['name']%>'
|
105
|
+
<%end%>
|
106
|
+
|
107
|
+
<%if item['element']['altered']%>
|
108
|
+
using the '<%=item['element']['altered']%>' input
|
109
|
+
<%end%>
|
110
|
+
|
111
|
+
<%if item['element']['owner']%>
|
112
|
+
at <a href="<%=CGI.escapeHTML( item['element']['owner'] )%>"> <%=item['element']['owner']%> </a>
|
113
|
+
<%end%>
|
114
|
+
|
115
|
+
<%if item['element']['action']%>
|
116
|
+
pointing to <a href="<%=CGI.escapeHTML( item['element']['action'] )%>"> <%=item['element']['action']%> </a>
|
117
|
+
<%end%>
|
118
|
+
|
119
|
+
<%if item['element']['method']%>
|
120
|
+
using <%=item['request']['method']%>
|
121
|
+
<%end%>
|
122
|
+
</h5>
|
123
|
+
|
124
|
+
<p>
|
125
|
+
It was submitted using the following parameters:
|
126
|
+
<ul>
|
127
|
+
<%item['element']['auditable'].each_pair do |k, v| %>
|
128
|
+
<li><%=k%> = <%=v%></li>
|
129
|
+
<%end%>
|
130
|
+
</ul>
|
131
|
+
|
132
|
+
The taint landed in the following elements at <a href="<%=CGI.escapeHTML( item['request']['url'] )%>"> <%=item['request']['url']%> </a>:
|
133
|
+
<ul>
|
134
|
+
<%item['landed'].each do |elem| %>
|
135
|
+
<li>
|
136
|
+
<%=elem['type'].capitalize%>
|
137
|
+
|
138
|
+
<%if elem['name']%>
|
139
|
+
named '<%=elem['name']%>'
|
140
|
+
<%end%>
|
141
|
+
|
142
|
+
<%if elem['altered']%>
|
143
|
+
using the '<%=elem['altered']%>' input
|
144
|
+
<%end%>
|
145
|
+
|
146
|
+
<%if elem['auditable']%>
|
147
|
+
<ul>
|
148
|
+
<%elem['auditable'].each_pair do |k, v| %>
|
149
|
+
<li><%=k%> = <%=v%></li>
|
150
|
+
<%end%>
|
151
|
+
</ul>
|
152
|
+
<%end%>
|
153
|
+
</li>
|
154
|
+
<%end%>
|
155
|
+
</ul>
|
156
|
+
|
157
|
+
<div class="hidden" id="inspection-dialog_<%=idx%>" title="Relevant content is shown in red.">
|
158
|
+
<% match = CGI.escapeHTML( item['response']['body'] )%>
|
159
|
+
<pre> <%=CGI.escapeHTML( item['response']['body'] ).gsub( item['taint'], '<strong style="color: red">' + item['taint'] + '</strong>' ) %> </pre>
|
160
|
+
</div>
|
161
|
+
|
162
|
+
<form style="display:inline" action="#">
|
163
|
+
<input onclick="javascript:inspect( '#inspection-dialog_<%=idx%>')" type="button" value="Inspect" />
|
164
|
+
</form>
|
165
|
+
|
166
|
+
<form style="display:inline" action="<%=item['request']['url']%>" target="_blank" method="<%=item['request']['method']%>">
|
167
|
+
<% item['request']['params'].each_pair do |name, value|%>
|
168
|
+
<input type="hidden" name="<%=CGI.escapeHTML(name)%>" value="<%=CGI.escapeHTML( value )%>" />
|
169
|
+
<%end%>
|
170
|
+
<input type="submit" value="Replay" />
|
171
|
+
</form>
|
172
|
+
|
173
|
+
</p>
|
174
|
+
|
175
|
+
<p> </p>
|
176
|
+
|
177
|
+
<%end%>
|
@@ -0,0 +1,55 @@
|
|
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 Reports
|
13
|
+
|
14
|
+
class Stdout
|
15
|
+
module PluginFormatters
|
16
|
+
|
17
|
+
#
|
18
|
+
# Stdout formatter for the results of the AutoLogin plugin
|
19
|
+
#
|
20
|
+
#
|
21
|
+
# @author: Tasos "Zapotek" Laskos
|
22
|
+
# <tasos.laskos@gmail.com>
|
23
|
+
# <zapotek@segfault.gr>
|
24
|
+
# @version: 0.1
|
25
|
+
#
|
26
|
+
class AutoLogin < Arachni::Plugin::Formatter
|
27
|
+
|
28
|
+
def initialize( plugin_data )
|
29
|
+
@results = plugin_data[:results]
|
30
|
+
@description = plugin_data[:description]
|
31
|
+
end
|
32
|
+
|
33
|
+
def run
|
34
|
+
print_status( 'AutoLogin' )
|
35
|
+
print_info( '~~~~~~~~~~~~~~' )
|
36
|
+
|
37
|
+
print_info( 'Description: ' + @description )
|
38
|
+
print_line
|
39
|
+
print_ok( @results[:msg] )
|
40
|
+
|
41
|
+
return if !@results[:cookies]
|
42
|
+
print_info( 'Cookies set to:' )
|
43
|
+
@results[:cookies].each_pair {
|
44
|
+
|name, val|
|
45
|
+
print_info( ' * ' + name + ' = ' + val )
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|