堆叠注入原理
堆叠注入,顾名思义,就是将语句堆叠在一起进行查询
原理很简单,mysql_multi_query() 支持多条sql语句同时执行,就是个;分隔,成堆的执行sql语句,例如
select * from users;show databases;
就同时执行以上两条命令,所以我们可以增删改查,只要权限够
虽然这个注入姿势很牛逼,但实际遇到很少,其可能受到API或者数据库引擎,又或者权限的限制只有当调用数据库函数支持执行多条sql语句时才能够使用,利用mysqli_multi_query()函数就支持多条sql语句同时执行,但实际情况中,如PHP为了防止sql注入机制,往往使用调用数据库的函数是mysqli_ query()函数,其只能执行一条语句,分号后面的内容将不会被执行,所以可以说堆叠注入的使用条件十分有限,一旦能够被使用,将可能对网站造成十分大的威胁。
漏洞造成代码分析
sqli-labs38
if(isset($_GET['id']))
{
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// connectivity
//mysql connections for stacked query examples.
$con1 = mysqli_connect($host,$dbuser,$dbpass,$dbname);
// Check connection
if (mysqli_connect_errno($con1))
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
else
{
@mysqli_select_db($con1, $dbname) or die ( "Unable to connect to the database: $dbname");
}
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
/* execute multi query */
if (mysqli_multi_query($con1, $sql))
{
/* store first result set */
if ($result = mysqli_store_result($con1))
{
if($row = mysqli_fetch_row($result))
{
echo '<font size = "5" color= "#00FF00">';
printf("Your Username is : %s", $row[1]);
echo "<br>";
printf("Your Password is : %s", $row[2]);
echo "<br>";
echo "</font>";
}
// mysqli_free_result($result);
}
/* print divider */
if (mysqli_more_results($con1))
{
//printf("-----------------\n");
}
//while (mysqli_next_result($con1));
}
else
{
echo '<font size="5" color= "#FFFF00">';
print_r(mysqli_error($con1));
echo "</font>";
}
/* close connection */
mysqli_close($con1);
对输入的参数没有进行严格的过滤,攻击者构造恶意的攻击语句造成了SQL注入攻击,存在回显点,可以进行联合注入,并且如果出现错误,会输出报错信息,这里也可以使用显错注入。
还可以看到,这里的SQL语句查询使用的是mysqli_multi_query函数,mysqli_multi_query函数可以执行多条SQL语句。
127.0.0.1/sqli-labs/Less-38/?id=1';insert into users(id,username,password) value (77,'acca','bbc')--+
可以看到,我们堆叠查询的语句执行成功,那么我们可以在堆叠的SQL语句使用时间盲注的语句。
<?php
header("Content-Type:text/html;charset=utf8");
try{
$con=new PDO("mysql:host=localhost;dbname=security","root","root");
$con->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
$id=$_GET['id'];
$stmt=$con->query("select * from users where id='".$id."'");
$result=$stmt->setFetchMode(PDO::FETCH_ASSOC);
foreach ($stmt->fetchAll() as $k => $v) {
foreach ($v as $key => $value) {
echo $value;
}
}
$dsn=null;
}
catch(PDOException $e){
echo "error";
}
$con=null;
?>
上面这个代码,程序获取GET参数ID,使用PDO的方式进行数据查询,但仍然将参数ID拼接到查询语句,导致PDO没起到预编译的效果,程序仍然存在SQL注入漏洞。
使用PDO执行SQL语句时,可以执行多条语句,不过这样通常不能直接得到注入结果,因为PDO只会返回第一条SQL语句执行的结果,所以在第二条语句中可以用update更新数据或者使用时间盲注获取数据。
?id=1';select if(ord(substring(user(),1,1))=114,sleep(3),1);#
总结
这个注入方式并不是很常用,理解和使用也较为简单,但是利用姿势比较多样特别,要多加理解和运用。