I've a website that hacked today. Server logs returned something like this as hacker's tries:
www.site.com/notifications.php?PID=7&id=999999.9%20union%20all%20select%20%28select%20distinct%20concat%280x7e%2C0x27%2Cunhex%28Hex%28cast%28schema_name%20as%20char%29%29%29%2C0x27%2C0x7e%29%20from%20%60information_schema%60.schemata%20limit%201%2C1%29%2C0x31303235343830303536%2C0x31303235343830303536%2C0x31303235343830303536--
But I've used mysql_real_escape_string() in my code:
if (isset($_GET['id']) && $_GET['id'] != '') {
$id = mysql_real_escape_string($_GET['id']);
} else {
$id = '';
}
if ($id == '') {
$stmt = "SELECT * FROM tbln13 ORDER BY id DESC";
} else {
$stmt = "SELECT * FROM tbln13 WHERE id = $id";
}
$NewsResult = mysql_query($stmt) or die (mysql_error());
Why my website could not prevent this attack?
Because your escaped variable is not a string therefore it is not inside quotes in your query. If you want a quick fix you can change your query to:
It is not standard use for numeric comparison but should work.
Because escape_string add slashes and such to quotes. You didn't have any quotes in your query, or the string they submitted.
Your query doesn't have a STRING in it, it appears to expect an int. If you expected an integer, you should have verified it was an int, or forced it to an int, before using it in a query. Escaping a value as a string, then using it as an int, won't work.
Switch to prepared statements in MySQLi or PDO.
As mentioned by others, you should ditch deprecated
mysql_*
functions and instead used prepared statements viamysqli
orPDO
.Even then you should also be validating your input, because just using prepared statements will not help you identify whether you have input values that are valid. You would ideally make sure all your input is valid before even attempting a prepared statement. In this case, this validation could be as simple as this:
Use prepared statements, that will, in most cases, prevent
SQL injections
.A simple and comprehensible guide to prepared statements can be found in this website:
Bobby Tables
More over you should stop using MYSQL, it's outdated and will be removed in future implementations. Use
MySQLi
orPDO
instead.The sql injected query looks like this
as you see, you were injected because you have just allowed this!
You expected a number but you didn't check for it! So you got the number and something more.
You should have checked the
$id
variable for what you expected, which is the number. This is what I would use: