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
@@ -1,3 +1,3 @@
1
1
  ping -n __TIME__ localhost
2
2
  ping -c __TIME__ localhost
3
- /usr/sbin/ping -s localhost 1000 10
3
+ /usr/sbin/ping -s localhost 1000 __TIME__
@@ -35,209 +35,32 @@ class BlindrDiffSQLInjection < Arachni::Module::Base
35
35
  super( page )
36
36
  end
37
37
 
38
- def prepare( )
38
+ def prepare
39
+ @@__bools ||= []
39
40
 
40
- # possible quote characters used in SQL statements
41
- @__quotes = [
42
- '\'',
43
- '"',
44
- ''
45
- ]
41
+ if @@__bools.empty?
42
+ read_file( 'payloads.txt' ) {
43
+ |str|
46
44
 
47
- # this will cause a silent error if there's a blind SQL injection
48
- @__bad_chars =[
49
- '\'"`',
50
- # we need 2 requests thus we change the second one a little bit to
51
- # fool the Auditor's redundancy filter
52
- '\'"``'
53
- ]
54
-
55
- # %q% will be replaced by a character in @__quotes
56
- @__injection = '%q% and %q%1'
57
-
58
- @__opts = {
59
- :format => [ Format::APPEND ],
60
- # we need to do our own redundancy checks
61
- :redundant => true
62
- }
63
-
64
- # used for redundancy checks
65
- @@__audited ||= Set.new
66
-
67
- # this is the structure of the responses
68
- @responses = {
69
- :orig => '',
70
-
71
- :good => {
72
-
73
- },
74
- :bad => {
75
- }
76
- }
77
-
78
- end
79
-
80
- def run( )
81
-
82
- return if( __audited? )
83
-
84
- if( !@page.query_vars || @page.query_vars.empty? )
85
- print_status( 'Nothing to audit on current page, skipping...' )
86
- return
87
- end
88
-
89
- # get the link object that fits the URL of the page
90
- # this will be the one to audit
91
- @page.links.each {
92
- |link|
93
- @__candidate = link if link.action == @page.url
94
- }
95
-
96
- return if !@__candidate
97
-
98
- # let's get a fresh rendering of the page to assist us with
99
- # irrelevant dynamic content elimination (banners, ads, etc...)
100
- @http.get( @page.url, :params => @page.query_vars ).on_complete {
101
- |res|
102
-
103
- # eliminate dynamic content that's context-irrelevant
104
- # ie. changing with every refresh
105
- @responses[:orig] = @page.html.rdiff( res.body )
106
- }
107
-
108
- # force the webapp to return an error page
109
- prep_bad_responses( )
110
-
111
- # start injecting 'good' SQL queries
112
- prep_good_responses( )
113
-
114
- @http.after_run {
115
- # analyze the HTML code of the responses in order to determine
116
- # which injections were succesfull
117
- analyze( )
118
- }
119
- end
120
-
121
- # Audits page with 'bad' SQL characters and gathers error pages
122
- def prep_bad_responses( )
123
-
124
- @__bad_chars.each {
125
- |str|
126
-
127
- # get injection variations that will hopefully cause an internal/silent
128
- # SQL error
129
- variations = @__candidate.injection_sets( str, @__opts )
130
-
131
- @responses[:bad_total] = variations.size
132
-
133
- variations.each {
134
- |link|
135
-
136
- # the altered link variable
137
- altered = link.altered
138
-
139
- print_status( @__candidate.get_status_str( altered ) )
140
-
141
- # register us as the auditor
142
- link.auditor( self )
143
- # submit the link and get the response
144
- link.submit( @__opts ).on_complete {
145
- |res|
146
-
147
- @responses[:bad][altered] ||= res.body.clone
148
-
149
- # remove context-irrelevant dynamic content like banners and such
150
- # from the error page
151
- @responses[:bad][altered] = @responses[:bad][altered].rdiff( res.body.clone )
45
+ [ '\'', '"', '' ].each {
46
+ |quote|
47
+ @@__bools << str.gsub( '%q%', quote )
152
48
  }
153
49
  }
154
- }
155
- end
156
-
157
- # Injects SQL code that doesn't affect the flow of execution nor presentation
158
- def prep_good_responses( )
159
-
160
- @__quotes.each {
161
- |quote|
162
-
163
- # prepare the statement with combinations of quote characters
164
- str = @__injection.gsub( '%q%', quote )
165
-
166
- variations = @__candidate.injection_sets( str, @__opts )
167
-
168
- @responses[:good_total] = variations.size
169
-
170
- variations.each {
171
- |link|
172
-
173
- # the altered link variable
174
- altered = link.altered
175
-
176
- # register us as the auditor
177
- link.auditor( self )
178
-
179
- # submit the link and get the response
180
- link.submit( @__opts ).on_complete {
181
- |res|
182
-
183
- @responses[:good][altered] ||= []
184
-
185
- # save the response for later analysis
186
- @responses[:good][altered] << {
187
- 'str' => str,
188
- 'res' => res
189
- }
190
- }
191
-
192
- }
193
- }
194
-
195
- end
196
-
197
- # Goes through the responses induced by {#prep_good_responses} and {#__check} their code
198
- def analyze( )
199
- @responses[:good].keys.each {
200
- |key|
201
- @responses[:good][key].each {
202
- |res|
203
- __check( res['str'], res['res'], key )
204
- }
205
- }
206
- end
207
-
208
- #
209
- # Compares HTML responses in order to identify successful blind sql injections
210
- #
211
- # @param [String] str the string that unveiled the vulnerability
212
- # @param [Typhoeus::Response]
213
- # @param [String] var the vulnerable variable
214
- #
215
- def __check( str, res, var )
216
-
217
- # if one of the injections gives the same results as the
218
- # original page then a blind SQL injection exists
219
- check = res.body.rdiff( @page.html )
220
-
221
- if( check == @responses[:orig] && @responses[:bad][var] != check &&
222
- !@http.custom_404?( res ) && res.code == 200 )
223
- __log_results( var, res, str )
224
50
  end
225
-
226
51
  end
227
52
 
228
- def clean_up
229
- @@__audited << __audit_id( )
230
- end
53
+ def run( )
231
54
 
232
- def __audit_id
233
- "#{URI( normalize_url( @page.url ) ).path}::#{@page.query_vars.keys}"
234
- end
55
+ opts = {}
56
+ # fault injection seeds
57
+ opts[:faults] = [ '\'"`' ]
58
+ # boolean injection seeds
59
+ opts[:bools] = @@__bools
235
60
 
236
- def __audited?
237
- @@__audited.include?( __audit_id( ) )
61
+ audit_rdiff( opts )
238
62
  end
239
63
 
240
-
241
64
  def self.info
242
65
  {
243
66
  :name => 'Blind (rDiff) SQL Injection',
@@ -247,7 +70,9 @@ class BlindrDiffSQLInjection < Arachni::Module::Base
247
70
  (Note: This module may get confused by certain types of XSS vulnerabilities.
248
71
  If this module returns a positive result you should investigate nonetheless.)},
249
72
  :elements => [
250
- Issue::Element::LINK
73
+ Issue::Element::LINK,
74
+ Issue::Element::FORM,
75
+ Issue::Element::COOKIE
251
76
  ],
252
77
  :author => 'Tasos "Zapotek" Laskos <tasos.laskos@gmail.com> ',
253
78
  :version => '0.3',
@@ -276,46 +101,6 @@ class BlindrDiffSQLInjection < Arachni::Module::Base
276
101
  }
277
102
  end
278
103
 
279
- private
280
-
281
- def __log_results( var, res, str )
282
-
283
- url = res.effective_url
284
-
285
- # since we bypassed the auditor completely we need to create
286
- # our own opts hash and pass it to the Vulnerability class.
287
- #
288
- # this is only required for Metasploitable vulnerabilities
289
- opts = {
290
- :injected_orig => URI( @page.url ).query,
291
- :combo => @__candidate.auditable
292
- }
293
-
294
- issue = Issue.new( {
295
- :var => var,
296
- :url => url,
297
- :method => res.request.method.to_s,
298
- :opts => opts,
299
- :injected => str,
300
- :id => str,
301
- :regexp => 'n/a',
302
- :regexp_match => 'n/a',
303
- :elem => Issue::Element::LINK,
304
- :response => res.body,
305
- :verification => true,
306
- :headers => {
307
- :request => res.request.headers,
308
- :response => res.headers,
309
- }
310
- }.merge( self.class.info )
311
- )
312
-
313
- print_ok( "In #{Issue::Element::LINK} var '#{var}' ( #{url} )" )
314
-
315
- # register our results with the system
316
- register_results( [ issue ] )
317
- end
318
-
319
104
  end
320
105
  end
321
106
  end
@@ -0,0 +1,5 @@
1
+ %q% and %q%1
2
+ %q%) and %q%1
3
+ %q%)) and %q%1
4
+ %q%))) and %q%1
5
+ %q%)))) and %q%1
@@ -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/89.html
24
24
  # @see http://capec.mitre.org/data/definitions/7.html
