Path: blob/master/modules/post/windows/gather/enum_db.rb
19721 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Post::File7include Msf::Post::Windows::Registry8include Msf::Auxiliary::Report910def initialize(info = {})11super(12update_info(13info,14'Name' => 'Windows Gather Database Instance Enumeration',15'Description' => %q{This module will enumerate a Windows system for installed database instances.},16'License' => MSF_LICENSE,17'Author' => [18'Barry Shteiman <barry[at]sectorix.com>', # Module author19'juan vazquez' # minor help20],21'Platform' => [ 'win' ],22'SessionTypes' => [ 'meterpreter' ],23'Notes' => {24'Stability' => [CRASH_SAFE],25'SideEffects' => [],26'Reliability' => []27},28'Compat' => {29'Meterpreter' => {30'Commands' => %w[31stdapi_fs_search32stdapi_sys_config_getenv33]34}35}36)37)38end3940def run41hostname = sysinfo.nil? ? cmd_exec('hostname') : sysinfo['Computer']42print_status("Enumerating databases on #{hostname} (#{session.session_host})")4344results = []45if check_mssql46results += enumerate_mssql47end48if check_oracle49results += enumerate_oracle50end51if check_db252results += enumerate_db253end54if check_mysql55results += enumerate_mysql56end57if check_sybase58results += enumerate_sybase59end6061if results.empty?62print_status('Done, no databases were found')63return64end6566print_status("Done, #{results.length} databases found.")6768tbl = Rex::Text::Table.new(69'Header' => 'Installed Databases',70'Indent' => 1,71'Columns' =>72[73'Type',74'Instance',75'Database',76'Port'77]78)7980results.each do |r|81report_service(host: session.sock.peerhost, port: r[3], name: r[0], info: "#{r[0]}, #{r[1]}")82tbl << r83end8485print_line(tbl.to_s)86p = store_loot('host.databases', 'text/plain', session, tbl.to_s, 'databases.txt', 'Running Databases')87print_good("Results stored in: #{p}")88end8990##### initial identification methods #####9192# Check if MSSQL database instances are installed on host93def check_mssql94if registry_enumkeys('HKLM\\SOFTWARE\\Microsoft').include?('Microsoft SQL Server')95print_status("\tMicrosoft SQL Server found.")96return true97end9899return false100rescue StandardError101return false102end103104# Check if Oracle database instances are installed on host105def check_oracle106keys = registry_enumkeys('HKLM\\SOFTWARE\\Oracle')107108if keys.include?('ALL_HOMES')109print_status("\tOracle Server found.")110return true111end112113if keys.include?('SYSMAN')114print_status("\tOracle Server found.")115return true116end117118if keys.include?('KEY_XE')119print_status("\tOracle Server found.")120return true121end122123return false124rescue StandardError125return false126end127128# Check if DB2 database instances are installed on host129def check_db2130if registry_enumkeys('HKLM\\SOFTWARE\\IBM\\DB2').include?('GLOBAL_PROFILE')131print_status("\tDB2 Server found.")132return true133end134135return false136rescue StandardError137return false138end139140# Check if MySQL database instances are installed on host141def check_mysql142if registry_enumkeys('HKLM\\SOFTWARE').include?('MySQL AB')143print_status("\tMySQL Server found.")144return true145end146return false147rescue StandardError148return false149end150151# Check if Sybase database instances are installed on host152def check_sybase153keys = registry_enumkeys('HKLM\\SOFTWARE\\Sybase')154155if keys.include?('SQLServer')156print_status("\tSybase Server found.")157return true158end159160if keys.include?('Server')161print_status("\tSybase Server found.")162return true163end164165return false166rescue StandardError167return false168end169170##### deep analysis methods #####171172# method to identify MSSQL instances173def enumerate_mssql174results = []175key = 'HKLM\\SOFTWARE\\Microsoft\\Microsoft SQL Server\\Instance Names\\SQL'176instances = registry_enumvals(key)177178return results if instances.blank?179180instances.each do |i|181tcpkey = "HKLM\\SOFTWARE\\Microsoft\\Microsoft SQL Server\\#{registry_getvaldata(key, i)}\\MSSQLServer\\SuperSocketNetLib\\Tcp\\IPAll"182tcpport = registry_getvaldata(tcpkey, 'TcpPort')183print_good("\t\t+ #{registry_getvaldata(key, i)} (Port:#{tcpport})")184results << ['mssql', "instance:#{registry_getvaldata(key, i)} port:#{tcpport}", 'Microsoft SQL Server', tcpport]185end186187results188rescue StandardError189print_error("\t\t! could not identify information")190return results || []191end192193# method to identify oracle instances194def enumerate_oracle195results = []196found_key = false197basekey_set = ['HKLM\\SOFTWARE\\Oracle\\SYSMAN', 'HKLM\\SOFTWARE\\ORACLE\\KEY_XE']198basekey_set.each do |basekey|199next if found_key200201instances = registry_enumkeys(basekey)202203next if instances.blank?204205found_key = true206207instances.each do |i|208if basekey.include? 'KEY_XE'209oracle_sid = registry_getvaldata(basekey, 'ORACLE_SID')210oracle_home = registry_getvaldata(basekey, 'ORACLE_HOME')211else212key = "#{basekey}\\#{i}"213oracle_sid = registry_getvaldata(key, 'ORACLE_SID')214oracle_home = registry_getvaldata(key, 'ORACLE_HOME')215end216217if !exist?(oracle_home + '\\NETWORK\\ADMIN\\tnsnames.ora')218print_error("\t\t! #{oracle_sid} (No Listener Found)")219next220end221222data_tnsnames = read_file(oracle_home + '\\NETWORK\\ADMIN\\tnsnames.ora')223if data_tnsnames =~ /PORT\ =\ (\d+)/224port = ::Regexp.last_match(1)225print_good("\t\t+ #{oracle_sid} (Port:#{port})")226results << [ 'oracle', "instance:#{oracle_sid} port:#{port}", 'Oracle Database Server', port ]227else228print_error("\t\t! #{oracle_sid} (No Listener Found)")229end230end231end232233if !found_key234print_error("\t\t! Oracle instances not found")235end236237results238rescue StandardError239print_error("\t\t! could not identify information")240return results || []241end242243# method to identify mysql instances244def enumerate_mysql245results = []246basekey = 'HKLM\\SOFTWARE\\MySQL AB'247instances = registry_enumkeys(basekey)248249return results if instances.blank?250251instances.each do |i|252key = "#{basekey}\\#{i}"253location = registry_getvaldata(key, 'Location')254255data = read_mysql_conf(location)256if data.nil?257data = find_and_read_mysql_conf258end259260if data && data =~ (/port=(\d+)/)261port = ::Regexp.last_match(1)262print_good("\t\t+ MYSQL (Port:#{port})")263results << ['mysql', "instance:MYSQL port:#{port}", 'MySQL Server', port]264else265print_error("\t\t! could not identify information")266end267end268269results270rescue StandardError271print_error("\t\t! could not identify information")272return results || []273end274275# method to identify sybase instances276def enumerate_sybase277basekey = 'HKLM\\SOFTWARE\\Sybase\\SQLServer'278instance = registry_getvaldata(basekey, 'DSLISTEN')279location = registry_getvaldata(basekey, 'RootDir')280results = []281282if !exist?(location + '\\ini\\sql.ini')283print_error("\t\t! could not locate configuration file.")284return results285end286287data = read_file(location + '\\ini\\sql.ini')288if data =~ /\[#{instance}\]([^\[]*)/289segment = ::Regexp.last_match(1)290else291print_error("\t\t! could not locate information.")292return results293end294295if segment =~ /master=\w+,[^,]+,(\d+)/296port = ::Regexp.last_match(1)297else298print_error("\t\t! could not locate information.")299return results300end301302print_good("\t\t+ #{instance} (Port:#{port})")303results << [ 'sybase', "instance:#{instance} port:#{port}", 'Sybase SQL Server', port ]304return results305rescue StandardError306print_error("\t\t! could not locate information.")307return results || []308end309310# method to identify db2 instances311def enumerate_db2312results = []313cmd_i = cmd_exec('db2cmd', '-i -w /c db2ilist')314cmd_p = cmd_exec('db2cmd', '-i -w /c db2 get dbm cfg')315if cmd_p =~ %r{\ ?TCP/IP\ Service\ name\ +\(SVCENAME\)\ =\ (\w+)}316port = ::Regexp.last_match(1)317else318print_error("\t\t! could not identify instances information")319return results320end321322windir = session.sys.config.getenv('windir')323getfile = session.fs.file.search(windir + '\\system32\\drivers\\etc\\', 'services.*', true, -1)324325data = nil326getfile.each do |file|327if exist?("#{file['path']}\\#{file['name']}")328data = read_file("#{file['path']}\\#{file['name']}")329break if !data.nil?330end331end332333if data && data =~ (/#{port}[\ \t]+(\d+)/)334port_t = ::Regexp.last_match(1)335else336print_error("\t\t! could not identify instances information")337return results338end339340cmd_i.split("\n").compact.each do |line|341stripped = line.strip342print_good("\t\t+ #{stripped} (Port:#{port_t})")343results << [ 'db2', "instance:#{stripped} port:#{port_t}", 'DB2 Server', port_t ]344end345346results347rescue StandardError348print_error("\t\t! could not identify instances information")349return results || []350end351352##### helper methods #####353354def read_mysql_conf(location)355return unless location356357if exist?(location + '\\my.ini')358return read_file(location + '\\my.ini')359end360361if exist?(location + '\\my.cnf')362return read_file(location + '\\my.cnf')363end364365nil366end367368def find_and_read_mysql_conf369sysdriv = session.sys.config.getenv('SYSTEMDRIVE')370getfile = session.fs.file.search(sysdriv + '\\', 'my.ini', true, -1)371getfile.each do |file|372path = "#{file['path']}\\#{file['name']}"373if exist?(path)374return read_file(path)375end376end377378nil379end380end381382383