Yes, you are completely open to SQL injection, eg via validUsername' injectionPayload %23
, which would give you this query (the #
(encoded as %23
cuts of the remaining '
):
SELECT * FROM users WHERE name='validUsername' injectionPayload #'
Into Outfile
depending on the rights of the user, you could write content into a file with this payload:
-1' UNION ALL SELECT 'injected string' INTO OUTFILE '/path/to/file.php' #
Blind Injection (with valid user credentials)
With your current code, it's hard to get any data directly from the database. You only use the password and the name, and both of those have to be correct, as otherwise your code will not work.
But this is a login script, so it will create a different result for valid user credentials and for invalid ones, correct?
As that is the case, standard blind SQL injection can be used (if you have valid user credentials). The payloads would look something like this:
// mysql 4 or 5?
validUsername' AND substring(version(), 1, 1)='5
validUsername' AND substring(version(), 1, 1)='4
// is first char of database hash smaller than ascii 100?
validUsername' AND ascii(substring((SELECT password FROM mysql.user LIMIT 0,1),1,1))<100 #
[...]
And so on. What happens is that you combine the query with a boolean question. Eg does the database version start with a 5?
. If the answer is true
, then everything works normally, and you are logged in. If the answer is false
, you will not be logged in, as the query will not return data, and thus $numrows == 1
is false.
It creates a lot of requests (especially for a login script), but it is possible to extract data.
Login Bypass
It should also be possible to bypass the login page (login as any user if you know the username but not the password):
-1' UNION ALL SELECT name, md5('password') FROM users WHERE name='attackedUser' #
I didn't test this, but what should happen: the -1
removes the legitimate results of your query, the union
adds the results of the injected query, and the injected query gets the name of an attacked user, and sets the password to password
for this request (and you submit password
as the POST value for password).
Blind Injection (without valid user credentials)
As we have seen in the section above, we can actually set the password, so we do not need valid credentials for a blind injection. You could either combine the first and second attacker described, or I could imagine something like this:
-1' UNION ALL SELECT 1,md5(user) FROM mysql.user LIMIT 0,1 #
This is just a simplified string to show the idea: again, you remove the valid data with -1
, you add your query, and you select as the password the data you want to extract (md5 hashed, as the supplied password will be hashed). Then, as the password you submit via POST, you submit the value you guess (eg root
). Those two values will then be compared via $password == $dbpass
. If you are logged in, your guess is correct, if not, then it's wrong. For guessing password hashes, you can use the substring approach from above.
Conclusion
Even if you think that the SQL injection you have doesn't disclose any information, you should still use prepared statements, as there might be some way to disclose information. And even if there isn't right now, your code might change in the future.