什么是二阶注入?
简单的来说,就是第一次注入时,开发者进行了编码等限制,无法直接进行注入,但是在数据库中保留了我们注入的语句,程序在其它地方再次调用保存着我们注入的语句时发生了注入,这就是二阶注入,有点类似存储型XSS漏洞的意思。
二阶注入演示
实验环境介绍
text数据库里有张users表,目前里面已有admin和root账户
用户注册页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>用户注册</title>
</head>
<?php
function check($str){
$str1=str_replace("'","''",$str);
$str1=str_replace('"','""',$str1);
return $str1;
}
if(isset($_POST['submit'])){
$username=check($_POST['username']);
$passwd=check($_POST['passwd']);
$email=check($_POST['email']);
$mysqli=new mysqli();
$mysqli->connect('localhost','root','root');
if($mysqli->connect_errno){
die('数据库连接失败:'.$mysqli->connect_error);
}
$mysqli->select_db('text');
if($mysqli->errno){
die('打开数据库失败:'.$mysqli->error);
}
$mysqli->set_charset('utf-8');
$sql="SELECT * FROM users WHERE username='{$username}'";
$sl=$mysqli->query($sql);
if(!$sl){
die('SQL语句执行错误:'.$mysqli->error);
}else if($sl->num_rows>0){
$sl->free();
$mysqli->close();
die('该用户已被注册,请使用其它账户');
}else {
$sql="INSERT INTO users VALUES(NULL,'{$username}',md5('{$passwd}'),'{$email}')";
echo 'SQL执行语句'.$sql.'<hr />';
$sl=$mysqli->query($sql);
if(!$sl){
die('SQL语句执行错误:'.$mysqli->error);
}else {
die("恭喜你注册{$username}成功!");
}
}
$sl->free();
$mysqli->close();
}
?>
<body>
<h1>用户注册</h1>
<form action="" method="post">
用户名:<input type="text" name="username"><br />
密码:<input type="password" name="passwd"><br />
邮箱:<input type="text" name="email"><br />
<input type="submit" name="submit" value="注册">
</form>
</body>
</html>
用户密码修改页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>修改用户密码</title>
</head>
<?php
if(isset($_POST['submit'])){
$username=$_POST['username'];
$passwd=$_POST['passwd'];
$newpasswd=$_POST['newpasswd'];
$mysqli=new mysqli();
$mysqli->connect('localhost','root','root');
if($mysqli->connect_errno){
die('数据库连接失败:'.$mysqli->connect_error);
}
$mysqli->select_db('text');
if($mysqli->errno){
die('打开数据库失败:'.$mysqli->error);
}
$mysqli->set_charset('utf-8');
$sql="SELECT * FROM users WHERE username='{$username}' AND passwd=md5('{$passwd}')";
$sl=$mysqli->query($sql);
if(!$sl){
die('SQL语句执行错误:'.$mysqli->error);
}else if($sl->num_rows==0){
$sl->free();
$mysqli->close();
die('修改密码失败,用户或原密码错误');
}else {
$sql="UPDATE users SET passwd=md5('{$newpasswd}') WHERE username='{$username}'";
$sl=$mysqli->query($sql);
if(!$sl){
die('SQL语句执行错误:'.$mysqli->error);
}else{
die('修改密码成功!');
}
}
$sl->free();
$mysqli->close();
}
?>
<body>
<h1>用户密码修改</h1>
<form action="" method="post">
用户名:<input type="text" name="username"><br />
原密码:<input type="password" name="passwd"><br />
新密码:<input type="password" name="newpasswd"><br />
<input type="submit" name="submit" value="修改">
</form>
</body>
</html>
二阶注入演示
首先用户注册页面,对用户提交的数据进行了check()函数过滤,对单引号和双引号进行了闭合,故无法闭合SQL语句。
如:id=1' => id=1''
这里很明显,无法直接一阶注入,但用户修改密码页面对这个表中的数据没有过滤或限制就调用了(开发人员相信数据库中数据),那么此时就存在二阶注入。
首先注册一个用户名为:admin'#的用户,经过check函数就变成了admin''#,此时就无法直接注入。
在数据库中,已插入一个用户名为admin'#的用户
然后在用户修改密码界面中,输入admin'#用户和相应的密码
此时,修改密码的SQL为:
UPDATE users SET passwd=md5('123123') WHERE username='admin'#';
=
UPDATE users SET passwd=md5('123123') WHERE username='admin';
此时,查看数据中记录,发现是admin用户的密码被修改了。