告诉我这个存储过程的注入攻击

时间:2013-07-31 03:30:52

标签: mysql sql-injection

我注意到很多人都说可以创建注入攻击,但我的理解是,如果有人从字符串创建查询,而不是参数。为了测试存储过程不能保护您免受注入攻击的声明,我举起这个例子,希望有人可以告诉我一个漏洞(如果有的话)。

请注意,我已经以这种方式构建了代码,以便轻松插入调用过程并将其嵌入SELECT查询的函数。这意味着我无法创建预备声明。理想情况下,我希望以这种方式保持我的设置,因为它是动态和快速的,但如果有人可以创建一个有效的注入攻击,显然这不会发生。

DELIMITER $$

#This procedure searches for an object by a unique name in the table.
#If it is not found, it inserts. Either way, the ID of the object
#is returned.

CREATE PROCEDURE `id_insert_or_find` (in _value char(200), out _id bigint(20))
BEGIN
    SET @_value = _value;
    SET @id = NULL;
    SELECT id INTO _id FROM `table` WHERE name=_value;

    IF _id IS NULL THEN
        BEGIN
            INSERT INTO `table` (`name`) VALUE (_value);
            SELECT LAST_INSERT_ID() INTO _id;
        END;
    END IF;
END$$

CREATE FUNCTION `get_id` (_object_name char(200)) RETURNS INT DETERMINISTIC
BEGIN
    SET @id = NULL;
    call `id_insert_or_find`(_object_name,@id);

    return @id;
END$$

PHP代码

我在这里使用的PHP代码是:

注意,Boann在下面指出了这段代码的愚蠢。我不是为了纪念答案而编辑它,但它肯定不是代码中的直接查询。它将是更新使用 - >准备等。如果发现新的漏洞,我仍然欢迎任何其他评论。

function add_relationship($table_name,$table_name_child) {
    #This table updates a separate table which has 
    #parent/child relationships listed.
    $db->query("INSERT INTO table_relationships (`table_id`,`tableChild_id`) VALUES (get_id('{$table_name}'),get_id('{$table_name_child}')");
}

最终结果是

table `table`
id      name
1       oak
2       mahogany

现在,如果我想让橡木成为桃花心木的孩子,我可以使用

add_relationship("mahogany","oak");

如果我想塑造橡树的孩子,我可以使用

add_relationship("oak","plastic");

希望这有助于提供一些框架和背景。

2 个答案:

答案 0 :(得分:4)

存储过程不一定是不安全的,而是您调用它的方式。

例如,如果您执行以下操作:

mysqli_multi_query("CALL id_insert_or_find(" + $value + ", " + $id + ")");
然后攻击者会设置$value="'attack'" and id="1); DROP SCHEMA YOUR_DB; --"

然后结果将是

mysqli_multi_query("CALL id_insert_or_find('attack', 1); DROP SCHEMA YOUR_DB; --)");

BOOM DEAD

答案 1 :(得分:3)

严格地说,应该编写该查询以转义表名:

$db->query("INSERT INTO table_relationships (`table_id`,`tableChild_id`) " .
    "VALUES (get_id(" . $db->quote($table_name) + ")," .
    "get_id(" . $db->quote($table_name_child) . "))");

否则,如果其中一个参数包含单引号,它将突破引号。如果您只在代码中使用文字字符串调用该函数(例如,add_relationship("mahogany", "oak");),那么不要逃避它是安全的。如果您可能使用来自$ _GET / $ _ POST / $ _ COOKIE或其他数据库字段或文件等的数据来调用add_relationship,则会遇到麻烦。我当然不会让它通过代码审查。

如果用户可以控制提供给该功能的表名,那么他们可以这样做,例如:

add_relationship("oak", "'+(SELECT CONCAT_WS(',', password_hash, password_salt) FROM users WHERE username='admin')+'");

现在您可能会说,如果生成的表名不存在,那么就没有实际的方法可以提取该信息,但即使这样,您仍然可以使用二进制文件一次提取一个二进制位的信息只需打破查询即可搜索和单独查询。像这样的东西(确切的语法没有测试):

add_relationship("oak", "plastic'+(IF(ORD(SUBSTR(SELECT password_hash FROM users WHERE username='admin'),1,1)>=128, 'foo', ''))+'");

真的,只是逃避参数更容易,然后你不必担心。