基于约束的SQL攻击

首先需要注意的是,本文所述的是基于约束的SQL攻击而非SQL注入攻击

碰到这个问题,是在做CTF题时碰到的(题目网址:http://123.206.31.85:49163/) 

基于约束的SQL攻击_第1张图片

这一道题是要求我们以管理员admin的身份登陆系统方可查看flag,方法就是在注册时注册一个admin (admin后面带一个或几个空格),然后登录系统,系统会误认为是管理员登录了系统,所以赋予管理员权限。

那么,就算我们采用PHP中的PDO以及预查寻的方式(详见简单的PDO技术以及预处理方法预防SQL注入)来处理是否能预防基于约束的SQL攻击呢?这里给出靶场的源代码,环境使用的是Windows上的phpstudy(php-5.6.27+apache)

前端代码loginPDO.php



	
		
		登录界面
	
	
		

登录

用户名称:

用户密码:

注册

用户名称:

用户密码:

注册模块代码registerPDO.php

getMessage();
	    exit;
	}
	$sql = "INSERT INTO loginPDO(userName,userPassword) VALUES (?,?)";
	//$sql = "INSERT INTO loginPDO(userName,userPassword) VALUES (:userName,:userPassword)";
	$stmt = $pdo->prepare($sql);
	$stmt->bindParam(1,$name);
	$stmt->bindParam(2,$password);
	//$stmt->bindParam(":userName",$name);		//绑定 一个 PHP 变量到预处理语句中对应的命名占位符或问号占位符
	//$stmt->bindParam(":userPassword",$password);
	$pdo->quote($name);
	$pdo->quote($password);
	$result = $stmt->execute();
		if($result){
			echo "";
			echo "

注册成功!,即将跳转至登录页面...

"; header("refresh:3; url = //localhost/loginPDO.php"); }else{ echo ""; echo "

注册失败,用户名已经注册或注册值为空...

"; } ?>

 登陆模块actionPDO.php

getMessage();
	    exit;
	}
	$sql = "SELECT * FROM loginPDO WHERE userName = :userName AND userPassword = :userPassword";
	//$sql = "SELECT * FROM login WHERE userName = ? AND userPassword = ?";
	$stmt = $con->prepare($sql);
	$stmt->bindParam(':userName',$name);    //bindParam方法与bindValue方法的区别在于bindParam的第二个参数可以传值用变量,而bindValue第二个参数只能传值用常量或字符串
	$stmt->bindParam(':userPassword',$password);
	//$stmt->bindParam('1',$name);
    //$stmt->bindParam('2',$password);
	$con->quote($name);          //quote方法是为普通的字符串添加引号
	$con->quote($password);
	$re=$stmt->execute();
	if($stmt->rowCount()!=0){
		echo "";
		echo "

欢迎您{$name}

"; }else{ echo ""; echo "

登录失败,3秒后自动跳转...

"; header("refresh:3; url = //localhost/loginPDO.php"); } ?>

靶场效果如下

基于约束的SQL攻击_第2张图片

基于约束的SQL攻击_第3张图片

根据数据库中的初始数据,账号admin,密码root可以成功登录,注册不允许有相同的用户名。

首先我尝试了在admin后面加一个空格,密码不变,提示登录成功

基于约束的SQL攻击_第4张图片

基于约束的SQL攻击_第5张图片 

       然后尝试注册一个后面带空格的admin,结果提示注册失败,注册用户已存在,并不像刚开始所期望的那样。于是我猜测是否是因为bindParam()在绑定参数的时候去掉了末尾的空格,于是开始翻阅php手册,结果并没有发现手册中有提到bindParam()会去掉参数的首尾空格

       于是换一个方式,登录时在admin前面加一个空格,密码不变,点击登录提示登陆失败

基于约束的SQL攻击_第6张图片

 基于约束的SQL攻击_第7张图片

再注册一个admin前有一个空格的用户,结果发现注册成功

基于约束的SQL攻击_第8张图片

基于约束的SQL攻击_第9张图片 

基于约束的SQL攻击_第10张图片 

       那么猜测应该是成立的,bindParam()会截断绑定参数值后面的空格,而不会截断前面的空格,也就是允许注册用户名的第一个字符为空格

 

       也就是说,在一个有严格权限区分的系统,如果得知了管理员的用户名,可以利用管理员用户名后加空格的方法注册,再登录,系统也会默认为管理员,类似CTF的这道题一样,产生基于约束的SQL攻击

 

防御方法

1、使用过滤空格的函数,$data = trim($data),去掉传入参数的首位空格,再进行数据库查询、插入等工作

2、对用户名的长度进行限制

3、验证成功后返回的必须是用户传递进来的用户名,而不是从数据库取出的用户名。因为当我们以用户admin和密码root登陆时,其实数据库返回的是我们自己的用户信息,而我们的用户名其实是[admin      ],如果此后的业务逻辑以该用户名为准,那么就不能达到越权的目的了。

4、将要求或者预期具有唯一性的那些列加上UNIQUE约束

5、使用id作为数据库表的主键并设置自动递增,并且数据应该通过程序中的id进行跟踪

你可能感兴趣的:(漏洞测试)