Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/auxiliary/admin/mysql/mysql_enum.rb
Views: 11623
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Auxiliary::Report7include Msf::Exploit::Remote::MYSQL8include Msf::OptionalSession::MySQL910def initialize(info = {})11super(update_info(info,12'Name' => 'MySQL Enumeration Module',13'Description' => %q{14This module allows for simple enumeration of MySQL Database Server15provided proper credentials to connect remotely.16},17'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>' ],18'License' => MSF_LICENSE,19'References' =>20[21[ 'URL', 'https://cisecurity.org/benchmarks.html' ]22]23))2425end2627def report_cred(opts)28service_data = {29address: opts[:ip],30port: opts[:port],31service_name: opts[:service_name],32protocol: 'tcp',33workspace_id: myworkspace_id34}3536credential_data = {37origin_type: :service,38module_fullname: fullname,39username: opts[:user],40private_data: opts[:password],41private_type: :nonreplayable_hash,42jtr_format: 'mysql,mysql-sha1'43}.merge(service_data)4445login_data = {46core: create_credential(credential_data),47status: Metasploit::Model::Login::Status::UNTRIED,48proof: opts[:proof]49}.merge(service_data)5051create_credential_login(login_data)52end5354def run55# If we have a session make use of it56if session57print_status("Using existing session #{session.sid}")58self.mysql_conn = session.client59self.sock = session.client.socket60else61# otherwise fallback to attempting to login62return unless mysql_login_datastore63end6465print_status("Running MySQL Enumerator...")66print_status("Enumerating Parameters")67#-------------------------------------------------------68# getting all variables69vparm = {}70res = mysql_query("show variables") || []71res.each do |row|72# print_status(" | #{row.join(" | ")} |")73vparm[row[0]] = row[1]74end7576#-------------------------------------------------------77# MySQL Version78print_status("\tMySQL Version: #{vparm["version"]}")79print_status("\tCompiled for the following OS: #{vparm["version_compile_os"]}")80print_status("\tArchitecture: #{vparm["version_compile_machine"]}")81print_status("\tServer Hostname: #{vparm["hostname"]}")82print_status("\tData Directory: #{vparm["datadir"]}")8384if vparm["log"] == "OFF"85print_status("\tLogging of queries and logins: OFF")86else87print_status("\tLogging of queries and logins: ON")88print_status("\tLog Files Location: #{vparm["log_bin"]}")89end9091print_status("\tOld Password Hashing Algorithm #{vparm["old_passwords"]}")92print_status("\tLoading of local files: #{vparm["local_infile"]}")93print_status("\tDeny logins with old Pre-4.1 Passwords: #{vparm["secure_auth"]}")94print_status("\tSkipping of GRANT TABLE: #{vparm["skip_grant_tables"]}") if vparm["skip_grant_tables"]95print_status("\tAllow Use of symlinks for Database Files: #{vparm["have_symlink"]}")96print_status("\tAllow Table Merge: #{vparm["have_merge_engine"]}")97print_status("\tRestrict DB Enumeration by Privilege: #{vparm["safe_show_database"]}") if vparm["safe_show_database"]9899if vparm["have_openssl"] == "YES"100print_status("\tSSL Connections: Enabled")101print_status("\tSSL CA Certificate: #{vparm["ssl_ca"]}")102print_status("\tSSL Key: #{vparm["ssl_key"]}")103print_status("\tSSL Certificate: #{vparm["ssl_cert"]}")104else105print_status("\tSSL Connection: #{vparm["have_openssl"]}")106end107108#-------------------------------------------------------109# Database selection110query = "use mysql"111mysql_query(query)112113# Starting from MySQL 5.7, the 'password' column was changed to 'authentication_string'.114if vparm['version'][0..2].to_f > 5.6115password_field = 'authentication_string'116else117password_field = 'password'118end119120# Account Enumeration121# Enumerate all accounts with their password hashes122print_status("Enumerating Accounts:")123query = "select user, host, #{password_field} from mysql.user"124res = mysql_query(query)125if res and res.size > 0126print_status("\tList of Accounts with Password Hashes:")127res.each do |row|128print_good("\t\tUser: #{row[0]} Host: #{row[1]} Password Hash: #{row[2]}")129report_cred(130ip: mysql_conn.peerhost,131port: mysql_conn.peerport,132user: row[0],133password: row[2],134service_name: 'mysql',135proof: row.inspect136)137end138end139# Only list accounts that can log in with SSL if SSL is enabled140if vparm["have_openssl"] == "YES"141query = %Q|select user, host, ssl_type from mysql.user where142(ssl_type = 'ANY') or143(ssl_type = 'X509') or144(ssl_type = 'SPECIFIED')|145res = mysql_query(query)146if res.size > 0147print_status("\tThe following users can login using SSL:")148res.each do |row|149print_status("\t\tUser: #{row[0]} Host: #{row[1]} SSLType: #{row[2]}")150end151end152end153query = "select user, host from mysql.user where Grant_priv = 'Y'"154res = mysql_query(query)155if res and res.size > 0156print_status("\tThe following users have GRANT Privilege:")157res.each do |row|158print_status("\t\tUser: #{row[0]} Host: #{row[1]}")159end160end161162query = "select user, host from mysql.user where Create_user_priv = 'Y'"163res = mysql_query(query)164if res and res.size > 0165print_status("\tThe following users have CREATE USER Privilege:")166res.each do |row|167print_status("\t\tUser: #{row[0]} Host: #{row[1]}")168end169end170query = "select user, host from mysql.user where Reload_priv = 'Y'"171res = mysql_query(query)172if res and res.size > 0173print_status("\tThe following users have RELOAD Privilege:")174res.each do |row|175print_status("\t\tUser: #{row[0]} Host: #{row[1]}")176end177end178query = "select user, host from mysql.user where Shutdown_priv = 'Y'"179res = mysql_query(query)180if res and res.size > 0181print_status("\tThe following users have SHUTDOWN Privilege:")182res.each do |row|183print_status("\t\tUser: #{row[0]} Host: #{row[1]}")184end185end186query = "select user, host from mysql.user where Super_priv = 'Y'"187res = mysql_query(query)188if res and res.size > 0189print_status("\tThe following users have SUPER Privilege:")190res.each do |row|191print_status("\t\tUser: #{row[0]} Host: #{row[1]}")192end193end194query = "select user, host from mysql.user where FILE_priv = 'Y'"195res = mysql_query(query)196if res and res.size > 0197print_status("\tThe following users have FILE Privilege:")198res.each do |row|199print_status("\t\tUser: #{row[0]} Host: #{row[1]}")200end201end202query = "select user, host from mysql.user where Process_priv = 'Y'"203res = mysql_query(query)204if res and res.size > 0205print_status("\tThe following users have PROCESS Privilege:")206res.each do |row|207print_status("\t\tUser: #{row[0]} Host: #{row[1]}")208end209end210queryinmysql = %Q| select user, host211from mysql.user where212(Select_priv = 'Y') or213(Insert_priv = 'Y') or214(Update_priv = 'Y') or215(Delete_priv = 'Y') or216(Create_priv = 'Y') or217(Drop_priv = 'Y')|218res = mysql_query(queryinmysql)219if res and res.size > 0220print_status("\tThe following accounts have privileges to the mysql database:")221res.each do |row|222print_status("\t\tUser: #{row[0]} Host: #{row[1]}")223end224end225226227# Anonymous Account Check228queryanom = "select user, host from mysql.user where user = ''"229res = mysql_query(queryanom)230if res and res.size > 0231print_status("\tAnonymous Accounts are Present:")232res.each do |row|233print_status("\t\tUser: #{row[0]} Host: #{row[1]}")234end235end236237# Blank Password Check238queryblankpass = "select user, host, #{password_field} from mysql.user where length(#{password_field}) = 0 or #{password_field} is null"239res = mysql_query(queryblankpass)240if res and res.size > 0241print_status("\tThe following accounts have empty passwords:")242res.each do |row|243print_status("\t\tUser: #{row[0]} Host: #{row[1]}")244end245end246247# Wildcard host248querywildcrd = 'select user, host from mysql.user where host = "%"'249res = mysql_query(querywildcrd)250if res and res.size > 0251print_status("\tThe following accounts are not restricted by source:")252res.each do |row|253print_status("\t\tUser: #{row[0]} Host: #{row[1]}")254end255end256257mysql_logoff unless session258end259end260261262