Exploiting second-order SQL injection 利用二阶注入获取数据库版本信息 SQL Injection Attacks and Defense Second Edition
w
SQL Injection Attacks and Defense Second Edition
Exploiting second-order SQL injection
Virtually every instance of SQL injection discussed in this book so far may be classified as
“first-order” SQL injection. This is because the events involved all occur within a single HTTP
request and response, as follows:
1 The attacker submits some crafted input in an HTTP request.
2 The application processes the input, causing the attacker’s injected SQL query to execute.
3 If applicable, the results of the query are returned to the attacker in the application’s response
to the request.
A different type of SQL injection attack is “second-order” SQL injection. Here, the
sequence of events is typically as follows:
1 The attacker submits some crafted input in an HTTP request.
2 The application stores that input for future use (usually in the database), and responds to the
request.
3 The attacker submits a second (different) request.
4 To handle the second request, the application retrieves the stored input and processes it,
causing the attacker’s injected SQL query to execute.
5 If applicable, the results of the query are returned to the attacker in the application’s response
to the second request.
Second-order SQL injection is just as powerful as the first-order equivalent; however, it is a
subtler vulnerability which is generally more difficult to detect.
Second-order SQL injection usually arises because of an easy mistake that developers make
when thinking about tainted and validated data. At the point where input is received directly
from users, it is clear that this input is potentially tainted, and so clued-in developers will make
some efforts to defend against first-order SQL injection, such as doubling up single quotes or
(preferably) using parameterized queries. However, if this input is persisted and later reused, it
may be less obvious that the data are still tainted, and some developers make the mistake of
handling the data unsafely at this point.
Consider an address book application which allows users to store contact information about
their friends. When creating a contact, the user can enter details such as name, e-mail, and
address. The application uses an INSERT statement to create a new database entry for the
contact, and doubles up any quotation marks in the input to prevent SQL injection attacks (see
Figure 7.1).
The application also allows users to modify selected details about an existing contact. When
a user modifies an existing contact, the application first uses a SELECT statement to retrieve
the current details about the contact, and holds the details in memory. It then updates the
relevant items with the new details provided by the user, again doubling up any quotation
marks in this input. Items which the user has not updated are left unchanged in memory. The
application then uses an UPDATE statement to write all of the in-memory items back to the
database (see Figure 7.2).
The quotes are doubled up in your input, and the resultant INSERT statement looks like this:
INSERT INTO tbl Contacts VALUES (‘a‘‘+@@version+’’a’, ‘foo@example.org’,…
Hence, the contact name is safely stored in the database, with the literal value that you
submitted.
Then, you need to go to the function to update the new contact, and provide a new value in
the address field only (any accepted value will do). When you do this, the application will first
retrieve the existing contact details, using the following statement:
SELECT
?
FROM tbl Users WHERE contact Id = 123
The retrieved details are stored briefly in memory. The value retrieved for the name field
will, of course, be the literal value that you originally submitted, because this is what was
stored in the database. The application replaces the retrieved address in memory with the new
value you supplied, taking care to double up quotation marks. It then performs the following
UPDATE statement to store the new information in the database:
UPDATE tbl Users
SET name=‘a’+@@version+‘a’, address=‘52 Throwley Way’,…
WHERE contact Id = 123
At this point, your attack is successful and the application’s query is subverted. The name
retrieved from the database is handled unsafely, and you are able to break out of the data
context within the query and modify the query’s structure. In this proof-of-concept attack, the
database version string is copied into the name of your contact, and will be displayed on-screen
when you view the updated contact details:
Name: a Microsoft SQL Server 7.00 – 7.00.623 (Intel X86) Nov 27 199822:20:07 Copyright (c)
1988–1998 Microsoft Corporation Desktop
Edition on Windows NT 5.1 (Build 2600:)a
Address: 52 Throwley Way Let’s assume that the doubling up of quotation marks in this instance is effective in
preventing first-order SQL injection. Nevertheless, the application is still vulnerable to second-
order attacks. To exploit the vulnerability, you first need to create a contact with your attack
payload in one of the fields. Assuming the database is Microsoft SQL Server, create a contact
with the following name:
a‘+@@version+’a To perform a more effective attack, you would need to use the general techniques already
described for injecting into UPDATE statements (see Chapter 4), again placing your attacks
into one contact field and then updating a different field to trigger the vulnerability.