初学万能密码代码审计
字数 1178 2025-08-09 22:00:37
万能密码漏洞代码审计与分析
漏洞概述
本教学文档分析一个典型的SQL注入漏洞案例,通过"万能密码"绕过登录验证。该漏洞存在于一个PHP网站的登录验证逻辑中,攻击者可以通过构造特殊的SQL语句绕过密码验证直接登录系统。
环境搭建
- 使用工具:phpstudy
- 靶场部署:
- 下载靶场代码
- 放置在phpstudy的域名站点管理目录
- 设置非80端口(示例中使用3456端口)
- 访问地址:
www.a.com:3456
漏洞复现步骤
- 访问后台登录页面
- 使用Firefox插件"live HTTP headers"抓包
- 捕获的登录请求参数:
user_name=11111&user_pass=1111 - 真正的请求地址:
www.a.com:3456/checkUser.php - 使用万能密码
' or 1#作为用户名 - 成功绕过登录验证
代码审计分析
关键文件:checkUser.php
if(isset($_POST["user_name"]) && isset($_POST["user_pass"])) {
// 检测用户名和密码参数是否设置
$username = $_POST["user_name"];
$password = md5($_POST["user_pass"]);
// 构造SQL查询语句
$sql = "select * from users where user_name='$username' and user_pass='$password'";
// 执行查询
$mysql = new mysql();
$row = $mysql->getOne($sql);
if($row) {
// 登录成功逻辑
} else {
// 登录失败逻辑
}
}
漏洞成因
- 未过滤的用户输入:直接将用户输入的
user_name和user_pass拼接到SQL语句中 - 密码MD5加密:
$password = md5($password);导致在密码字段使用万能密码不可行 - SQL语句构造:拼接后的SQL语句可以被注入
万能密码原理
当使用' or 1#作为用户名时,构造的SQL语句变为:
select * from users where user_name='' or 1#' and user_pass='6512bd43d9caa6e02c990b0a82652dca'
解释:
#在MySQL中表示注释,会注释掉后面的所有内容- 实际执行的SQL:
select * from users where user_name='' or 1 or 1条件永远为真,因此会返回users表中的数据
数据库查询分析
在mysql.class.php中:
public function getOne($sql) {
$res = $this->link->query($sql);
$row = $res->fetch_assoc();
return $row;
}
fetch_assoc()只获取查询结果的第一行- 使用万能密码登录时,会返回数据库中的第一条用户记录
漏洞验证
-
成功登录时的SQL语句:
select * from users where user_name='xxxx' or 1#' and user_pass='6512bd43d9caa6e02c990b0a82652dca' -
失败登录时的SQL语句(万能密码放在密码字段):
select * from users where user_name='xxxx' and user_pass='' or 1#'由于密码经过MD5加密,这种构造方式无法成功
防御措施
-
使用预处理语句(PDO/prepared statements)
$stmt = $pdo->prepare("SELECT * FROM users WHERE user_name = ? AND user_pass = ?"); $stmt->execute([$username, $password]); -
输入验证与过滤
- 对用户输入进行严格验证
- 使用
mysqli_real_escape_string()等函数转义特殊字符
-
最小权限原则
- 数据库用户只赋予必要的最小权限
-
错误处理
- 不要将数据库错误信息直接显示给用户
-
密码处理
- 继续使用加盐哈希处理密码(示例中已使用MD5,但建议使用更安全的如bcrypt)
总结
该漏洞是典型的SQL注入漏洞,由于直接将用户输入拼接到SQL语句中且未做任何过滤导致。通过代码审计可以发现:
- 登录验证逻辑存在SQL注入点
- 密码字段由于MD5加密,注入难度较大
- 用户名字段可直接注入,使用
' or 1#可绕过验证 - 系统会返回数据库中的第一条用户记录
修复此类漏洞的关键在于使用参数化查询和严格的输入验证。