arachni 0.2.3 → 0.2.4
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.
- data/CHANGELOG.md +21 -1
- data/README.md +4 -3
- data/external/metasploit/modules/exploits/unix/webapp/arachni_sqlmap.rb +84 -85
- data/lib/arachni.rb +1 -1
- data/lib/framework.rb +2 -1
- data/lib/http.rb +9 -1
- data/lib/module/auditor.rb +18 -7
- data/lib/ui/cli/cli.rb +16 -8
- data/lib/ui/web/output_stream.rb +4 -4
- data/lib/ui/web/server.rb +7 -5
- data/lib/ui/web/server/views/dispatchers.erb +1 -1
- data/lib/ui/web/server/views/instance.erb +2 -0
- data/lib/ui/web/server/views/output_results.erb +1 -1
- data/reports/html.rb +8 -7
- metadata +2 -2
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,27 @@
|
|
1
1
|
|
2
2
|
# ChangeLog
|
3
3
|
|
4
|
-
## Version 0.2.
|
4
|
+
## Version 0.2.4 _(July 1, 2011)_
|
5
|
+
- HTTP
|
6
|
+
- Implemented a 10s time-out [Issue #40]
|
7
|
+
- Command Line Interface
|
8
|
+
- The interrupt handler (Ctrl+C) now presents the option to generate reports mid-scan. [Issue #41]
|
9
|
+
- Added a counter of timed-out requests in the stats.
|
10
|
+
- WebUI
|
11
|
+
- The "Replay" form's action attribute now contains the full URL, including params. [Issue #38]
|
12
|
+
- Fixed path clash that caused the "shutdown" button in the Dispatchers screen not to work. [Issue #39]
|
13
|
+
- Fixed mix-up of output messages from different instances. [Issue #36]
|
14
|
+
- Added a counter of timed-out requests in "Instance" screens.
|
15
|
+
- External
|
16
|
+
- Metasploit
|
17
|
+
- Updated SQL injection exploit module to work with SQLmap 0.9. [Issue #37]
|
18
|
+
- Reports
|
19
|
+
- HTML
|
20
|
+
- Fixed yet another error condition occuring with broken encodings. [Issue #31]
|
21
|
+
- Auditor
|
22
|
+
- Timing attacks now have a "control" to verify that the server is indeed alive i.e. requests won't time-out by default.
|
23
|
+
|
24
|
+
## Version 0.2.3 _(May 22, 2011)_
|
5
25
|
- WebUI
|
6
26
|
- Added connection cache for XMLRPC server instances to remove HTTPS handshake overhead and take advantage of keep-alive support.
|
7
27
|
- Added initial support for management of multiple Dispatchers.
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
<table>
|
3
3
|
<tr>
|
4
4
|
<th>Version</th>
|
5
|
-
<td>0.2.
|
5
|
+
<td>0.2.4</td>
|
6
6
|
</tr>
|
7
7
|
<tr>
|
8
8
|
<th>Homepage</th>
|
@@ -229,11 +229,12 @@ Still, this can be an invaluable asset to Fuzzer modules.
|
|
229
229
|
|
230
230
|
### CDE packages for Linux
|
231
231
|
|
232
|
-
Arachni is released as [CDE packages](http://stanford.edu/~pgbovine/cde.html) for your convinience.<br/>
|
232
|
+
<del>Arachni is released as [CDE packages](http://stanford.edu/~pgbovine/cde.html) for your convinience.<br/>
|
233
233
|
CDE packages are self contained and thus alleviate the need for Ruby and other dependencies to be installed or root access.<br/>
|
234
234
|
You can download the latest CDE package from the [download](https://github.com/Zapotek/arachni/downloads) page and escape the dependency hell.<br/>
|
235
|
-
If you decide to go the CDE route you can skip the rest, you're done
|
235
|
+
If you decide to go the CDE route you can skip the rest, you're done.</del>
|
236
236
|
|
237
|
+
Due to some incompatibility this release does not have a CDE package yet.
|
237
238
|
|
238
239
|
### Gem
|
239
240
|
|
@@ -2,91 +2,90 @@ require 'msf/core'
|
|
2
2
|
|
3
3
|
class Metasploit3 < Msf::Auxiliary
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
end
|
5
|
+
include Msf::Exploit::Remote::HttpClient
|
6
|
+
|
7
|
+
def initialize(info = {})
|
8
|
+
super(update_info(info,
|
9
|
+
'Name' => 'Arachni SQLMAP SQL Injection External Module',
|
10
|
+
'Description' => %q{
|
11
|
+
|
12
|
+
This module is designed to be used with the Arachni plug-in.
|
13
|
+
|
14
|
+
From the original:
|
15
|
+
|
16
|
+
This module launches an sqlmap session.
|
17
|
+
sqlmap is an automatic SQL injection tool developed in Python.
|
18
|
+
Its goal is to detect and take advantage of SQL injection
|
19
|
+
vulnerabilities on web applications. Once it detects one
|
20
|
+
or more SQL injections on the target host, the user can
|
21
|
+
choose among a variety of options to perform an extensive
|
22
|
+
back-end database management system fingerprint, retrieve
|
23
|
+
DBMS session user and database, enumerate users, password
|
24
|
+
hashes, privileges, databases, dump entire or user
|
25
|
+
specific DBMS tables/columns, run his own SQL SELECT
|
26
|
+
statement, read specific files on the file system and much
|
27
|
+
more.
|
28
|
+
},
|
29
|
+
'Author' => [
|
30
|
+
'Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>', # modified to work with the Arachni plug-in
|
31
|
+
'Bernardo Damele A. G. <bernardo.damele[at]gmail.com>' # original module: auxiliary/scanner/http/sqlmap.rb
|
32
|
+
],
|
33
|
+
'License' => BSD_LICENSE,
|
34
|
+
'Version' => '$Revision: 9212 $',
|
35
|
+
'References' =>
|
36
|
+
[
|
37
|
+
['URL', 'http://github.com/Zapotek/arachni'],
|
38
|
+
['URL', 'http://sqlmap.sourceforge.net'],
|
39
|
+
]
|
40
|
+
))
|
41
|
+
|
42
|
+
register_options(
|
43
|
+
[
|
44
|
+
OptString.new('METHOD', [ true, "HTTP Method", 'GET' ]),
|
45
|
+
OptString.new('PATH', [ true, "The path to test for SQL injection", 'index.php' ]),
|
46
|
+
OptString.new('GET', [ false, "HTTP GET query", 'id=1' ]),
|
47
|
+
OptString.new('POST', [ false, "The data string to be sent through POST", '' ]),
|
48
|
+
OptString.new('COOKIES', [ false, "", '' ]),
|
49
|
+
OptString.new('OPTS', [ false, "The sqlmap options to use", '--users --dbs --sql-shell -v 0' ]),
|
50
|
+
OptPath.new('SQLMAP_PATH', [ true, "The sqlmap 0.9 full path ", 'sqlmap' ]),
|
51
|
+
], self.class)
|
52
|
+
end
|
53
|
+
|
54
|
+
def run
|
55
|
+
|
56
|
+
sqlmap = datastore['SQLMAP_PATH']
|
57
|
+
|
58
|
+
if not sqlmap
|
59
|
+
print_error("The sqlmap script could not be found")
|
60
|
+
return
|
61
|
+
end
|
62
|
+
|
63
|
+
data = datastore['POST'].gsub( 'XXinjectionXX', '' )
|
64
|
+
method = datastore['METHOD'].upcase
|
65
|
+
|
66
|
+
sqlmap_url = (datastore['SSL'] ? "https" : "http")
|
67
|
+
sqlmap_url += "://" + datastore['RHOST'] + ":" + datastore['RPORT']
|
68
|
+
sqlmap_url += "/" + datastore['PATH']
|
69
|
+
|
70
|
+
if method == "GET"
|
71
|
+
sqlmap_url += '?' + datastore['GET'].gsub( 'XXinjectionXX', '' )
|
72
|
+
end
|
73
|
+
|
74
|
+
cmd = sqlmap + ' -u \'' + sqlmap_url + '\''
|
75
|
+
cmd += ' ' + datastore['OPTS']
|
76
|
+
cmd += ' --cookie \'' + datastore['COOKIES'].to_s + '\'' if datastore['COOKIES']
|
77
|
+
|
78
|
+
if not data.empty?
|
79
|
+
cmd += ' --data \'' + data + '\''
|
80
|
+
end
|
81
|
+
|
82
|
+
if datastore['BATCH'] == true
|
83
|
+
cmd += ' --batch'
|
84
|
+
end
|
85
|
+
|
86
|
+
print_status("exec: #{cmd}")
|
87
|
+
system( cmd )
|
88
|
+
end
|
90
89
|
|
91
90
|
end
|
92
91
|
|
data/lib/arachni.rb
CHANGED
data/lib/framework.rb
CHANGED
@@ -57,7 +57,7 @@ module Arachni
|
|
57
57
|
# @author: Tasos "Zapotek" Laskos
|
58
58
|
# <tasos.laskos@gmail.com>
|
59
59
|
# <zapotek@segfault.gr>
|
60
|
-
# @version: 0.2.
|
60
|
+
# @version: 0.2.3
|
61
61
|
#
|
62
62
|
class Framework
|
63
63
|
|
@@ -217,6 +217,7 @@ class Framework
|
|
217
217
|
return {
|
218
218
|
:requests => req_cnt,
|
219
219
|
:responses => res_cnt,
|
220
|
+
:time_out_count => http.time_out_count,
|
220
221
|
:time => audit_store.delta_time,
|
221
222
|
:avg => ( res_cnt / @opts.delta_time ).to_i.to_s,
|
222
223
|
:sitemap_size => @sitemap.size,
|
data/lib/http.rb
CHANGED
@@ -66,6 +66,8 @@ class HTTP
|
|
66
66
|
attr_reader :request_count
|
67
67
|
attr_reader :response_count
|
68
68
|
|
69
|
+
attr_reader :time_out_count
|
70
|
+
|
69
71
|
attr_reader :curr_res_time
|
70
72
|
attr_reader :curr_res_cnt
|
71
73
|
|
@@ -127,11 +129,12 @@ class HTTP
|
|
127
129
|
:user_agent => opts.user_agent,
|
128
130
|
:follow_location => false,
|
129
131
|
:disable_ssl_peer_verification => true,
|
130
|
-
|
132
|
+
:timeout => 10000
|
131
133
|
}.merge( proxy_opts )
|
132
134
|
|
133
135
|
@request_count = 0
|
134
136
|
@response_count = 0
|
137
|
+
@time_out_count = 0
|
135
138
|
|
136
139
|
# we'll use it to identify our requests
|
137
140
|
@rand_seed = seed( )
|
@@ -242,6 +245,11 @@ class HTTP
|
|
242
245
|
print_debug( 'Train?: ' + res.request.train?.to_s )
|
243
246
|
print_debug( '------------' )
|
244
247
|
|
248
|
+
if res.timed_out?
|
249
|
+
print_error( 'Request timed-out! -- ID# ' + res.request.id.to_s )
|
250
|
+
@time_out_count += 1
|
251
|
+
end
|
252
|
+
|
245
253
|
if( req.train? )
|
246
254
|
# handle redirections
|
247
255
|
if( ( redir = redirect?( res.dup ) ).is_a?( String ) )
|
data/lib/module/auditor.rb
CHANGED
@@ -20,7 +20,7 @@ module Module
|
|
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.3
|
24
24
|
#
|
25
25
|
module Auditor
|
26
26
|
|
@@ -359,17 +359,28 @@ module Auditor
|
|
359
359
|
( (opts[:timeout] + 3000) / opts[:timeout_divider] ).to_s )
|
360
360
|
|
361
361
|
elem.auditor( self )
|
362
|
-
|
362
|
+
|
363
|
+
# this is the control; audit the element with an empty seed to make sure
|
364
|
+
# that the web page is alive i.e won't time-out by default
|
365
|
+
elem.audit( '' , opts ) {
|
363
366
|
|res, opts|
|
367
|
+
if !res.timed_out?
|
368
|
+
|
369
|
+
elem.audit( str, opts ) {
|
370
|
+
|res, opts|
|
364
371
|
|
365
|
-
|
372
|
+
if res.timed_out?
|
373
|
+
|
374
|
+
# all issues logged by timing attacks need manual verification.
|
375
|
+
# end of story.
|
376
|
+
opts[:verification] = true
|
377
|
+
log( opts, res)
|
378
|
+
end
|
379
|
+
}
|
366
380
|
|
367
|
-
# all issues logged by timing attacks need manual verification.
|
368
|
-
# end of story.
|
369
|
-
opts[:verification] = true
|
370
|
-
log( opts, res)
|
371
381
|
end
|
372
382
|
}
|
383
|
+
|
373
384
|
end
|
374
385
|
|
375
386
|
def audit_timeout_debug_msg( phase, delay )
|
data/lib/ui/cli/cli.rb
CHANGED
@@ -26,7 +26,7 @@ module UI
|
|
26
26
|
# @author: Tasos "Zapotek" Laskos
|
27
27
|
# <tasos.laskos@gmail.com>
|
28
28
|
# <zapotek@segfault.gr>
|
29
|
-
# @version: 0.1.
|
29
|
+
# @version: 0.1.7
|
30
30
|
# @see Arachni::Framework
|
31
31
|
#
|
32
32
|
class CLI
|
@@ -141,6 +141,7 @@ class CLI
|
|
141
141
|
print_info( "Burst response count total #{stats[:curr_res_cnt]} " )
|
142
142
|
print_info( "Burst average response time #{stats[:average_res_time]}" )
|
143
143
|
print_info( "Burst average #{stats[:curr_avg]} requests/second" )
|
144
|
+
print_info( "Timed-out requests #{stats[:time_out_count]}" )
|
144
145
|
print_info( "Original max concurrency #{@opts.http_req_limit}" )
|
145
146
|
print_info( "Throttled max concurrency #{stats[:max_concurrency]}" )
|
146
147
|
|
@@ -166,13 +167,20 @@ class CLI
|
|
166
167
|
@interrupt_handler = Thread.new {
|
167
168
|
|
168
169
|
Thread.new {
|
169
|
-
if gets[0] == 'e'
|
170
|
-
@@only_positives = false
|
171
|
-
unmute!
|
172
|
-
@interrupt_handler.kill
|
173
170
|
|
174
|
-
|
175
|
-
|
171
|
+
case gets[0]
|
172
|
+
|
173
|
+
when 'e'
|
174
|
+
@@only_positives = false
|
175
|
+
unmute!
|
176
|
+
@interrupt_handler.kill
|
177
|
+
|
178
|
+
print_info( 'Exiting...' )
|
179
|
+
exit 0
|
180
|
+
|
181
|
+
when 'r'
|
182
|
+
unmute!
|
183
|
+
@arachni.reports.run( @arachni.audit_store( ) )
|
176
184
|
end
|
177
185
|
|
178
186
|
@@only_positives = only_positives_opt
|
@@ -196,7 +204,7 @@ class CLI
|
|
196
204
|
exit 0
|
197
205
|
end
|
198
206
|
|
199
|
-
print_info( 'Continue? (hit \'enter\' to continue, \'e\' to exit)' )
|
207
|
+
print_info( 'Continue? (hit \'enter\' to continue, \'r\' to generate reports and \'e\' to exit)' )
|
200
208
|
mute!
|
201
209
|
|
202
210
|
::IO::select( nil, nil, nil, 1 )
|
data/lib/ui/web/output_stream.rb
CHANGED
@@ -62,13 +62,13 @@ module Web
|
|
62
62
|
|
63
63
|
self << @instance.service.output
|
64
64
|
|
65
|
-
|
65
|
+
@last_output ||= ''
|
66
66
|
cnt = 0
|
67
67
|
|
68
68
|
if @buffer.empty?
|
69
|
-
yield
|
69
|
+
yield @last_output
|
70
70
|
else
|
71
|
-
|
71
|
+
@last_output = ''
|
72
72
|
end
|
73
73
|
|
74
74
|
while( ( out = @buffer.pop ) && ( ( cnt += 1 ) < @lines ) )
|
@@ -80,7 +80,7 @@ module Web
|
|
80
80
|
|
81
81
|
icon = @icon_whitelist[type] || ''
|
82
82
|
str = icon + CGI.escapeHTML( " #{out.values[0]}" ) + "<br/>"
|
83
|
-
|
83
|
+
@last_output << str
|
84
84
|
yield str
|
85
85
|
|
86
86
|
end
|
data/lib/ui/web/server.rb
CHANGED
@@ -42,14 +42,14 @@ require Arachni::Options.instance.dir['lib'] + 'ui/web/output_stream'
|
|
42
42
|
# @author: Tasos "Zapotek" Laskos
|
43
43
|
# <tasos.laskos@gmail.com>
|
44
44
|
# <zapotek@segfault.gr>
|
45
|
-
# @version: 0.1.
|
45
|
+
# @version: 0.1.4
|
46
46
|
#
|
47
47
|
# @see Arachni::RPC::XML::Client::Instance
|
48
48
|
# @see Arachni::RPC::XML::Client::Dispatcher
|
49
49
|
#
|
50
50
|
module Web
|
51
51
|
|
52
|
-
VERSION = '0.1.
|
52
|
+
VERSION = '0.1.4'
|
53
53
|
|
54
54
|
class Server < Sinatra::Base
|
55
55
|
|
@@ -658,7 +658,7 @@ class Server < Sinatra::Base
|
|
658
658
|
#
|
659
659
|
# shuts down all instances
|
660
660
|
#
|
661
|
-
post "/dispatchers/:url/
|
661
|
+
post "/dispatchers/:url/shutdown_all" do
|
662
662
|
shutdown_all( params[:url] )
|
663
663
|
redirect '/dispatchers'
|
664
664
|
end
|
@@ -789,7 +789,9 @@ class Server < Sinatra::Base
|
|
789
789
|
begin
|
790
790
|
arachni = connect_to_instance( params[:url] )
|
791
791
|
if arachni.framework.busy?
|
792
|
-
|
792
|
+
@@output_streams ||= {}
|
793
|
+
@@output_streams[params[:url]] ||= OutputStream.new( arachni, 38 )
|
794
|
+
{ 'data' => @@output_streams[params[:url]].data }.to_json
|
793
795
|
else
|
794
796
|
settings.log.instance_shutdown( env, params[:url] )
|
795
797
|
save_and_shutdown( arachni )
|
@@ -873,7 +875,7 @@ class Server < Sinatra::Base
|
|
873
875
|
arachni.service.shutdown!
|
874
876
|
end
|
875
877
|
rescue
|
876
|
-
flash.now[:notice] = "Instance at #{params[:url]} has
|
878
|
+
flash.now[:notice] = "Instance at #{params[:url]} has been shutdown."
|
877
879
|
erb params[:splat][0].to_sym, { :layout => true }, :shutdown => true, :stats => dispatcher_stats
|
878
880
|
end
|
879
881
|
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 )%>/
|
24
|
+
<form action="/dispatchers/<%=sanitize_url( d_url.dup )%>/shutdown_all" method="post">
|
25
25
|
<%= csrf_tag %>
|
26
26
|
<input type="submit" value="Shutdown all" />
|
27
27
|
</form>
|
@@ -48,6 +48,7 @@
|
|
48
48
|
<ul>
|
49
49
|
<li>Current max concurrency: <span id="max_concurrency">0</span> requests</li>
|
50
50
|
<li>Average response time: <span id="average_res_time">0</span> ms</li>
|
51
|
+
<li>Timed-out requests: <span id="time_out_count">0</span></li>
|
51
52
|
<li>Current page: <span id="current_page">0</span></li>
|
52
53
|
</ul>
|
53
54
|
|
@@ -123,6 +124,7 @@
|
|
123
124
|
document.getElementById( 'crawled' ).innerHTML = stats.sitemap_size;
|
124
125
|
document.getElementById( 'current_page' ).innerHTML = stats.current_page;
|
125
126
|
document.getElementById( 'average_res_time' ).innerHTML = stats.average_res_time;
|
127
|
+
document.getElementById( 'time_out_count' ).innerHTML = stats.time_out_count;
|
126
128
|
document.getElementById( 'max_concurrency' ).innerHTML = stats.max_concurrency;
|
127
129
|
|
128
130
|
percentage = (stats.auditmap_size / stats.sitemap_size) * 100
|
@@ -33,7 +33,7 @@
|
|
33
33
|
|
34
34
|
<% if issue.method && (issue.elem.downcase == 'form' || issue.elem.downcase == 'link' ) &&
|
35
35
|
( issue.method.downcase == 'get' || issue.method.downcase == 'post' ) %>
|
36
|
-
<form style="display:inline" action="<%=issue.url%>" target="_blank" method="<%=issue.method.downcase%>">
|
36
|
+
<form style="display:inline" action="<%=issue.variations[0]['url']%>" target="_blank" method="<%=issue.method.downcase%>">
|
37
37
|
<% if issue.variations[0]['opts'][:combo]%>
|
38
38
|
<%issue.variations[0]['opts'][:combo].each_pair do |name, value|%>
|
39
39
|
<input type="hidden" name="<%=escape(name)%>" value="<%=escape( value )%>" />
|
data/reports/html.rb
CHANGED
@@ -11,6 +11,7 @@
|
|
11
11
|
require 'erb'
|
12
12
|
require 'base64'
|
13
13
|
require 'cgi'
|
14
|
+
require 'iconv'
|
14
15
|
|
15
16
|
module Arachni
|
16
17
|
|
@@ -24,7 +25,7 @@ module Reports
|
|
24
25
|
# @author: Tasos "Zapotek" Laskos
|
25
26
|
# <tasos.laskos@gmail.com>
|
26
27
|
# <zapotek@segfault.gr>
|
27
|
-
# @version: 0.2.
|
28
|
+
# @version: 0.2.2
|
28
29
|
#
|
29
30
|
class HTML < Arachni::Report::Base
|
30
31
|
|
@@ -87,15 +88,15 @@ class HTML < Arachni::Report::Base
|
|
87
88
|
"\"" + str.gsub( "\n", '\n' ) + "\"";
|
88
89
|
end
|
89
90
|
|
91
|
+
def normalize( str )
|
92
|
+
ic = ::Iconv.new( 'UTF-8//IGNORE', 'UTF-8' )
|
93
|
+
ic.iconv( str + ' ' )[0..-2]
|
94
|
+
end
|
95
|
+
|
90
96
|
def escapeHTML( str )
|
91
97
|
# carefully escapes HTML and converts to UTF-8
|
92
98
|
# while removing invalid character sequences
|
93
|
-
|
94
|
-
return CGI.escapeHTML( str )
|
95
|
-
rescue
|
96
|
-
ic = Iconv.new( 'UTF-8//IGNORE', 'UTF-8' )
|
97
|
-
return CGI.escapeHTML( ic.iconv( str + ' ' )[0..-2] )
|
98
|
-
end
|
99
|
+
return CGI.escapeHTML( normalize( str ) )
|
99
100
|
end
|
100
101
|
|
101
102
|
def self.prep_description( str )
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: arachni
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.2.
|
5
|
+
version: 0.2.4
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Tasos Laskos
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-07-01 00:00:00 +03:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|