watobo 0.9.20 → 0.9.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/CHANGELOG.md +54 -2
  2. data/README.md +1 -1
  3. data/config/scanner.yml +1 -0
  4. data/custom-views/prettify-json.rb +19 -0
  5. data/lib/watobo/adapters/file/marshal_store.rb +297 -0
  6. data/lib/watobo/adapters.rb +2 -1
  7. data/lib/watobo/core/active_check.rb +4 -0
  8. data/lib/watobo/core/chat.rb +8 -0
  9. data/lib/watobo/core/chats.rb +2 -1
  10. data/lib/watobo/core/cookie.rb +3 -3
  11. data/lib/watobo/core/finding.rb +7 -0
  12. data/lib/watobo/core/request.rb +3 -3
  13. data/lib/watobo/core/session.rb +6 -2
  14. data/lib/watobo/framework/init_modules.rb +18 -16
  15. data/lib/watobo/gui/conversation_table.rb +13 -16
  16. data/lib/watobo/gui/conversation_table_ctrl2.rb +1 -0
  17. data/lib/watobo/gui/custom_viewer.rb +101 -76
  18. data/lib/watobo/gui/define_scope_frame.rb +44 -10
  19. data/lib/watobo/gui/edit_scope_dialog.rb +1 -1
  20. data/lib/watobo/gui/fuzzer_gui.rb +61 -23
  21. data/lib/watobo/gui/main_window.rb +1 -1
  22. data/lib/watobo/gui/scanner_settings_dialog.rb +15 -0
  23. data/lib/watobo/http/data/json.rb +6 -0
  24. data/lib/watobo/interceptor/html/favicon.ico +0 -0
  25. data/lib/watobo/interceptor/html/index.html +13 -0
  26. data/lib/watobo/interceptor/proxy.rb +70 -18
  27. data/lib/watobo/mixins/httpparser.rb +26 -16
  28. data/lib/watobo/mixins/shapers.rb +49 -5
  29. data/lib/watobo/mixins/transcoders.rb +8 -8
  30. data/lib/watobo/sockets/connection.rb +1 -1
  31. data/lib/watobo/utils/load_chat.rb +62 -0
  32. data/lib/watobo/utils/response_hash.rb +3 -3
  33. data/lib/watobo.rb +1 -1
  34. data/modules/active/cq5/cq5_default_selectors.rb +116 -0
  35. data/modules/active/cq5/cqp_user_enumeration.rb +134 -0
  36. data/modules/active/struts2/include_params_ognl.rb +1 -1
  37. data/modules/active/xml/xml_xxe.rb +6 -1
  38. data/modules/passive/disclosure_domino.rb +1 -1
  39. data/modules/passive/in_script_parameter.rb +9 -4
  40. data/plugins/aem/aem.rb +21 -0
  41. data/plugins/aem/gui/main.rb +128 -0
  42. data/plugins/aem/gui/tree_view.rb +180 -0
  43. data/plugins/aem/icons/aem.ico +0 -0
  44. data/plugins/aem/lib/agent.rb +140 -0
  45. data/plugins/aem/lib/dispatcher.rb +53 -0
  46. data/plugins/aem/lib/engine.rb +187 -0
  47. data/plugins/filefinder/dbs/cq5.db +23 -0
  48. data/plugins/filefinder/dbs/subs-big.lst +44 -44
  49. data/plugins/filefinder/filefinder.rb +4 -4
  50. data/plugins/sqlmap/lib/sqlmap_ctrl.rb +11 -10
  51. metadata +16 -2
@@ -43,7 +43,7 @@ module Watobo#:nodoc: all
43
43
  end
44
44
 
45
45
  def replaceURL(new_url)
46
- self.first.gsub!(/(^[^[:space:]]{1,})(.*) (HTTP.*)/i,"\\1 #{new_url} \\3")
46
+ self.first.gsub!(/(^[^[:space:]]{1,}) (.*) (HTTP.*)/i,"\\1 #{new_url} \\3")
47
47
  end
48
48
 
49
49
  def replaceQuery(new_query)
@@ -63,6 +63,53 @@ module Watobo#:nodoc: all
63
63
  self.first.gsub!(/(^[^[:space:]]{1,} https?:\/\/[\-0-9a-zA-Z.]*[:0-9]{0,6}\/)(.*)( HTTP\/.*)/, "\\1#{dir}\\3")
