sql_injection:example_attacks
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
sql_injection:example_attacks [2016/10/13 12:15] – peter | sql_injection:example_attacks [2020/04/16 20:52] (current) – removed peter | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== SQL Injection - Example attacks ====== | ||
- | [[SQL Injection - Example attacks: | ||
- | |||
- | [[SQL Injection - Example attacks: | ||
- | |||
- | |||
- | ===== Basic SQLi attack ===== | ||
- | |||
- | If user input is inserted without modification into an SQL query, then the application becomes vulnerable to SQL injection, like in the following example: | ||
- | |||
- | <code php> | ||
- | $unsafe_variable = $_POST[' | ||
- | |||
- | mysql_query(" | ||
- | </ | ||
- | |||
- | That's because the user can input something like | ||
- | |||
- | <code php> | ||
- | value' | ||
- | </ | ||
- | |||
- | and the query becomes: | ||
- | |||
- | <code sql> | ||
- | INSERT INTO `table` (`column`) VALUES(' | ||
- | </ | ||
- | |||
- | |||
- | ===== SQL injection example ===== | ||
- | |||
- | Here is a sample string that has been gathered from a normal user and a bad user trying to use SQL Injection. We asked the users for their login, which will be used to run a SELECT statement to get their information. | ||
- | |||
- | MySQL & PHP Code: | ||
- | |||
- | <code php> | ||
- | // A good user's name. | ||
- | $name = " | ||
- | $query = " | ||
- | echo " | ||
- | |||
- | // User input that uses SQL Injection. | ||
- | $name_bad = "' | ||
- | |||
- | // Our MySQL query builder, however, not a very safe one. | ||
- | $query_bad = " | ||
- | |||
- | // Display what the new query will look like, with injection. | ||
- | echo " | ||
- | </ | ||
- | |||
- | Displays: | ||
- | |||
- | <code sql> | ||
- | Normal: SELECT * FROM customers WHERE username = ' | ||
- | Injection: SELECT * FROM customers WHERE username = '' | ||
- | </ | ||
- | |||
- | The normal query is no problem, as our MySQL statement will just select everything from customers that has a username equal to john. | ||
- | |||
- | However, the injection attack has actually made our query behave differently than we intended. | ||
- | |||
- | * username = ' '// // and then added on to our WHERE statement with an OR clause of 1 which is always true. | ||
- | * username = ' ' OR 1// This OR clause of 1 will always be true and so every single entry in the " | ||
- | |||
- | |||
- | ==== A more serious SQL injection attack ==== | ||
- | |||
- | Although the above example displayed a situation where an attacker could possibly get access to a lot of information they shouldn' | ||
- | |||
- | MySQL & PHP Code: | ||
- | |||
- | <code php> | ||
- | $name_evil = "'; | ||
- | |||
- | // Our MySQL query builder really should check for injection. | ||
- | $query_evil = " | ||
- | |||
- | // The new evil injection query would include a DELETE statement. | ||
- | echo " | ||
- | </ | ||
- | |||
- | Displays: | ||
- | |||
- | <code sql> | ||
- | SELECT * FROM customers WHERE username = ' '; DELETE FROM customers WHERE 1 or username = ' ' | ||
- | </ | ||
- | |||
- | If you were run this query, then the injected DELETE statement would completely empty your " | ||
- | |||
- | |||
- | ==== injection prevention - mysql_real_escape_string() ==== | ||
- | |||
- | This problem has been known for a while and PHP has a specially-made function to prevent these attacks. | ||
- | |||
- | What mysql_real_escape_string does is take a string that is going to be used in a MySQL query and returns the same string with all SQL Injection attempts safely escaped. | ||
- | |||
- | Lets try out this function on our two previous injection attacks and see how it works. | ||
- | |||
- | MySQL & PHP Code: | ||
- | |||
- | <code php> | ||
- | //NOTE: you must be connected to the database to use this function! | ||
- | // connect to MySQL | ||
- | |||
- | $name_bad = "' | ||
- | $name_bad = mysql_real_escape_string($name_bad); | ||
- | |||
- | $query_bad = " | ||
- | echo " | ||
- | |||
- | $name_evil = "'; | ||
- | $name_evil = mysql_real_escape_string($name_evil); | ||
- | |||
- | $query_evil = " | ||
- | echo " | ||
- | </ | ||
- | |||
- | Displays: | ||
- | |||
- | <code sql> | ||
- | Escaped Bad Injection: | ||
- | SELECT * FROM customers WHERE username = ' | ||
- | Escaped Evil Injection: | ||
- | SELECT * FROM customers WHERE username = ' | ||
- | </ | ||
- | |||
- | Notice that those evil quotes have been escaped with a backslash \, preventing the injection attack. | ||
- | |||
- | * Bad: \' OR 1\' | ||
- | * Evil: \'; DELETE FROM customers WHERE 1 or username = \' | ||
- | |||
- | The handy **mysql_real_escape_string()** function has helped prevent SQL Injection attacks on your websites. | ||
- | |||
- | |||
- | ==== injection prevention - MySQLi ==== | ||
- | |||
- | The **mysql_real_escape_string()** function has been obsoleted in more recent versions of PHP. MySQLi supports parameterized queries. | ||
- | |||
- | Instead of | ||
- | |||
- | <code php> | ||
- | $unsafe_variable = $_POST[" | ||
- | $safe_variable = mysql_real_escape_string($unsafe_variable); | ||
- | |||
- | mysql_query(" | ||
- | </ | ||
- | |||
- | use this: | ||
- | |||
- | <code php> | ||
- | <?php | ||
- | $mysqli = new mysqli(" | ||
- | |||
- | // TODO - Check that connection was successful. | ||
- | $unsafe_variable = $_POST[" | ||
- | |||
- | $stmt = $mysqli-> | ||
- | |||
- | // TODO check that $stmt creation succeeded. | ||
- | |||
- | // " | ||
- | $stmt-> | ||
- | $stmt-> | ||
- | $stmt-> | ||
- | $mysqli-> | ||
- | ?> | ||
- | </ | ||
- | |||
- | The key function to read up on there would be [[http:// | ||
- | |||
- | A better alternative is to use [[http:// | ||
- | |||
- | ===== Example attacks ===== | ||
- | |||
- | **Scenario #1**: The application uses untrusted data in the construction of the following vulnerable SQL call: | ||
- | |||
- | <code java> | ||
- | String query = " | ||
- | </ | ||
- | |||
- | **Scenario #2**: Similarly, an application’s blind trust in frameworks may result in queries that are still vulnerable, (e.g., Hibernate Query Language (HQL)): | ||
- | |||
- | <code sql> | ||
- | Query HQLQuery = session.createQuery(“FROM accounts WHERE custID=' | ||
- | </ | ||
- | |||
- | In both cases, the attacker modifies the ‘id’ parameter value in her browser to send: ' or ' | ||
- | |||
- | For example: | ||
- | |||
- | This changes the meaning of both queries to return all the records from the accounts table. | ||
- | |||
- | **Scenario #3**: Code to do an insert into the database could also be vulnerable. | ||
- | |||
- | <code sql> | ||
- | $sql = " | ||
- | execute_sql($sql); | ||
- | </ | ||
- | |||
- | The first line creates a string containing an SQL INSERT statement. The content of the **$studentName** variable is glued into the SQL statement. The second line sends the resulting SQL statement to the database. The pitfall of this code is that outside data, in this case the content of $studentName, | ||
- | |||
- | First let's see what the SQL statement looks like if we insert a student named John: | ||
- | |||
- | <code sql> | ||
- | INSERT INTO Students (Name) VALUES (' | ||
- | </ | ||
- | |||
- | This does exactly what we want: it inserts John into the Students table. | ||
- | |||
- | Now we insert some injection code by setting $studentName to **< | ||
- | |||
- | <code sql> | ||
- | INSERT INTO Students (Name) VALUES (' | ||
- | </ | ||
- | |||
- | This inserts Robert into the Students table. However, the INSERT statement is now followed by a **DROP TABLE** statement which removes the entire Students table. Ouch! | ||
- | |||
- | |||
- | ===== Attack against PHP addslashes ===== | ||
- | |||
- | In [[http:// | ||
- | |||
- | How does this help? If I want to attempt an SQL injection attack against a MySQL database, having single quotes escaped with a backslash is a bummer. If you're using addslashes(), | ||
- | |||
- | I'm going to use MySQL 5.0 and PHP's mysqli extension for this demonstration. If you want to try this yourself, make sure you're using GBK. I just changed / | ||
- | |||
- | |||
- | <file bash / | ||
- | [client]default-character-set=GBK | ||
- | </ | ||
- | |||
- | Create a table called users: | ||
- | |||
- | <code mysql> | ||
- | CREATE TABLE users ( | ||
- | username VARCHAR(32) CHARACTER SET GBK, | ||
- | password VARCHAR(32) CHARACTER SET GBK, | ||
- | PRIMARY KEY (username)); | ||
- | </ | ||
- | |||
- | The following script mimics a situation where only **addslashes()** (or **magic_quotes_gpc**) is used to escape the data being used in a query: | ||
- | |||
- | <code php> | ||
- | <? | ||
- | |||
- | $mysql = array(); | ||
- | | ||
- | $db = mysqli_init(); | ||
- | $db-> | ||
- | | ||
- | $_POST[' | ||
- | | ||
- | $mysql[' | ||
- | $mysql[' | ||
- | | ||
- | $sql = " | ||
- | FROM users | ||
- | WHERE username = ' | ||
- | AND password = ' | ||
- | | ||
- | $result = $db-> | ||
- | | ||
- | if ($result-> | ||
- | /* Success */ | ||
- | } | ||
- | else | ||
- | { | ||
- | /* Failure */ | ||
- | } | ||
- | ?> | ||
- | </ | ||
- | |||
- | Despite the use of **addslashes()**, | ||
- | |||
- | The following PHP cURL script would be able to make use of the injection: | ||
- | |||
- | <code php> | ||
- | <?php | ||
- | |||
- | $url = " | ||
- | $ref = " | ||
- | $session = " | ||
- | |||
- | $ch = curl_init(); | ||
- | |||
- | curl_setopt( $ch, CURLOPT_URL, | ||
- | curl_setopt( $ch, CURLOPT_REFERER, | ||
- | curl_setopt( $ch, CURLOPT_RETURNTRANSFER, | ||
- | curl_setopt( $ch, CURLOPT_COOKIE, | ||
- | curl_setopt( $ch, CURLOPT_POST, | ||
- | curl_setopt( $ch, CURLOPT_POSTFIELDS, | ||
- | "OR 1=1/ | ||
- | |||
- | $data = curl_exec( $ch ); | ||
- | |||
- | print( $data ); | ||
- | curl_close( $ch ); | ||
- | ?> | ||
- | </ | ||
- | |||
- | To avoid this type of vulnerability, | ||
- | |||
- | See also http:// | ||
- | |||
- | This points out the additional risk associated with changing the character set via an SQL query: | ||
- | |||
- | <code mysql> | ||
- | SET CHARACTER SET ' | ||
- | </ | ||
- | |||
- | Doing so does not affect **mysql_real_escape_string()**, | ||
- | |||
- | Just use **mysql_set_character_set()**. | ||
- | |||
- | http:// | ||
- | |||
- | > This function works like the SET NAMES statement, but also sets the value of mysql-> | ||
- | |||
- | |||
- | The function in php with mysqli is **mysqli_set_charset()**. | ||
- | |||
- | http:// | ||
- | |||
- | The " | ||
- | |||
- | <code php> | ||
- | <?php | ||
- | mysql_connect(" | ||
- | mysql_query(" | ||
- | $file = fopen(" | ||
- | fwrite($file, | ||
- | fclose($file); | ||
- | ?> | ||
- | </ | ||
- | |||
- | |||
- | ===== Other attacks ===== | ||
- | |||
- | Passing the following in as input. | ||
- | |||
- | <code php> | ||
- | -1 union all select table_name from information_schema.tables | ||
- | </ | ||
- | |||
- | and now just extract table structure: | ||
- | |||
- | <code sql> | ||
- | SELECT ... WHERE id = -1 union all select column_name from information_schema.column where table_name = 0x61727469636c65 | ||
- | </ | ||
- | |||
- | |||
- | ===== References ===== | ||
- | |||
- | * http:// | ||
- | |||
- | * http:// |
sql_injection/example_attacks.1476360958.txt.gz · Last modified: 2020/07/15 09:30 (external edit)