Mirror of metasploit
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

timing.rb 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. # -*- coding: binary -*-
  2. ##
  3. # This file is part of the Metasploit Framework and may be subject to
  4. # redistribution and commercial restrictions. Please see the Metasploit
  5. # Framework web site for more information on licensing and terms of use.
  6. # https://metasploit.com/framework/
  7. ##
  8. module Msf
  9. module Auxiliary::Web
  10. module Analysis::Timing
  11. TIMING_OPTIONS = {
  12. # stub to be replaced by delay * multi
  13. :stub => '__TIME__',
  14. # stub = delay * multi
  15. :multi => 1,
  16. # delay in seconds to attempt to introduce
  17. :delay => 5
  18. }
  19. #
  20. # Performs timeout/time-delay analysis and logs an issue should there be one.
  21. #
  22. # Fuzzer must provide:
  23. # - #seeds_for -- Array of Strings with server-side code which, when interpreted,
  24. # will cause a delay in response. Must include 'stub'.
  25. #
  26. # Here's how it goes:
  27. # * Ensures that the server is responsive.
  28. # * Injects the seed and makes sure that the expected delay has been successfully introduced.
  29. # * Ensures that the server is responsive -- blocks until the attack has worn off.
  30. # * Increases the original delay and makes sure that the expected delay has been successfully introduced.
  31. # * Ensures that the server is responsive-- blocks until the attack has worn off.
  32. # * Logs the vulnerability.
  33. #
  34. # opts - Options Hash (default: {})
  35. # :timeout - Integer amount of seconds to wait for the request to complete (default: 5)
  36. # :stub - String stub to be replaced by delay * multi (default: __TIME__)
  37. # :multi - Integer multiplier (stub = timeout * multi) (default: 1)
  38. #
  39. def timeout_analysis( opts = {} )
  40. opts = TIMING_OPTIONS.merge( opts )
  41. multi = opts[:multi]
  42. stub = opts[:stub]
  43. return if fuzzed? :type => :timing
  44. fuzzed :type => :timing
  45. permutations.each do |p|
  46. timeout = opts[:delay]
  47. seed = p.altered_value.dup
  48. payload = fuzzer.payloads.select{ |pl| seed.include?( pl ) }.
  49. sort_by { |p2| p2.size }.last
  50. # 1st pass, make sure the webapp is responsive
  51. if_responsive do
  52. # 2nd pass, see if we can manipulate the response times
  53. timeout += 1
  54. p.altered_value = seed.gsub( stub, (timeout * multi).to_s )
  55. p.if_unresponsive( timeout - 1 ) do
  56. # 3rd pass, make sure that the previous step wasn't a fluke (like a dead web server)
  57. if_responsive do
  58. # 4th pass, increase the delay and timeout to make sure that we are the ones
  59. # manipulating the webapp and this isn't all a coincidence
  60. timeout *= 2
  61. timeout += 1
  62. p.altered_value = seed.gsub( stub, (timeout * multi).to_s )
  63. p.if_unresponsive( timeout - 1 ) do
  64. # log it!
  65. fuzzer.process_vulnerability( p, 'Manipulatable response times.',
  66. :payload => payload.gsub( stub, (timeout * multi).to_s ) )
  67. end
  68. end
  69. end
  70. end
  71. end
  72. end
  73. def responsive?( timeout = 120 )
  74. !submit( :timeout => timeout ).timed_out?
  75. end
  76. def responsive_async?( timeout = 120, &callback )
  77. submit_async( :timeout => timeout ) { |r| callback.call !r.timed_out? }
  78. end
  79. def if_responsive( timeout = 120, &callback )
  80. responsive_async?( timeout ) { |b| callback.call if b }
  81. end
  82. def if_unresponsive( timeout = 120, &callback )
  83. responsive_async?( timeout ) { |b| callback.call if !b }
  84. end
  85. end
  86. end
  87. end