发现MySql有一个弱转义函数,如何利用?
在我正在开发的一个应用程序中,我发现了一个弱转义函数来防止注入。我试图证明这一点,但我很难想出一个简单的例子。
转义函数的工作原理如下(PHP 示例)。
function escape($value) {
$value = str_replace("'","''",$value);
$value = str_replace("\\","\\\\",$value);
return $value;
}
我意识到这不处理使用双引号 (") 编码的值,但所有查询都是使用单引号 (') 构造的。
谁能击败这个转义函数?
要求:
- 查询中的字符串始终用引号引起来。
- 双引号从未使用过
- MySQL 连接设置为 UTF8
简单示例:
$sql = "SELECT id FROM users WHERE username = '" . escape($username) . "' AND password = '" . escape($password) . "'";
$sql = "UPDATE users SET email = '" . escape($email) . "' WHERE id = '" . escape($id) . "'";
In an application I'm working on I've found a weak escape function to prevent injection. I'm trying to prove this, but I'm having trouble coming up with a simple example.
The escape function works as follows (PHP example).
function escape($value) {
$value = str_replace("'","''",$value);
$value = str_replace("\\","\\\\",$value);
return $value;
}
I realize this doesn't deal with values encoded using double quotes ("), but all queries are constructed using single quotes (').
Who can defeat this escape function?
Requirements:
- String in queries are always enclosed in quotes.
- Double-quotes are never used.
- MySQL connection is set to UTF8.
Simple examples:
$sql = "SELECT id FROM users WHERE username = '" . escape($username) . "' AND password = '" . escape($password) . "'";
$sql = "UPDATE users SET email = '" . escape($email) . "' WHERE id = '" . escape($id) . "'";
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
如果您只是用
''
替换'
那么您可以通过注入\'
来利用它,它将变成到\''
中,这将允许您突破,因为这为您提供了“字符文字”单引号和真正的单引号。但是,将"\\"
替换为"\\\\"
可以消除此攻击。双单引号用于“转义”MS-SQL 的单引号,但这不适合 MySQL,但它可以工作。以下代码证明除了三个条件之外,此转义函数对于所有情况都是安全的。此代码排列控制章程的所有可能变体,并测试每个变体以确保单引号括起来的 select 语句不会发生错误。此代码在 MySQL 5.1.41 上进行了测试。
漏洞条件 1:未使用引号。
漏洞利用:
漏洞条件 2:使用双引号
漏洞利用:
漏洞条件 2:使用单引号,但 < a href="http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string" rel="noreferrer">使用替代字符集。 。
利用:
结论是始终使用
mysql_real_escape_string()
作为MySQL的转义例程。连接到 mysql 数据库时,pdo 和 adodb 等参数化查询库始终使用 mysql_real_escape_string() 。addslashes()
是一个逃逸例程的更好,因为它可以处理易受攻击的情况 2。应该注意的是,即使是mysql_real_escape_string()
将停止条件 1,但参数化查询库会停止。If you are just replacing
'
with''
then you could exploit this by injecting a\'
which will turn into a\''
and this will allow you to break out because this gives you a "character literal" single-quote and a real single-quote. However, the replacement of"\\"
with"\\\\"
negates this attack. The double-single-quote is used to "escape" single quotes for MS-SQL, but this isn't proper for MySQL, but it can work.The following codes proves that this escape function is safe for all except three conditions. This code permutes though all possible variations of control charters, and testing each one to make sure an error doesn't occur with a single quote encased select statement. This code was tested on MySQL 5.1.41.
Vulnerable Condition 1: no quote marks used.
Exploit:
Vulnerable Condition 2: double quote marks used
Exploit:
Vulnerable Condition 2: single quotes are used, however an alternative character set is used..
Exploit:
The conclusion is to always use
mysql_real_escape_string()
as the escape routine for MySQL. Parameterized query libraries like pdo and adodb always usemysql_real_escape_string()
when connected to a mysql database.addslashes()
is FAR BETTER of an escape routine because it takes care of vulnerable condition 2. It should be noted that not evenmysql_real_escape_string()
will stop condition 1, however a parameterized query library will.事实上,此外您还可以尝试使用 UNION SELECT
shop.php?productid=322
=>
shop.php?productid=322 UNION SELECT 1,2,3 FROM users WHERE 1;--
显示其他表的信息。
当然,您必须更改表名称和 UNION SELECT 中的数字以匹配您拥有的列数。这是提取管理员用户名和密码等数据的流行方法。
Indeed, in addition you could try something with UNION SELECT
shop.php?productid=322
=>
shop.php?productid=322 UNION SELECT 1,2,3 FROM users WHERE 1;--
To display information from other tables.
Of course you would have to change the table name and the numbers inside the UNION SELECT to match the amount of columns you have. This is a popular way of extracting data like admin user names and passwords.
转义函数不处理多字节字符。检查 http://shiflett.org/blog/2006 /jan/addslashes-versus-mysql-real-escape-string 查看如何利用此转义函数。
享受黑客数据库的乐趣!
The escape function doesn't handle multibyte characters. Check http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string to see how to exploit this escape function.
Have fun hacking your database!
处理数字时怎么样?
变为
SELECT * FROM [Products] WHERE Productid=322
变为
SELECT * FROM [Products] WHERE Productid=322;从产品中删除;--
(并非所有查询都是使用单引号和字符串构建的)
How about when dealing with numbers?
becomes
SELECT * FROM [Products] WHERE productid=322
becomes
SELECT * FROM [Products] WHERE productid=322; delete from products;--
(Not all queries are built with single quotes and strings)
由于您使用 UTF-8 作为编码,因此可能容易受到过长 UTF-8 序列的影响。撇号字符 (') 虽然通常编码为 0x27,但可以编码为超长序列 0xc0 0xa7(URL 编码:%c0%a7)。转义函数会错过这一点,但 MySQL 可能会以导致 SQL 注入的方式解释它。
正如其他人提到的,您确实需要至少使用 mysql_real_escape_string (在您的情况下很容易修复),它应该为您处理字符编码和其他问题。最好切换到使用准备好的语句。
Since you are using UTF-8 as the encoding, this could be vulnerable to an overlong UTF-8 sequence. An apostrophe character ('), while normally encoded as 0x27, could be encoded as the overlong sequence 0xc0 0xa7 (URL-encoded: %c0%a7). The escape function would miss this, but MySQL may interpret it in a way that causes a SQL injection.
As others have mentioned, you really need to be using
mysql_real_escape_string
at minimum (easy fix in your case), which should be handling character encoding and other issues for you. Preferably, switch to using prepared statements.我从来没有使用过PHP,但是,你能不使用存储过程调用而不是直接SQL语句吗?与尝试使用转义函数相比,这似乎是更好的防御 SQL 注入的方法。
然而,转义函数对于对抗恶意 JavaScript 很有用。
I've never used PHP, however, can you not use Stored Procedure calls instead of direct SQL statements? It seems like a better defense against SQL injection than trying to use an escape function.
An escape function, however, would be useful against malicious javascript.
怎么样...
应该扩展到:
因此在以下查询中使用它作为 id...
应该会导致:
how about...
Which should be expanded to:
So using it for id in the following query...
should result in: