1 实验介绍
1.1 实验目的
- 由于网页服务端对代码的过滤不够严谨,可能会存在万能用户名或万能密码绕过的风险。
- 加深对网页代码和SQL代码的理解。
1.2 实验环境
- 实验靶场——虚拟机:本节实验靶场是在win2008系统上基于phpstudy搭建的一个简单网站,win2008及phpstudy的安装过程可以参考《win2008R2SP1+WAMP环境部署》,网站的搭建过程可以参考《综合实验:一个简单丑陋的论坛网站》。
- 本实验在该论坛的登录页面进行实验。
- 该网站对登录账号密码的验证代码如下所示。
<meta charset = "utf-8">
<?php
include "../inc/dblink.inc.php";
?>
<?php
if (isset($_POST['userSubmit'])){
//var_dump($_POST);
$sql = "select * from users where name = '".$_POST['userName']."' and password ='".md5($_POST['userPass'])."'";
//echo $sql;
if ($results = mysqli_query($link,$sql)){
if (mysqli_num_rows($results) > 0){
setcookie ('name',$_POST['userName'],time()+3600,"/");
echo "登录成功,请返回<a href = '../index.php'>首页</a>或<a href = './index.php'>个人中心</a>";
}else{
echo "账号或密码错误,请<a href = './login.php'>重新输入</a>";
}
}else{
die(mysqli_error($link));
}
}else{
echo "请输入账号密码";
}
?>
<html>
<form method = "post" target = "_blank">
用户名:<input type = "text" name = "userName"><br>
密码:<input type = "password" name = "userPass"><br>
<input type="submit" name="userSubmit" value="登录">
</form>
</html>
<?php
mysqli_close($link);
?>
2 实验
2.1 实验分析
- 上述代码第8行用于在数据库中检验客户端输入账号密码是否存在,而能否登录成功关键在于第10行 if 语句判断条件是否为真,也就是说只要构造的用户名或密码能让SQL语句能成功查询并返回结果,就能实现登录。
- 由于SQL语句采用的是单引号闭合的方式,因此所构造的语句需要注意屏蔽前后的单引号,采用不同用户名及密码的组合进行实验结果如下。
用户名 | 密码 | 结果 | 分析 |
---|---|---|---|
aaa’ or 1=1# | 随意 | 成功 | 采用单引号屏蔽变量前的单引号,采用#注释掉变量后续语句 |
aaa’ or ‘1’='1 | 随意 | 失败 | 因为and的优先级比or的优先级高, 语句先执行 '1'='1' and password = '随意' 语句得到false,再执行 name = 'aaa' or false ,结果还是false,所以SQL语句无法查询到内容,登录失败. |
a’ or ‘1’='1 | 随意 | 成功 | 与上一组合不同的是,此处a是刚好碰到数据库中有该用户名, 所以or语句执行成功,适合用于爆破特定用户名 |
随意 | aaa’ or 1=1# | 失败 | 由于密码字段在代码中被MD5编码过,无法实现语句构造的功能 |
随意 | aaa’ or ‘1’=‘1’ | 失败 | 同上 |
- 当后台代码对输入参数进行过滤转换时,需要注意思考之前学过的各种绕过技巧。
2.2 实验过程
- 在登录界面输入用户名
aaa' or 1=1#
,密码随意,如下,点击登录。
- 可以看到成功登录。
- 点击个人中心,可以看到目前登录的账户是数据库中注册的第一个账号。
3 总结
- 加深理解SQL语句构造与绕过;
- 掌握万能用户名与密码检测的方法。