最近了解到二次注入,因而参考强网杯的"three hit",本地搭建了二次注入的环境来复现理解二次注入的造成php
搭建一个web环境,功能有注册、登陆、登陆后显示同年龄的人html
如下给出源码,因为只是为了达到复现二次注入产生的效果来理解二次注入,故在功能和界面上代码写得比较粗糙,望见谅mysql
conn.php源码:web
1 <?php 2 $con = mysqli_connect('localhost','root','root','test'); 3 if(!$con){ 4 die('Cound not connect:'.mysqli_connect_error()); 5 } 6 ?>
register.php源码:sql
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>注册</title> 5 <meta charset="utf-8"> 6 </head> 7 <body> 8 <h2 align="center">注册</h2> 9 <form action="" method="POST"> 10 用户名: <input type="text" name="name"><br> 11 年龄: <input type="text" name="age"><br> 12 密码: <input type="text" name="pwd"><br> 13 <input type="submit" name="submit" value="提交"> 14 </form> 15 <?php 16 require('conn.php'); 17 if(isset($_POST['submit'])){ 18 $user = addslashes(@$_POST['name']); //addslashes过滤掉单引号等防注入 19 $age = addslashes(@$_POST['age']); 20 $pwd = addslashes(@$_POST['pwd']); 21 $sql = "INSERT INTO user(name,pwd,age) VALUES('".$user."','".$pwd."','".$age."')"; 22 if($res = mysqli_query($con,$sql)){ 23 echo "注册成功<br>用户名:$user<br>年龄:$age<br><a href='login.php'>去登陆</a>"; 24 }else{ 25 echo "注册失败"; 26 } 27 } 28 ?> 29 </body> 30 </html>
login.php源码:数据库
1 <?php 2 session_start(); 3 ?> 4 5 <!DOCTYPE html> 6 <html> 7 <head> 8 <title>登陆</title> 9 <meta charset="utf-8"> 10 </head> 11 <body> 12 <h2 align="center">登陆</h2> 13 <form action="" method="POST"> 14 用户名: <input type="text" name="name"><br> 15 密码: <input type="text" name="pwd"><br> 16 <input type="submit" name="submit" value="登陆"> 17 </form> 18 <h2>已注册用户:</h2><hr> 19 <?php 20 require("conn.php"); 21 $sql = "SELECT * FROM user"; 22 // 列出已注册用户 23 if($res = mysqli_query($con,$sql)){ 24 while($row = mysqli_fetch_assoc($res)){ 25 echo "用户名:".$row['name']."<br>年龄:".$row['age']."<br>"; 26 } 27 } 28 ?> 29 <hr> 30 <?php 31 if(isset($_POST['submit'])){ 32 $name = @$_POST['name']; 33 $pwd = @$_POST['pwd']; 34 $sql = "SELECT * FROM user WHERE name='".$name."' and pwd='".$pwd."'"; 35 // 登陆 36 if($res = mysqli_query($con,$sql)){ 37 if(mysqli_num_rows($res)>0){ 38 $_SESSION['user'] = $name; 39 header("Refresh:0;url=index.php"); 40 }else{ 41 echo '登陆失败'; 42 } 43 } 44 } 45 ?> 46 </body> 47 </html>
index.php源码:服务器
1 <?php 2 session_start(); 3 if(!isset($_SESSION['user'])){ 4 header("Refresh:0;url=login.php"); 5 } 6 ?> 7 <!DOCTYPE html> 8 <html> 9 <head> 10 <title>首页</title> 11 <meta charset="utf-8"> 12 </head> 13 <body> 14 <?php 15 require('conn.php'); 16 //显示当前用户信息 17 $sql = "SELECT * FROM user WHERE name='".@$_SESSION['user']."'"; 18 if($res = mysqli_query($con,$sql)){ 19 while($row = mysqli_fetch_assoc($res)){ 20 $current_name = $row['name']; 21 $current_age = $row['age']; 22 echo '当前用户:'.$current_name.'<br>年龄:'.$current_age; 23 } 24 } 25 echo "<br><br>"; 26 //显示同龄用户 27 $sql = "SELECT * FROM user WHERE age='".$current_age."' LIMIT 1";// $current_age从数据库取出未通过滤直接拼接SQL语句,从而产生二次注入 28 if($res = mysqli_query($con,$sql)){ 29 while($row = mysqli_fetch_assoc($res)){ 30 echo '与'.$current_name.'<br>同年龄为'.$current_age.'的有<br>'.$row['name']."<br>"; 31 } 32 } 33 34 echo "<br><br><a href='register.php'>去注册</a>" 35 ?> 36 </body> 37 </html>
先注册一个用户test1,年龄为1session
登陆后,能够看到正常的效果fetch
接下来,注册一个用户user1,年龄为1' and 1=2 #ui
这里能够看到,单引号前是被加了\的,产生不了注入
接着在login.php能够看到,从数据库取出的年龄是有单引号而且最后有个#注释符的,是被污染的危险数据
登陆以后,能够看到,本来该显示同年龄的人的地方并无显示,说明报错了,and 1=2被拼接进了SQL语句
接下来就是常规的SQL注入了
接着注册年龄为【1' order by 1 #】...【1' order by 4#】、【1' union select 1,2,3#】、【1' union select user(),2,3#】...
【1' order by 1#】
【1' order by 4#】
【1' union select 1,2,3#】
【1' union select user(),2,3#】
二次注入能够理解为先将恶意数据插入到数据库,以后服务器从数据库取出恶意数据,未通过滤就直接拼接SQL语句进行查询而致使的漏洞
由于精心构造的恶意数据在中间折转了一次,故名为二次注入