1. 示例代码
搭建环境:
PHP/5.6.40/Nginx/1.24.0/Mysql/5.0.11
<?php
$server="localhost";
$username="root";
$password="password";
$db_connect=mysql_connect($server,$username,$password) or die("Unable to connect to the MySQL!");
mysql_select_db('sql',$db_connect);
if(!isset($_POST['mail'])) {
die("POST submission mail.n");
}
$mail = $_POST['mail'];
$filter_chain = array(FILTER_DEFAULT, FILTER_SANITIZE_ADD_SLASHES, FILTER_VALIDATE_EMAIL, FILTER_SANITIZE_STRING);
for($i=0; $i < count($filter_chain); $i++){
if(filter_var($mail, $filter_chain[$i]) === false){
die("Invalid Email.n");
}
}
$result = mysql_query("SELECT username FROM users WHERE email='$mail' LIMIT 1");
if ($result) {
while ($row = mysql_fetch_assoc($result)) {
$username=$row['username'];
echo "My name is:" . $username . "<br>";
}
} else {
echo "没有找到匹配的用户";
}
?>
请查看上述代码,找出其中的漏洞。
2. 漏洞位置
$filter_chain = array(FILTER_DEFAULT, FILTER_SANITIZE_ADD_SLASHES, FILTER_VALIDATE_EMAIL, FILTER_SANITIZE_STRING);
for($i=0; $i < count($filter_chain); $i++){
if(filter_var($mail, $filter_chain[$i]) === false){
die("Invalid Email.n");
}
}
$result = mysql_query("SELECT username FROM users WHERE email='$mail' LIMIT 1");
3. 漏洞原理
在示例代码中,用户输入的参数被直接用于执行SQL查询操作,这种方式存在潜在的安全风险。尽管代码中使用了过滤器进行过滤,但这种方式依然不足以防止攻击者绕过过滤器,从而导致SQL注入漏洞。
由于filter_var的返回值被丢弃,因此唯一相关的过滤器是FILTER_VALIDATE_EMAIL。RFC不是非常严格,允许使用许多特殊字符。
FILTER_VALIDATE_EMAIL:基于RFC822的电子邮件验证;
4. 漏洞复现
在访问示例代码时,可以使用Burpsuite进行抓包。更改请求方式为POST,需要提交一个名为mail的参数。FILTER_VALIDATE_EMAIL过滤器不允许在邮件地址中出现空格符号,可以使用/**/来代替。模拟邮件格式@可以成功注入。
经过测试,以下payload可以成功注入:
Payload:获取表中username字段值
mail='/**/union/**/select/**/username/**/FROM/**/users/**/#'@a.s
Payload:获取表中password字段值
mail='/**/union/**/select/**/password/**/FROM/**/users/**/#'@a.s
5. 修复方案
在进行数据库操作时,需要使用PDO预处理的方式,防止SQL注入漏洞的产生。PDO预处理方式,确保用户输入的值不会被当成sql语句解析。通过使用预处理语句和参数绑定,可以有效地防止恶意用户通过注入恶意代码来篡改查询的意图。
修复示例:
$stmt = $db_connect->prepare("SELECT username FROM users WHERE email=:mail LIMIT 1");
$stmt->bindParam(':mail', $mail);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
作者:Spider-Man
2023年10月20日
洞源实验室