Path: blob/master/modules/auxiliary/admin/mssql/mssql_idf.rb
19515 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45##6# Author: Robin Wood <[email protected]> <http://www.digininja.org>7# Version: 0.18#9# This module will search the specified MSSQL server for10# 'interesting' columns and data11#12##1314class MetasploitModule < Msf::Auxiliary15include Msf::Exploit::Remote::MSSQL16include Msf::OptionalSession::MSSQL1718def initialize(info = {})19super(20update_info(21info,22'Name' => 'Microsoft SQL Server Interesting Data Finder',23'Description' => %q{24This module will search the specified MSSQL server for25'interesting' columns and data.2627This module has been tested against the latest SQL Server 2019 docker container image (22/04/2021).28},29'Author' => [ 'Robin Wood <robin[at]digininja.org>' ],30'License' => MSF_LICENSE,31'References' => [32[ 'URL', 'http://www.digininja.org/metasploit/mssql_idf.php' ],33],34'Notes' => {35'Stability' => [CRASH_SAFE],36'SideEffects' => [IOC_IN_LOGS],37'Reliability' => []38}39)40)4142register_options(43[44OptString.new('NAMES', [ true, 'Pipe separated list of column names', 'passw|bank|credit|card']),45]46)47end4849def print_with_underline(str)50print_line(str)51print_line('=' * str.length)52end5354def run55headings = [56['Database', 'Schema', 'Table', 'Column', 'Data Type', 'Row Count']57]5859sql = ''60sql += 'DECLARE @dbname nvarchar(255), @id int, @sql varchar (4000); '61sql += 'DECLARE table_cursor CURSOR FOR SELECT name FROM sys.databases '62sql += 'OPEN table_cursor '63sql += 'FETCH NEXT FROM table_cursor INTO @dbname '64sql += 'WHILE (@@FETCH_STATUS = 0) '65sql += 'BEGIN '66sql += "SET @sql = 'select ';"67sql += "SET @sql = @sql + ' ''' + @dbname + ''' as ''Database'', ';"68sql += "SET @sql = @sql + 'sys.schemas.name as ''Schema'', ';"69sql += "SET @sql = @sql + 'sys.objects.name as ''Table'', ';"70sql += "SET @sql = @sql + 'sys.columns.name as ''Column'', ';"71sql += "SET @sql = @sql + 'sys.types.name as ''Column Type'' ';"72sql += "SET @sql = @sql + 'from ' + @dbname + '.sys.columns ';"73sql += "SET @sql = @sql + 'inner join ' + @dbname + '.sys.objects on sys.objects.object_id = sys.columns.object_id ';"74sql += "SET @sql = @sql + 'inner join ' + @dbname + '.sys.types on sys.types.user_type_id = sys.columns.user_type_id ';"75sql += "SET @sql = @sql + 'inner join ' + @dbname + '.sys.schemas on sys.schemas.schema_id = sys.objects.schema_id ';"7677list = datastore['Names']78where = "SET @sql = @sql + ' WHERE ("79list.split(/\|/).each do |val|80where += " lower(sys.columns.name) like ''%" + val + "%'' OR "81end8283where.slice!(-3, 4)8485where += ") ';"8687sql += where8889sql += "SET @sql = @sql + 'and sys.objects.type=''U'';';"90sql += 'EXEC (@sql);'91sql += 'FETCH NEXT FROM table_cursor INTO @dbname '92sql += 'END '93sql += 'CLOSE table_cursor '94sql += 'DEALLOCATE table_cursor '9596begin97if session98set_mssql_session(session.client)99else100unless mssql_login_datastore101print_error('Login failed')102return103end104end105result = mssql_query(sql, false)106rescue Rex::ConnectionRefused => e107print_error("Connection failed: #{e}")108return109end110111column_data = result[:rows]112widths = [0, 0, 0, 0, 0, 9]113total_width = 0114115if result[:errors] && !result[:errors].empty?116result[:errors].each do |err|117print_error(err)118end119end120121if column_data.nil?122print_error("No columns matched the pattern #{datastore['NAMES'].inspect}. Set the NAMES option to change this search pattern.")123return124end125126(column_data | headings).each do |row|1270.upto(4) do |col|128widths[col] = row[col].length if row[col].length > widths[col]129end130end131132widths.each do |a|133total_width += a134end135136print_line137138buffer = ''139headings.each do |row|1400.upto(5) do |col|141buffer += row[col].ljust(widths[col] + 1)142end143print_line(buffer)144print_line145buffer = ''1461470.upto(5) do |col|148buffer += print '=' * widths[col] + ' '149end150print_line(buffer)151print_line152end153154column_data.each do |row|155count_sql = 'SELECT COUNT(*) AS count FROM '156157full_table = ''158column_name = ''159buffer = ''1600.upto(4) do |col|161full_table += row[col] + '.' if col < 3162column_name = row[col] if col == 3163buffer += row[col].ljust(widths[col] + 1)164end165full_table.slice!(-1, 1)166count_sql += full_table167168result = mssql_query(count_sql, false) if mssql_login_datastore169170count_data = result[:rows]171row_count = count_data[0][0]172173buffer += row_count.to_s174print_line(buffer)175print_line176end177178print_line179disconnect180end181end182183184