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
@@ -26,7 +26,7 @@ module Watobo#:nodoc: all
26
26
 
27
27
  def initialize(owner, prefs)
28
28
  #super(owner, "Edit Target Scope", DECOR_TITLE|DECOR_BORDER, :width => 300, :height => 425)
29
- super(owner, "Edit Target Scope", DECOR_ALL, :width => 300, :height => 425)
29
+ super(owner, "Edit Target Scope", DECOR_ALL, :width => 350, :height => 425)
30
30
 
31
31
  @scope = Hash.new
32
32
 
@@ -62,6 +62,8 @@ module Watobo#:nodoc: all
62
62
  fuzz_request.extend Watobo::Mixin::Parser::Url
63
63
 
64
64
  test_request, test_response = doRequest(fuzz_request, @prefs)
65
+
66
+ notify(:stats, test_response)
65
67
 
66
68
  notify(:fuzzer_match, test_fuzzle, test_request, test_response, test_response.join) if @filter_list.empty?
67
69
 
@@ -359,10 +361,36 @@ module Watobo#:nodoc: all
359
361
  end
360
362
 
361
363
  def addResponse(response)
364
+
365
+ @log_queue << response
366
+
367
+ end
368
+
369
+ def clearResponseCodeTable()
370
+ @response_code_tbl.clearItems()
371
+ @response_code_tbl.setTableSize(0, 2)
372
+
373
+ @response_code_tbl.setColumnText( 0, "STATUS" )
374
+ @response_code_tbl.setColumnText( 1, "COUNT" )
375
+
376
+ @response_code_tbl.rowHeader.width = 0
377
+ @response_code_tbl.setColumnWidth(0, 70)
378
+
379
+ @response_code_tbl.setColumnWidth(1, 70)
362
380
 
363
- return nil unless response.respond_to? :status
364
381
 
365
- @lock.synchronize {
382
+ end
383
+
384
+ def start_update_timer
385
+ @timer = FXApp.instance.addTimeout( 1000, :repeat => true) {
386
+ #print @log_queue.length
387
+ while @log_queue.length > 0
388
+ response = @log_queue.deq
389
+
390
+ if response.respond_to? :status
391
+ @count_total += 1
392
+ @count_text.text = "Total: #{@count_total}"
393
+
366
394
  cstatus = response.status
367
395
  count_item = nil
368
396
  @response_code_tbl.getNumRows.times do |i|
@@ -381,24 +409,13 @@ module Watobo#:nodoc: all
381
409
  c = count_item.text.to_i
382
410
  count_item.text = ( c + 1 ).to_s
383
411
  end
384
- }
385
-
386
- end
387
-
388
- def clearResponseCodeTable()
389
- @response_code_tbl.clearItems()
390
- @response_code_tbl.setTableSize(0, 2)
391
-
392
- @response_code_tbl.setColumnText( 0, "STATUS" )
393
- @response_code_tbl.setColumnText( 1, "COUNT" )
394
-
395
- @response_code_tbl.rowHeader.width = 0
396
- @response_code_tbl.setColumnWidth(0, 70)
397
-
398
- @response_code_tbl.setColumnWidth(1, 70)
399
-
412
+ @count_text.handle(self, FXSEL(SEL_UPDATE, 0), nil)
413
+ end
414
+
415
+ end
416
+ }
400
417
 
401
- end
418
+ end
402
419
 
403
420
  def clearResponseLengthTable()
404
421
  @response_length_tbl.clearItems()
@@ -419,13 +436,18 @@ module Watobo#:nodoc: all
419
436
  @response_length_tbl.getItem(lastRowIndex, 1).justify = FXTableItem::LEFT
420
437
  end
421
438
  end
422
-
439
+
440
+
423
441
  def initialize(parent, opts)
424
442
  super(parent, opts)
425
443
 
426
- @lock = Mutex.new
444
+ @log_queue = Queue.new
427
445
 
428
446
  @count_total = 0
447
+
448
+ @count_text = FXLabel.new(self, "Total: 0")
449
+ @count_text.setFont(FXFont.new(getApp(), "helvetica", 11, FONTWEIGHT_BOLD, FONTENCODING_DEFAULT))
450
+
429
451
  counter_frame = FXHorizontalFrame.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y)
430
452
  response_code_gb = FXGroupBox.new(counter_frame, "Response Codes", LAYOUT_SIDE_BOTTOM|FRAME_GROOVE|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0, 0, 0, 0)
431
453
  frame = FXVerticalFrame.new(response_code_gb, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y )
@@ -439,7 +461,11 @@ module Watobo#:nodoc: all
439
461
  sunken = FXVerticalFrame.new(frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK, :padding => 0)
440
462
  @response_length_tbl = FXTable.new(sunken, :opts => FRAME_SUNKEN|TABLE_COL_SIZABLE|TABLE_ROW_SIZABLE|LAYOUT_FILL_X|LAYOUT_FILL_Y|TABLE_READONLY|LAYOUT_SIDE_TOP, :padding => 2)
441
463
  @response_length_tbl.columnHeader.connect(SEL_COMMAND) { }
464
+
465
+
442
466
  clearResponseLengthTable()
467
+
468
+ start_update_timer
443
469
  end
444
470
  end
445
471
 
@@ -909,12 +935,17 @@ module Watobo#:nodoc: all
909
935
  return 0 if response != MBOX_CLICKED_YES
910
936
 
911
937
  end
912
- fh = File.new(filename, "w")
938
+ r = []
913
939
  @matchTable.numRows.times do |i|
914
940
  #puts items[1].to_s
941
+ tv = @matchTable.getItemData(i,0)
915
942
  data = @matchTable.getItemData(i,1)
916
- fh.puts data.strip if data
943
+ if data
944
+ r << { :tag => tv, :data => data.strip }
945
+ end
917
946
  end
947
+ fh = File.new(filename, "w")
948
+ fh.puts YAML.dump(r)
918
949
  fh.close
919
950
  end
920
951
  rescue => bang
@@ -954,6 +985,7 @@ module Watobo#:nodoc: all
954
985
  lastRowIndex = @matchTable.getNumRows
955
986
  @matchTable.appendRows(1)
956
987
  @matchTable.setItemText(lastRowIndex, 0, s.join("\n"))
988
+ @matchTable.setItemData(lastRowIndex, 0, fuzzle )
957
989
  @matchTable.getItem(lastRowIndex, 0).justify = FXTableItem::LEFT
958
990
  @matchTable.fitRowsToContents(lastRowIndex)
959
991
  cell_text = match.gsub(/(\n+|\r+)/, " ")
@@ -999,6 +1031,12 @@ module Watobo#:nodoc: all
999
1031
  @pbar.increment(1)
1000
1032
  }
1001
1033
 
