watobo 0.9.20 → 0.9.21

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.
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