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.

redis.rb 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. # -*- coding: binary -*-
  2. require 'msf/core/exploit'
  3. module Msf
  4. ###
  5. #
  6. # This module provides methods for working with redis
  7. #
  8. ###
  9. module Auxiliary::Redis
  10. include Msf::Exploit::Remote::Tcp
  11. include Auxiliary::Scanner
  12. include Auxiliary::Report
  13. #
  14. # Initializes an instance of an auxiliary module that interacts with Redis
  15. #
  16. def initialize(info = {})
  17. super
  18. register_options(
  19. [
  20. Opt::RPORT(6379),
  21. OptString.new('PASSWORD', [false, 'Redis password for authentication test', 'foobared'])
  22. ]
  23. )
  24. register_advanced_options(
  25. [
  26. OptInt.new('READ_TIMEOUT', [true, 'Seconds to wait while reading redis responses', 2])
  27. ]
  28. )
  29. end
  30. def read_timeout
  31. datastore['READ_TIMEOUT']
  32. end
  33. def report_redis(version)
  34. report_service(
  35. host: rhost,
  36. port: rport,
  37. proto: 'tcp',
  38. name: 'redis',
  39. info: "version #{version}"
  40. )
  41. end
  42. def redis_command(*commands)
  43. command_string = printable_redis_response(commands.join(' '))
  44. unless (command_response = send_redis_command(*commands))
  45. vprint_error("No response to '#{command_string}'")
  46. return
  47. end
  48. if /(?<auth_response>ERR operation not permitted|NOAUTH Authentication required)/i =~ command_response
  49. fail_with(::Msf::Module::Failure::BadConfig, "#{peer} requires authentication but Password unset") unless datastore['Password']
  50. vprint_status("Requires authentication (#{printable_redis_response(auth_response, false)})")
  51. if (auth_response = send_redis_command('AUTH', datastore['PASSWORD']))
  52. unless auth_response =~ /\+OK/
  53. vprint_error("Authentication failure: #{printable_redis_response(auth_response)}")
  54. return
  55. end
  56. vprint_status("Authenticated")
  57. unless (command_response = send_redis_command(*commands))
  58. vprint_error("No response to '#{command_string}'")
  59. return
  60. end
  61. else
  62. vprint_status("Authentication failed; no response")
  63. return
  64. end
  65. end
  66. vprint_status("Redis command '#{command_string}' got '#{printable_redis_response(command_response)}'")
  67. command_response
  68. end
  69. def printable_redis_response(response_data, convert_whitespace = true)
  70. Rex::Text.ascii_safe_hex(response_data, convert_whitespace)
  71. end
  72. private
  73. def redis_proto(command_parts)
  74. return if command_parts.blank?
  75. command = "*#{command_parts.length}\r\n"
  76. command_parts.each do |c|
  77. command << "$#{c.length}\r\n#{c}\r\n"
  78. end
  79. command
  80. end
  81. def send_redis_command(*command_parts)
  82. sock.put(redis_proto(command_parts))
  83. command_response = sock.get_once(-1, read_timeout)
  84. return unless command_response
  85. command_response.strip
  86. end
  87. end
  88. end