After initiating this post, it is estimated that many people will not bother to see the question. In the PHP + MySQL environment for a long time, no matter whether it is a program or an injection attack, it is impossible to execute multiple statements. Such a well-known common sense has no reason why no one will know.
Authority is used to be challenged, and common sense is used to be broken. If there is no innovation at all, and you have been struggling with your curiosity, what kind of Hacker and Geek spirit is there to fight for freedom and resolve the world?
I recently saw a very simple SQL Injection case. Although the vulnerability is very simple, the content in the case can be significantly different.
Highlights:The author used mysql multi-statement execution during the injection and exploitation process.
Thanks to the author @ Zi mengyu, we have been thoroughly revolutionizing the creed that we have been serving as Jin Ke Yu law.
Based on the idea of Know it then hack it, I carefully studied how this "Common Sense" was formed and how it was broken by the author.
Starting from the first articles about SQL Injection with MySQL and Advanced SQL Injection with MySQL introduced by angel in China, PHP + MySQL injection has been built on the cornerstone of UNION Select. The Union select method can be used as the SQL Inj method, which has always been subject to many restrictions. For example, if you need to guess the number of fields and the name of the table, union cannot be used without the select statement, the injection points are difficult to operate after order by or group by statements, and blind injection is complicated.
But why do we have to use union select? Apart from the fact that MySQL 3.x does not support subqueries for data in the current year, the main reason is that injection cannot use semicolons to separate and execute multiple SQL statements like mssql. Why? For MySQL and MySQLi extensions in PHP, CLIENT_MULTI_STATEMENTS cannot be set during connect due to security reasons,Even if you manually set this flag during connect, php will still remove it at the source code level.:
php-5.3.8/ext/mysqli/mysqli_nonapi.c
/* set some required options */
flags |= CLIENT_MULTI_RESULTS; /* needed for mysql_multi_query() */
/* remove some insecure options */
flags &= ~CLIENT_MULTI_STATEMENTS; /* don't allow multi_queries via connect parameter */
Without this special setting, MySQL does not allow the use of semicolons in a mysql_query to execute multiple statements. Therefore, this is why we have long considered mysql as the root cause of disallowing many statements. In fact, this is a wrong understanding,Mysql 4.1 allows multi-statement execution.. PHP only limits this usage.
But isn't PHP completely unable to execute multiple statements? The answer is: mysqli_multi_query can be used to execute multiple statements. However, in practical applications, no one will use this statement. What is the situation of another PDO method commonly used by programmers to operate databases?
create table `car`(`name` varchar(32), `type` varchar(32));
<?php
$db = new PDO("mysql:host=localhost:3306;dbname=test", 'root', '');
// works regardless of statements emulation
// $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
//
$sql = "DELETE FROM car; INSERT INTO car(name, type) VALUES ('car13', 'coupe'); INSERT INTO car(name, type) VALUES ('car2', 'coupe');";
//
try {
//$db->exec($sql);
$db->query($sql);
//$stmt = $db->prepare($sql);
//$stmt->execute();
}
catch(PDOException $e){
echo $e->getMessage();
die();
}
After testing, the above multi-statements were executed securely in the case of PDO. Search for PHP source code:
php-5.3.8/ext/mysqlnd/mysqlnd_enum_n_def.h
#define CLIENT_MULTI_STATEMENTS (1UL << 16) /* Enable/disable multi-stmt support */
php-5.3.8/ext/pdo_mysql/mysql_driver.c
#ifdef CLIENT_MULTI_STATEMENTS
|CLIENT_MULTI_STATEMENTS
Sure enough,By default, PHP source code supports the multi-statement execution feature. Multiple statement execution parameters have been defined in the driver mysqlnd..
You know, nowMost PHP programming frameworks use PDO as the underlying database connection mode to support multiple database types.. What does this mean? This means that in the PDO environment, the insert, update, delete, and select types of injection points are no longer important, and the injection points are no longer important in the statement (table, where, orderby), all possibilities are reproduced, mysql features suddenly open in front of us, you can use multiple statements to re-construct the required SQL statements.
Is there no limit on using PDO? Of course not. First, the general framework uses PDO as a database connection. Common Database Operations use parameter binding or prepare to bind parameters. By default, such parameter binding is performed on the php client. In this case, many statements are not allowed. Only the following methods are available:
$ Db-> setAttribute (PDO: ATTR_EMULATE_PREPARES, 0 );
You can use prepare to execute multiple statements (because the parameter binding is performed on the server), which is rare.
So,The multi-statement injection that can be used only exists when PDO is used to connect to the database and execute SQL statements directly using exec or query functions.Is it too harsh? In fact, this type of example is not uncommon. You can always find it by looking for it with your heart.
At the end of this article, I would like to thank the author @ zimeng Peng and @ Laruence for guiding me to find the cause of the vulnerability. They have provided me with a lot of help in viewing PHP code.
GARY