如何演示二阶SQL注入?

时间:2012-10-18 10:09:52

标签: php pdo sql-injection

所以我一直在尝试复制二阶SQL注入。这是我准备的两个基于php的网站的示例模板。我们只需将其称为选民登记表。用户可以注册,然后您可以检查您是否是注册选民。

insert.php

<?php

$db_selected = mysql_select_db('canada',$conn);
if (!db_selected)
    die("can't use mysql: ". mysql_error());

$sql_statement = "INSERT into canada (UserID,FirstName,LastName,Age,State,Town)
                    values ('".mysql_real_escape_string($_REQUEST["UserID"])."',
                    '".mysql_real_escape_string($_REQUEST["FirstName"])."',
                    '".mysql_real_escape_string($_REQUEST["LastName"])."',
                    ".intval($_REQUEST["Age"]).",
                    '".mysql_real_escape_string($_REQUEST["State"])."',
                    '".mysql_real_escape_string($_REQUEST["Town"])."')";

echo "You ran the sql query=".$sql_statement."<br/>";
$qry = mysql_query($sql_statement,$conn) || die (mysql_error());
mysql_close($conn);
Echo "Data inserted successfully";
}
?>

select.php

<?php


$db_selected = mysql_select_db('canada', $conn);
if(!db_selected)
    die('Can\'t use mysql:' . mysql_error());
$sql = "SELECT * FROM canada WHERE UserID='".addslashes($_POST["UserID"])."'";
echo "You ran the sql query=".$sql."<br/>";
$result = mysql_query($sql,$conn);
$row=mysql_fetch_row($result);

$sql1 = "SELECT * FROM canada WHERE FirstName = '".$row[1]."'";
echo "The web application ran the sql query internally=" .$sql1. "<br/>";
$result1 = mysql_query($sql1, $conn);
$row1 = mysql_fetch_row($result1);

mysql_close($conn);
echo "<br><b><center>Database Output</center></b><br><br>";

echo "<br>$row1[1] $row1[2] , you are a voter! <br>";

echo "<b>VoterID: $row[0]</b><br>First Name: $row[1]<br>Last Name: $row[2]
    <br>Age: $row[3]<br>Town: $row[4]<br>State: $row[5]<br><hr><br>";
}
?>

所以我特意让这个易受攻击,以显示二阶SQL注入是如何工作的,用户可以在第一个名称部分输入代码(我目前卡在那里,我尝试了很多不同的方法,但似乎我无法做任何事情)。 然后当一个人想要激活他在第一个名字部分中插入的代码时,他只需输入用户ID并插入代码。

例如: 我将在insert.php页面中输入: userid = 17

firstname =(我需要在这里注入一些东西)

lastname = ..

年龄= ..

town = ..

state = ..

然后当我检查我的详细信息并输入17时,将激活注入的SQL脚本。 我能举几个例子来说明我可以通过这种方式展示哪种漏洞?

2 个答案:

答案 0 :(得分:4)

有什么可证明的?

二阶SQL注入只不过是SQL注入,但不安全的代码不是第一行。

所以,要证明:

1)创建一个SQL注入字符串,在没有转义的情况下执行不需要的操作。

2)将该字符串安全地存储在您的数据库中(带有转义)。

3)让你的代码的另一部分FETCH成为字符串,并在其他地方使用而不转义。

编辑:添加了一些示例代码:

表格:

CREATE TABLE tblUsers (
  userId serial PRIMARY KEY,
  firstName TEXT
)

假设您有一些像这样的SAFE代码,从表单中接收名字:

$firstname = someEscapeFunction($_POST["firstname"]);

$SQL = "INSERT INTO tblUsers (firstname) VALUES ('{$firstname }');";
someConnection->execute($SQL);

到目前为止,非常好,假设someEscapeFunction()做得很好。无法注入SQL。

如果我将以下一行的名字作为值发送,你不介意:

BLA');从tblUsers删除; //

现在,假设同一系统上的某个人想要将firstName从tblUsers传输到tblWhatever,并且这样做:

$userid = 42;
$SQL = "SELECT firstname FROM tblUsers WHERE (userId={$userid})";
$RS = con->fetchAll($SQL);
$firstName = $RS[0]["firstName"];

然后将其插入tblWhatever,无需转义:

$SQL = "INSERT INTO tblWhatever (firstName) VALUES ('{$firstName}');";

现在,如果firstname包含一些delete命令,它仍将被执行。

答案 1 :(得分:4)

使用名字:

' OR 1 OR '

这将在

的第二个SQL中产生一个where子句
  

WHERE FirstName =''OR 1 OR''

因此结果将是表格中的第一条记录。

通过添加LIMIT子句,您可以使用以下内容从表中提取所有行:

  

'OR 1 ORDER BY UserID ASC LIMIT 0,1 -

显然它一次只能提取1行,所以你需要重复这一行并在LIMIT中增加0。此示例使用注释--来终止剩余的SQL,否则会导致查询失败,因为它会在LIMIT之后添加单引号。

以上是一个简单的例子,更复杂的攻击是使用UNION SELECT,它可以通过使用information_schema来访问整个数据库。

此外,您在其中一个查询中使用addslashes()。这不像mysql_real_escape_string()那样安全,反过来:使用其中任何一个转义引号都不如使用预处理语句或参数化查询那样安全,例如在PDO或MySQLi中。