1034
+ @stat_viewer.clearView
1035
+
1036
+ check_list.first.subscribe(:stats) { |response|
1037
+ @stat_viewer.addResponse(response)
1038
+ }
1039
+
1002
1040
  check_list.first.subscribe(:fuzzer_match) { |fuzzle, request, response, match|
1003
1041
  @stat_viewer.addResponse(response)
1004
1042
  addMatch(fuzzle, match)
@@ -1418,7 +1418,7 @@ module Watobo#:nodoc: all
1418
1418
 
1419
1419
  # C H A T T A B L E
1420
1420
  @chatTable = ConversationTable.new(@conversation_table_ctrl )
1421
- @conversation_table_ctrl.table= @chatTable
1421
+ @conversation_table_ctrl.table = @chatTable
1422
1422
 
1423
1423
  @chatTable.autoscroll = true
1424
1424
  =begin
@@ -18,6 +18,7 @@ module Watobo#:nodoc: all
18
18
  settings[:max_parallel_checks] = @max_par_checks.value
19
19
  settings[:smart_scan] = @enable_smart_scan.checked?
20
20
  settings[:run_passive_checks] = @enable_passive_checks.checked?
21
+ settings[:ignore_server_errors] = @ignore_server_errors.checked?
21
22
 
22
23
  settings[:scanlog_dir] = ''
23
24
  if @log_scan_cb.checked? then
@@ -104,6 +105,20 @@ module Watobo#:nodoc: all
104
105
  text = "If Smart Scan is enabled the scanner will reduce the number of checks."
105
106
  fxtext.setText(text)
106
107
 
108
+ gbox = FXGroupBox.new(scroll_area, "Response Codes", LAYOUT_SIDE_LEFT|FRAME_GROOVE|LAYOUT_FILL_X, 0, 0, 0, 50)
109
+ gbframe = FXVerticalFrame.new(gbox, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y, :padding => 0)
110
+ frame = FXHorizontalFrame.new(gbframe, :opts => LAYOUT_FILL_X, :padding => 0)
111
+ @ignore_server_errors = FXCheckButton.new(frame, "Ignore Server Errors ", nil, 0, JUSTIFY_LEFT|JUSTIFY_TOP|ICON_BEFORE_TEXT)
112
+ @ignore_server_errors.checkState = @settings[:ignore_server_errors]
113
+
114
+ #@edit_uniq_parms_btn = FXButton.new(frame, "Non-Unique Parms", :opts => LAYOUT_RIGHT|FRAME_RAISED)
115
+
116
+ fxtext = FXText.new(gbframe, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_WORDWRAP)
117
+ fxtext.backColor = fxtext.parent.backColor
118
+ fxtext.disable
119
+ text = "Handle error codes (5xx) as file does not exist"
120
+ fxtext.setText(text)
121
+
107
122
 
108
123
  gbox = FXGroupBox.new(scroll_area, "Passive Checks", LAYOUT_SIDE_LEFT|FRAME_GROOVE|LAYOUT_FILL_X, 0, 0, 0, 150)
109
124
  gbframe = FXVerticalFrame.new(gbox, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y, :padding => 0)
@@ -33,10 +33,16 @@ module Watobo#:nodoc: all
33
33
  parms = []
34
34
  json_str = @root.body.to_s
35
35
 
36
+ begin
36
37
  JSON.parse(json_str).each do |k,v|
37
38
  val = v.is_a?(String) ? v : v.to_s
38
39
  parms << Watobo::JSONParameter.new( :name => k, :value => val )
39
40
  end
41
+ rescue => bang
42
+ puts "! could not parse JSON parameters !"
43
+ puts @root.headers
44
+ puts json_str.gsub(/[^[:print:]]/, '.')
45
+ end
40
46
  parms
41
47
  end
42
48
 
@@ -0,0 +1,13 @@
1
+ <html>
2
+ <head>
3
+ <title>WATOBO - Interceptor</title>
4
+ </head>
5
+ <body>
6
+ <h1>Thank you for using WATOBO - The Webapplication Toolbox</h1>
7
+ Info:<br>
8
+ Version: WATOBO_VERSION<br />
9
+ Home dir: WATOBO_HOME<br />
10
+ <br /><br />
11
+ <a href="watobo.pem">Download Certificate</a>
12
+ </body>
13
+ </html>
@@ -27,6 +27,50 @@ module Watobo#:nodoc: all
27
27
  def self.transparent?
28
28
  return true if ( Watobo::Conf::Interceptor.proxy_mode & Watobo::Interceptor::MODE_TRANSPARENT ) > 0
29
29
  return false
30
+ end
31
+
32
+
33
+
34
+ def watobo_srv_get(file)
35
+ srv_file = file.empty? ? File.join(@srv_path, 'index.html') : File.join(@srv_path, file)
36
+ if File.exist? srv_file
37
+ ct = case srv_file
38
+ when /\.ico/
39
+ "image/vnd.microsoft.icon"
40
+ when /\.htm/
41
+ 'text/html; charset=iso-8859-1'
42
+ else
43
+ 'text/plain'
44
+ end
45
+ headers = [ "HTTP/1.0 200 OK", "Server: Watobo-Interceptor", "Connection: close", "Content-Type: #{ct}"]
46
+ content = File.open(srv_file,"rb").read
47
+ content.gsub!('WATOBO_VERSION', Watobo::VERSION )
48
+ content.gsub!('WATOBO_HOME', Watobo.working_directory )
49
+ headers << "Content-Length: #{content.length}"
50
+ r = headers.join("\r\n")
51
+ r << "\r\n\r\n"
52
+ r << content
53
+ return r
54
+ end
55
+
56
+ headers = [ "HTTP/1.0 404 Not Found", "Server: Watobo-Interceptor", "Connection: close", "Content-Type: text/plain; charset=iso-8859-1"]
57
+ content = "The requested file (#{file}) does not exist in the interceptor web folder."
58
+ headers << "Content-Length: #{content.length}"
59
+ r = headers.join("\r\n")
60
+ r << "\r\n\r\n"
61
+ r << content
62
+ return r
63
+
64
+ end
65
+
66
+ def cert_response
67
+ crt_file = File.join(Watobo.working_directory, "CA", "cacert.pem")
68
+ headers = [ "HTTP/1.0 200 OK", "Server: Watobo-Interceptor", "Connection: close", "Content-Type: application/x-pem-file"]
69
+ content = File.read(crt_file)
70
+ headers << "Content-Length: #{content.length}"
71
+ r = headers.join("\r\n")
72
+ r << "\r\n\r\n"
73
+ r << content
30
74
  end
31
75
 
32
76
  def server
@@ -183,6 +227,19 @@ module Watobo#:nodoc: all
183
227
  end
184
228
  #next
185
229
  Thread.exit
230
+ end
231
+
232
+ # check for watobo info page
233
+ if request.host =~ /^watobo$/
234
+ if request.path =~ /watobo\.pem/
235
+ response = cert_response
236
+ else
237
+ response = watobo_srv_get(request.path)
238
+ end
239
+
240
+ c_sock.write response
241
+ c_sock.close
242
+ Thread.exit
186
243
  end
187
244
 
188
245
  request_intercepted = false
@@ -231,17 +288,16 @@ module Watobo#:nodoc: all
231
288
  Thread.exit
232
289
  end
233
290
 
234
- # check if response should be passed throug
291
+ # check if response should be passed through
235
292
  #Thread.current.exit if isPassThrough?(req, resp, s_sock, c_sock)
236
293
  if isPassThrough?(req, resp, s_sock, c_sock)
294
+ #puts "[Interceptor] PassThrough >> #{req.url}"
237
295
  Watobo::HTTPSocket.close s_sock
238
296
  c_sock.close
239
297
  Thread.exit
240
298
  end
241
- #p "no pass-through"
242
-
299
+
243
300
  begin
244
- # puts "* got response status: #{resp.status}"
245
301
  missing_credentials = false
246
302
  rs = resp.status
247
303
  auth_type = AUTH_TYPE_NONE
@@ -271,18 +327,11 @@ module Watobo#:nodoc: all
271
327
  resp.unshift "HTTP/1.1 200 OK\r\n"
272
328
  end
273
329
  end
274
- #else
275
-
276
- #resp.push "WATOBO: Unknown authorization type.<br><br>\r\n" + resp.join("<br>\r\n")
277
- #resp.shift
278
- #resp.unshift "HTTP/1.1 200 OK\r\n"
279
- #resp.fix_content_length
280
-
281
330
  end
282
331
  end
283
-
284
- unless auth_type == AUTH_TYPE_UNKNOWN or req.method =~ /^head/i
285
- # don't try to read body if request method is HEAD
332
+
333
+ # don't try to read body if request method is HEAD
334
+ unless auth_type == AUTH_TYPE_UNKNOWN or req.method =~ /^head/i
286
335
  sender.readHTTPBody(s_sock, resp, req, :update_sids => true)
287
336
  Watobo::HTTPSocket.close s_sock
288
337
  end
@@ -319,8 +368,8 @@ module Watobo#:nodoc: all
319
368
  end
320
369
 
321
370
  # puts ">> SEND TO CLIENT"
322
- # puts ">>C<< - Close: #{request.connection_close?}"
323
- #request.headers("Connection"){ |h| puts h }
371
+ # puts ">>C<< - Close: #{request.connection_close?}"
372
+ # request.headers("Connection"){ |h| puts h }
324
373
 
325
374
  if missing_credentials
326
375
  resp.set_header("Connection", "close")
@@ -388,7 +437,9 @@ module Watobo#:nodoc: all
388
437
 
389
438
  #Watobo::Interceptor.proxy_mode = INTERCEPT_NONE
390
439
 
391
- init_instance_vars
440
+ init_instance_vars
441
+
442
+ @srv_path = File.join(File.dirname(__FILE__),'html')
392
443
 
393
444
  @awaiting_requests = 0
394
445
  @awaiting_responses = 0
@@ -658,7 +709,8 @@ module Watobo#:nodoc: all
658
709
  begin
659
710
  # return false if true
660
711
  reason = nil
661
- clen = response.content_length
712
+ clen = response.content_length
713
+
662
714
  # no pass-through necessary if request method is HEAD
663
715
  return false if request.method =~ /^head/i
664
716
 
@@ -215,6 +215,7 @@ module Watobo#:nodoc: all
215
215
  end
216
216
  url
217
217
  end
218
+ # alias :url :url_string
218
219
 
219
220
  def site
220
221
  #@site ||= nil
@@ -422,10 +423,10 @@ module Watobo#:nodoc: all
422
423
  self.headers.each do |header|
423
424
  begin
424
425
  if header =~ /^#{header_name}/i then
425
- dummy = header.split(/:/)
426
- value=dummy[1]
427
- value.gsub!(/^[ ]*/,"")
428
- header_values.push value
426
+ vstart = header.index ':'
427
+ unless vstart.nil?
428
+ header_values.push header[vstart+1..-1].strip
429
+ end
429
430
  end
430
431
  rescue => bang
431
432
  puts bang
@@ -438,11 +439,21 @@ module Watobo#:nodoc: all
438
439
  def content_type(default_ct='undefined')
439
440
  ct = default_ct
440
441
  self.each do |line|
442
+ begin
441
443
  break if line.strip.empty?
442
- if line =~ /^Content-Type:([^;]*);?/i then
444
+ #cl = line.encode('ASCII', :invalid => :replace, :undef => :replace)
445
+ cl = line.force_encoding('ASCII-8BIT')
446
+ if cl =~ /^Content-Type:([^;]*);?/i then
443
447
  ct = $1
444
448
  break
445
449
  end
450
+ rescue => bang
451
+ puts "! could not parse content_type !"
452
+ puts bang
453
+ puts cl
454
+ # puts cl.gsub(/[^[:print:]]/, '.')
455
+
456
+ end
446
457
  end
447
458
  return ct.strip
448
459
  end
@@ -451,7 +462,9 @@ module Watobo#:nodoc: all
451
462
  ct = default_ct
452
463
  self.each do |line|
453
464
  break if line.strip.empty?
454
- if line =~ /^Content-Type:(.*)/i then
465
+ # cl = line.encode('ASCII', :invalid => :replace, :undef => :replace)
466
+ cl = line.force_encoding('ASCII-8BIT')
467
+ if cl =~ /^Content-Type:(.*)/i then
455
468
  ct = $1.strip
456
469
  break
457
470
  end
@@ -654,13 +667,15 @@ def content_encoding
654
667
  return b.unpack("C*").pack("C*")
655
668
  end
656
669
 
657
- def responseCode
670
+ def status_code
658
671
  if self.first =~ /^HTTP\/... (\d+) /
659
672
  return $1
660
673
  else
661
674
  return nil
662
675
  end
663
676
  end
677
+
678
+ alias :responseCode :status_code
664
679
 
665
680
  # returns array of new cookies
666
681
  # Set-Cookie: mycookie=b41dc9e55d6163f78321996b10c940edcec1b4e55a76464c4e9d25e160ac0ec5b769806b; Path=/
@@ -708,23 +723,18 @@ end
708
723
 
709
724
  def headers(filter=nil, &b)
710
725
  begin
726
+ filter = '.*' if filter.nil?
711
727
  header_list=[]
712
728
  self.each do |line|
713
- cl = line.unpack("C*").pack("C*")
729
+ cl = line.force_encoding('ASCII-8BIT')
714
730
  return header_list if cl.strip.empty?
715
- unless filter.nil?
716
- if cl =~ /#{filter}/
717
- yield line if block_given?
718
- header_list.push line
719
- end
720
- else
731
+ if cl =~ /#{filter}/
721
732
  yield line if block_given?
722
733
  header_list.push line
723
- end
734
+ end
724
735
  end
725
736
  return header_list
726
737
  rescue => bang
727
- puts "! no headers available !".upcase
728
738
  puts bang
729
739
  puts bang.backtrace
730
740
  if $DEBUG