SQL injection (SQLi) is a type of code injection relying on the Structured Query Language (SQL).
SQL is a language used to interact with Database Management Systems (DBMS). SQLi can happen, for example, when the user of a website can inject malicious SQL code in a login form in order to interact directly with the database management system running on the server.This allows an attacker to retrieve information from the database, bypass login form and might allow the attacker to compromise the server.
Searching and exploiting SQLi
Most websites use a database management system (DBMS). The database might be used to store price and quantity for an online shop, users credentials, credit cards number, etc. These databases are hidden from the user, but are sometimes in direct connection with the web server. A login form, for example, will retrieve information from the database in order to compare the credential provided by the user with that from the database and grant access or not. A malformed username or password, if not sanitized, can alter the command issued to check the credentials from the database.
Let's take an example on the Mutillidae website. This is part of Metasploitable, a virtual machine designed to be insecure. Let's take a look at the OWASP/injection/bypass authentication section. Here we find a standard login form. If we try to login using the username admin and the password asdf, we obtain a login failed.
In order to check if our credentials are good, the web server must be communicating with a database. Let's try to add an apostrophe ' after the username. Apostrophe is a character used to start en end strings in SQL. If the server is vulnerable to SQLi, adding an apostrophe to the username will create a syntax error in the request sent to the database.
We can see that the new username with an apostrophe results in a error. We also have a very explicit error message: You have an error in your SQL syntax;
In this case we even have the SQL query that is sent to the database:
SELECT * FROM accounts WHERE username='admin'' AND password='asdf'
We can see that the web server tries to check if a user with a given password exists. If this check fails, the login fails. One way to get a valid results would be to make the web server only check for the username. If the username is valid, then the response from the database will be valid. Given the request made to the server, we can see that we can easily inject some code that will prevent the web server to check the password. In SQL, the commenting character is #. By including this character in the username, we can transform the last part of the request into a comment. This will then only check for the username. For example, we can set the username to
admin' # and the password to
asdf. The full request sent by the web server to the database would be:
SELECT * FROM accounts WHERE username='admin' #' AND password='asdf'
Everything after the # character will be ignored, and the database will only check if the user admin exist. If this user exists the login will be granted.
In the case we don't know any username, the username can be replaced by
admin' or 1=1 #
Since the 1=1 statement is always true, the database will never throw an error to it, and the access should be granted.
How to prevent basic SQLi
As we saw in How to prevent basic code injection, in order to prevent a code injection, you need to sanitize the code that is entered by a user. It is not really common to have a username containing the # character. You can then block any login attempts that contains a # in the username. You can also set a rule on your website to prevent new user to create a username containing characters that could be used in a code injection. In SQL the double dash (--) can also be used as commenting character. This is something worse checking in all the input usernames.
SQLi can be found in many other forms. More advanced SQLi will be described in another post.