64
64
  end
65
65
 
66
+ #
67
+ # set a new file extension, e.g. mysite.html to mysite.php
68
+ # if no extension nor a file is given, the new extension will only be appended
69
+ # note: the first leading dot will be removed
70
+ # possible preferences are:
71
+ # :keep_query => keeps query parameters
72
+ # default-set is empty
73
+ def set_file_extension(nxt, *prefs)
74
+ return self.first if nxt.nil?
75
+ nxt.gsub!(/^\./,'')
76
+ s = "#{self.first}"
77
+ fend = nil
78
+ pend = nil
79
+
80
+ pstart = s.index('?')
81
+ pend = s.rindex(/ HTTP\//)
82
+
83
+ fend = (pstart - 1) unless pstart.nil?
84
+ fend = ( pend - 1 ) if fend.nil?
85
+
86
+ return self.first if fend.nil?
87
+
88
+ fstart = s.rindex('/', fend)
89
+ unless s[fstart-1] == '/'
90
+ fstart += 1 unless fstart.nil?
91
+ else
92
+ fstart = fend
93
+ end
94
+
95
+ fname = s[fstart..fend]
96
+ fname.gsub!(/\..*/,'')
97
+ fname << ".#{nxt}"
98
+
99
+ ns = s[0..fstart-1]
100
+ ns << fname
101
+
102
+ if prefs.include? :keep_query
103
+ unless pstart.nil?
104
+ ns << s[pstart..pend]
105
+ end
106
+ end
107
+
108
+ ns << s[pend..-1]
109
+
110
+ self.first.replace ns
111
+ end
112
+
66
113
  def appendDir(dir)
67
114
  dir.strip!
68
115
  dir.gsub!(/^\//,"")
@@ -245,10 +292,7 @@ module Watobo#:nodoc: all
245
292
 
246
293
  def fix_content_length
247
294
  return false if self.body.nil?
248
- #TODO: had trouble with length calculation of binary data in multipart request
249
- # Workaround: toHex and then calculate length ... very time consuming :(
250
- #
251
- #blen = self.body.unpack("H*")[0].length / 2
295
+ # had trouble with length calculation of binary data in multipart request
252
296
  blen = self.body.force_encoding("ASCII-8BIT").length
253
297
  set_header("Content-Length" , blen)
254
298
  end
@@ -20,23 +20,23 @@ module Watobo#:nodoc: all
20
20
  end
21
21
 
22
22
  def b64decode
23
- err_count = 0
24
- b64string = self
23
+ err_count = 0
25
24
  begin
25
+ b64string = self.force_encoding('ASCII-8BIT')
26
26
  rs = Base64.strict_decode64(b64string)
27
27
  #rs = Base64.decode64(b64string)
28
28
  return rs
29
29
  rescue
30
- b64string.gsub!(/.$/,'')
31
- err_count += 1
32
- retry if err_count < 4
33
- return ""
30
+ #b64string.gsub!(/.$/,'')
31
+ #err_count += 1
32
+ #retry if err_count < 4
33
+ return self.to_s
34
34
  end
35
35
  end
36
36
 
37
37
  def b64encode
38
38
  begin
39
- plain = self
39
+ plain = self.force_encoding('ASCII-8BIT')
40
40
  #rs = Base64.strict_encode64(plain)
41
41
  rs = Base64.strict_encode64(plain)
42
42
  # we only need a simple string without linebreaks
@@ -44,7 +44,7 @@ module Watobo#:nodoc: all
44
44
  #rs.strip!
45
45
  return rs
46
46
  rescue
47
- return ""
47
+ return self.to_s
48
48
  end
49
49
  end
50
50
 
@@ -95,7 +95,7 @@ module Watobo#:nodoc: all
95
95
  return nil
96
96
  end
97
97
 
98
- header = [ "HTTP/1.1 200 OK\r\n", "Server: WATOBO\r\n", "Content-Length: #{msg.length.to_i}\r\n", "Content-Type: text/html\r\n", "\r\n", "#{msg}" ] unless msg.nil?
98
+ header = [ "HTTP/1.1 502 Bad Gateway\r\n", "Server: WATOBO\r\n", "Content-Length: #{msg.length.to_i}\r\n", "Content-Type: text/html\r\n", "\r\n", "#{msg}" ] unless msg.nil?
99
99
 
100
100
  response = Watobo::Response.new header
101
101
  # update_sids(header)
@@ -11,6 +11,44 @@
11
11
  module Watobo#:nodoc: all
12
12
  module Utils
13
13
 
14
+ def Utils.loadChatMarshal(file)
15
+ begin
16
+ request = []
17
+ response = []
18
+ if File.exists?(file) then
19
+ puts "LoadChatMarshal: #{file}" if $DEBUG
20
+ settings = {}
21
+ File.open(file,"rb") { |fh|
22
+ settings = Marshal::load(fh.read)
23
+ request = settings[:request]
24
+ response = settings[:response]
25
+ settings.delete(:response)
26
+ settings.delete(:request)
27
+
28
+ }
29
+
30
+
31
+ chat = Watobo::Chat.new(request, response, settings)
32
+ chat.file = file
33
+
34
+ return chat
35
+
36
+ else
37
+ puts "* file #{file} not found"
38
+ return nil
39
+ end
40
+ rescue Psych::SyntaxError
41
+ puts "!!! Malformed File #{file}"
42
+ rescue => bang
43
+ puts "! could not load chat from file #{file}"
44
+ puts bang
45
+ puts bang.backtrace
46
+ #puts cdata
47
+ #puts bang
48
+ #puts bang.backtrace if $DEBUG
49
+ end
50
+ end
51
+
14
52
  # loadChat returns a chat object imported from a yaml file
15
53
  def Utils.loadChatYAML(file)
16
54
  begin
@@ -68,6 +106,30 @@ module Watobo#:nodoc: all
68
106
  end
69
107
 
70
108
 
109
+ def Utils.loadFindingMarshal(file)
110
+ puts "LoadFindingMarshal: #{file}" if $DEBUG
111
+ if File.exists?(file) then
112
+ begin
113
+ fdata = nil
114
+
115
+ File.open(file,"rb") {|f|
116
+ fdata = Marshal::load(f.read)
117
+ }
118
+
119
+ finding = Watobo::Finding.new(fdata[:request], fdata[:response], fdata[:details])
120
+
121
+ return finding
122
+ rescue => bang
123
+ puts bang
124
+ puts "could not load finding #{file}"
125
+ return nil
126
+ end
127
+ else
128
+ # puts "* file #{file} not found"
129
+ return nil
130
+ end
131
+ end
132
+
71
133
  def Utils.loadFindingYAML(file)
72
134
  puts "LoadFindingYAML: #{file}" if $DEBUG
73
135
  if File.exists?(file) then
@@ -138,11 +138,11 @@ module Watobo#:nodoc: all
138
138
  end
139
139
  rescue => bang
140
140
  # puts "VAL_CGI_Q: #{val_cgi_q}"
141
- puts bang
142
-
141
+ # return some random hash in case of an error
142
+ puts bang if $DEBUG
143
143
  puts bang.backtrace if $DEBUG
144
144
 
145
- return body, Digest::MD5.hexdigest(body||="")
145
+ return body, Digest::MD5.hexdigest(Time.now.to_f.to_s + rand(10000).to_s )
146
146
  end
147
147
  end
148
148
  end
data/lib/watobo.rb CHANGED
@@ -52,7 +52,7 @@ dont_know_why_REQUIRE_hangs = Mechanize.new
52
52
  # @private
53
53
  module Watobo#:nodoc: all #:nodoc: all
54
54
 
55
- VERSION = "0.9.20"
55
+ VERSION = "0.9.21"
56
56
 
57
57
  def self.base_directory
58
58
  @base_directory ||= ""
@@ -0,0 +1,116 @@
1
+ #.
2
+ # cq5_default_selectors.rb
3
+ #.
4
+ # Copyright 2014 by siberas, http://www.siberas.de
5
+ # This file is part of WATOBO (Web Application Tool Box) http://watobo.sourceforge.com
6
+ # WATOBO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License.
7
+ # WATOBO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
8
+ # You should have received a copy of the GNU General Public License along with WATOBO; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
9
+
10
+ # @private
11
+ module Watobo#:nodoc: all
12
+ module Modules
13
+ module Active
14
+ module Cq5
15
+ #class Dir_indexing < Watobo::Mixin::Session
16
+ class Cq5_default_selectors < Watobo::ActiveCheck
17
+
18
+ @info.update(
19
+ :check_name => 'CQ5 Selectors', # name of check which briefly describes functionality, will be used for tree and progress views
20
+ :description => "This module checks for default selectors.", # description of checkfunction
21
+ :author => "Andreas Schmidt", # author of check
22
+ :version => "1.0", # check version
23
+ :check_group => "CQ5"
24
+ )
25
+
26
+ @finding.update(
27
+ :threat => 'Selectors can reveal sensitive information about the application, e.g. password hashes (jackrabbit). Also, the query selector enables you to perform XPATH queries on the entire repository, which could slow your system down considerably, or even cause a denial of service if run multiple times', # thread of vulnerability, e.g. loss of information
28
+ :class => "CQ5: Selectors", # vulnerability class, e.g. Stored XSS, SQL-Injection, ...
29
+ :type => FINDING_TYPE_VULN, # FINDING_TYPE_HINT, FINDING_TYPE_INFO, FINDING_TYPE_VULN
30
+ :rating => VULN_RATING_INFO
31
+ )
32
+
33
+ def initialize(project, prefs={})
34
+ super(project, prefs)
35
+
36
+ @checked_locations = []
37
+ @selectors = %w( query assets infinity children s7catalog pages feed feedentry tidy sysview docview permissions overlay 1 2 3 4 5 6 7 )
38
+ @extensions = %w( json html csv zip xml )
39
+ # specials are combinations which need one or more parameters to produce a valid result
40
+ @specials = %w( query.json?statement=%2F%2F%2A cqactions.json?path=/&depth=1&authorizableId=* permissions.overlay.json?path=/ )
41
+
42
+ @mixed = @selectors.map{|s| @extensions.map{|e| s + '.' + e } }.flatten
43
+
44
+ end
45
+
46
+ def reset()
47
+ @checked_locations = []
48
+ end
49
+
50
+ def generateChecks(chat)
51
+ path = chat.request.path
52
+ return false if @checked_locations.include? path
53
+ @checked_locations << path
54
+
55
+ test_extensions = @extensions
56
+ test_extensions.concat @specials
57
+ test_extensions.concat @mixed
58
+
59
+ test_extensions.each do |ext|
60
+ checker = proc {
61
+ begin
62
+ test_request = nil
63
+ test_response = nil
64
+
65
+ test = chat.copyRequest
66
+
67
+ # replace file extension only
68
+
69
+ test.set_file_extension(ext)
70
+
71
+ status, test_request, test_response = fileExists?(test)
72
+
73
+ if status == true and test_response.content_type != chat.response.content_type and test_response.status_code < 300
74
+
75
+ addFinding( test_request, test_response,
76
+ :test_item => "#{test_request.url}",
77
+ :proof_pattern => "#{test_response.status}",
78
+ :chat => chat,
79
+ :title => "[#{ext}]"
80
+ )
81
+
82
+ end
83
+
84
+ # also test extensions on the path
85
+ test = chat.copyRequest
86
+
87
+ test.replaceFileExt(".#{ext}")
88
+
89
+ status, test_request, test_response = fileExists?(test)
90
+
91
+ if status == true and test_response.content_type != chat.response.content_type and test_response.status_code < 300
92
+
93
+ addFinding( test_request, test_response,
94
+ :test_item => "#{test_request.url}",
95
+ :proof_pattern => "#{test_response.status}",
96
+ :chat => chat,
97
+ :title => "[#{ext}]"
98
+ )
99
+
100
+ end
101
+ rescue => bang
102
+ puts bang
103
+ puts bang.backtrace if $DEBUG
104
+ end
105
+ [ test_request, test_response ]
106
+
107
+ }
108
+ yield checker
109
+ end
110
+
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,134 @@
1
+ #.
2
+ # cqp_user_enumeration.rb
3
+ #.
4
+ # Copyright 2014 by siberas, http://www.siberas.de
5
+ # This file is part of WATOBO (Web Application Tool Box) http://watobo.sourceforge.com
6
+ # WATOBO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License.
7
+ # WATOBO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
8
+ # You should have received a copy of the GNU General Public License along with WATOBO; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
9
+
10
+ # @private
11
+ module Watobo#:nodoc: all
12
+ module Modules
13
+ module Active
14
+ module Cq5
15
+ #class Dir_indexing < Watobo::Mixin::Session
16
+ class Cqp_user_enumeration < Watobo::ActiveCheck
17
+
18
+ @info.update(
19
+ :check_name => 'CQ5 CQP User Enumeration', # name of check which briefly describes functionality, will be used for tree and progress views
20
+ :description => "This module checks if CQ JSON extension is aktive and enumerates all usernames.", # description of checkfunction
21
+ :author => "Andreas Schmidt", # author of check
22
+ :version => "1.0", # check version
23
+ :check_group => "CQ5"
24
+ )
25
+
26
+ @finding.update(
27
+ :threat => 'Information Disclosure.', # thread of vulnerability, e.g. loss of information
28
+ :class => "CQ5: Users", # vulnerability class, e.g. Stored XSS, SQL-Injection, ...
29
+ :type => FINDING_TYPE_VULN, # FINDING_TYPE_HINT, FINDING_TYPE_INFO, FINDING_TYPE_VULN
30
+ :rating => VULN_RATING_INFO
31
+ )
32
+ def initialize(project, prefs={})
33
+ super(project, prefs)
34
+
35
+ end
36
+
37
+ def reset()
38
+ @checked_locations = []
39
+ end
40
+
41
+ def generateChecks(chat)
42
+
43
+ path = chat.request.path
44
+ return false if @checked_locations.include? path
45
+ @checked_locations << path
46
+ #
47
+ # via JSON Extension
48
+
49
+ checker = proc {
50
+ begin
51
+ test_request = nil
52
+ test_response = nil
53
+
54
+ test = chat.copyRequest
55
+
56
+ test.set_file_extension('.json')
57
+
58
+ status, test_request, test_response = fileExists?(test)
59
+
60
+ if status == true and test_response.has_body?
61
+ if test_response.content_type =~ /json/
62
+ j = JSON.parse test_response.body.to_s
63
+ username = j['jcr:createdBy']
64
+ puts "\nCQ5 User: #{username}"
65
+ addFinding( test_request, test_response,
66
+ :test_item => "#{test_request.url}",
67
+ :proof_pattern => "jcr:createdBy.*#{username}",
68
+ :chat => chat,
69
+ :threat => "Usernames may help an attacker to perform authorization attacks, e.g. brute-force attacks.",
70
+ :title => "[#{username}]"
71
+ )
72
+ end
73
+
74
+ end
75
+ rescue => bang
76
+ puts bang
77
+ puts bang.backtrace if $DEBUG
78
+ end
79
+ [ test_request, test_response ]
80
+
81
+ }
82
+ yield checker
83
+
84
+ #
85
+ # via XML Extension
86
+
87
+ checker = proc {
88
+ begin
89
+ test_request = nil
90
+ test_response = nil
91
+
92
+ test = chat.copyRequest
93
+
94
+ test.set_file_extension('.xml')
95
+
96
+ status, test_request, test_response = fileExists?(test)
97
+
98
+ if status == true and test_response.has_body?
99
+ if test_response.content_type =~ /xml/
100
+ xml = Nokogiri::XML(test_response.body.to_s)
101
+ xml.traverse do |node|
102
+ next unless node.respond_to? :attributes
103
+ node.attributes.each do |attr|
104
+ if attr[0] =~ /By$/i
105
+ username = attr[1]
106
+ addFinding( test_request, test_response,
107
+ :test_item => "#{test_request.url}",
108
+ :proof_pattern => "#{attr[0]}.*#{username}",
109
+ :chat => chat,
110
+ :threat => "Usernames may help an attacker to perform authorization attacks, e.g. brute-force attacks.",
111
+ :title => "[#{username}]"
112
+ )
113
+ end
114
+ end
115
+ end
116
+
117
+ end
118
+
119
+ end
120
+ rescue => bang
121
+ puts bang
122
+ puts bang.backtrace if $DEBUG
123
+ end
124
+ [ test_request, test_response ]
125
+
126
+ }
127
+ yield checker
128
+
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end