@@ -55,6 +55,13 @@ class BlindTimingSQLInjection < Arachni::Module::Base
55
55
  audit_timeout( @@__injection_str, @__opts )
56
56
  end
57
57
 
58
+ def redundant
59
+ # We add ourselves to the list too.
60
+ # We don't want more than one timing-attack variation per issue,
61
+ # it's too expensive.
62
+ [ 'sqli', 'sqli_blind_rdiff', 'sqli_blind_timing' ]
63
+ end
64
+
58
65
  def self.info
59
66
  {
60
67
  :name => 'Blind (timing) SQL injection',
@@ -68,7 +75,7 @@ class BlindTimingSQLInjection < Arachni::Module::Base
68
75
  Issue::Element::HEADER
69
76
  ],
70
77
  :author => 'Tasos "Zapotek" Laskos <tasos.laskos@gmail.com> ',
71
- :version => '0.1.1',
78
+ :version => '0.2.1',
72
79
  :references => {
73
80
  'OWASP' => 'http://www.owasp.org/index.php/Blind_SQL_Injection',
74
81
  'MITRE - CAPEC' => 'http://capec.mitre.org/data/definitions/7.html'
@@ -8,7 +8,7 @@
8
8
 
9
9
  =end
10
10
 
11
- module Anemone::Extractors
11
+ module Arachni::Parser::Extractors
12
12
 
13
13
  #
14
14
  # Extracts paths from anchor elements.
@@ -8,7 +8,7 @@
8
8
 
9
9
  =end
10
10
 
11
- module Anemone::Extractors
11
+ module Arachni::Parser::Extractors
12
12
 
13
13
  #
14
14
  # Extracts paths from "form" HTML elements.
@@ -8,7 +8,7 @@
8
8
 
9
9
  =end
10
10
 
11
- module Anemone::Extractors
11
+ module Arachni::Parser::Extractors
12
12
 
13
13
  #
14
14
  # Extracts paths from frames.
@@ -8,7 +8,7 @@
8
8
 
9
9
  =end
10
10
 
11
- module Anemone::Extractors
11
+ module Arachni::Parser::Extractors
12
12
 
13
13
  #
14
14
  # Extract URLs from arbitrary text.
@@ -8,7 +8,7 @@
8
8
 
9
9
  =end
10
10
 
11
- module Anemone::Extractors
11
+ module Arachni::Parser::Extractors
12
12
 
13
13
  #
14
14
  # Extracts paths from "link" HTML elements.
@@ -8,7 +8,7 @@
8
8
 
9
9
  =end
10
10
 
11
- module Anemone::Extractors
11
+ module Arachni::Parser::Extractors
12
12
 
13
13
  #
14
14
  # Extracts meta refresh URLs.
@@ -8,7 +8,7 @@
8
8
 
9
9
  =end
10
10
 
11
- module Anemone::Extractors
11
+ module Arachni::Parser::Extractors
12
12
 
13
13
  #
14
14
  # Extracts paths from "script" HTML elements.<br/>
@@ -8,7 +8,7 @@
8
8
 
9
9
  =end
10
10
 
11
- module Anemone::Extractors
11
+ module Arachni::Parser::Extractors
12
12
 
13
13
  #
14
14
  # @author: Tasos "Zapotek" Laskos
@@ -25,7 +25,7 @@ class Proxy
25
25
  # @author: Tasos "Zapotek" Laskos
26
26
  # <tasos.laskos@gmail.com>
27
27
  # <zapotek@segfault.gr>
28
- # @version: 0.1
28
+ # @version: 0.1.1
29
29
  #
30
30
  class Server < WEBrick::HTTPProxyServer
31
31
 
@@ -57,7 +57,8 @@ class Proxy
57
57
  res.header['content-type'] = 'text/plain'
58
58
  res.header.delete( 'content-encoding' )
59
59
 
60
- res.body << reasons.map{ |msg| " * #{msg}" }.join( "\n" )
60
+ res.body << reasons.pop + "\n"
61
+ res.body << reasons.map{ |msg| " * #{msg}" }.join( "\n" )
61
62
  end
62
63
  end
63
64
  end
@@ -126,7 +126,6 @@ class WAFDetector < Arachni::Plugin::Base
126
126
 
127
127
  def queue_original
128
128
  @precision.times {
129
- # grab the page containing the login form
130
129
  @framework.http.get( @url.to_s ).on_complete {
131
130
  |res|
132
131
  @responses[:original] ||= res.body
@@ -137,7 +136,6 @@ class WAFDetector < Arachni::Plugin::Base
137
136
 
138
137
  def queue_vanilla( )
139
138
  @precision.times {
140
- # grab the page containing the login form
141
139
  @framework.http.get( @url.to_s, :params => @safe ).on_complete {
142
140
  |res|
143
141
  @responses[:vanilla] ||= res.body
@@ -148,7 +146,6 @@ class WAFDetector < Arachni::Plugin::Base
148
146
 
149
147
  def queue_spicy( )
150
148
  @precision.times {
151
- # grab the page containing the login form
152
149
  @framework.http.get( @url.to_s, :params => @unsafe ).on_complete {
153
150
  |res|
154
151
  @responses[:spicy] ||= res.body