less-24
对于一个像我一样的小白来说这关就像php代码审计
一开始进行判断注入点的时候怎么都找不到一点思路都没有
只能搜教程 说是二次注入 从来没遇见的题型 于是从代码审计开始
先说一下什么叫二次注入
二次注入
二次注入是指通过SQL语句存储到数据库的用户输入被读取后再次被SQL语句执行导致的注入。原理
在第一次进行数据库插入数据的时候,仅仅只是使用了个别函数对其中的特殊字符进行了转义,在后端代码中可能被转义,但在存入数据库时还是原来的数据,数据中一般带有单引号和#号,然后下次使用拼凑SQL语句中,所以就形成了二次注入。
代码分析
login.php
<?PHP session_start(); //当调用 session_start() 函数时,PHP 会检查当前请求中是否存在会话标识符(通常是通过 cookie 或 URL 参数传递的), //如果存在会话标识符,则会恢复之前的会话数据;如果不存在会话标识符,则会创建一个新的会话,并生成一个唯一的会话标识符。 include("../sql-connections/sql-connect.php");//连接数据库 function sqllogin(){ $username = mysql_real_escape_string($_POST["login_user"]); //获取登录的账号 并且使用函数将内容中的单引号双引号进行转义 让他变成字符串 $password = mysql_real_escape_string($_POST["login_password"]);//和上面的同理 $sql = "SELECT * FROM users WHERE username='$username' and password='$password'"; //把转义后的用户和密码带入到数据库中进行查找 $res = mysql_query($sql) or die('You tried to be real smart, Try harder!!!! :( ');//执行 如果失败返回提示信息 $row = mysql_fetch_row($res); // if ($row[1]) { //$row[1]也就是username的位置 看看是否有值 return $row[1]; } else { return 0; } } $login = sqllogin();//将函数返回值给login参数 if (!$login== 0) //如果username位置有值 { $_SESSION["username"] = $login;//给会话赋值 setcookie("Auth", 1, time()+3600); /* expire in 15 Minutes */ header('Location: logged-in.php');//转到另一个logged-in.php } else { ?> <img src="../images/slap1.jpg"> <?PHP } ?>
Logged-in.php
<?PHP session_start(); if (!isset($_COOKIE["Auth"]))//如果cookie的auth的值不存在进入语句块 { if (!isset($_SESSION["username"])) //回话的username不存在进入语句块 { header('Location: index.php');//跳转到首页 也就是登录界面 } header('Location: index.php');//同理 我感觉这两个跳转 在这个位置放一个就行 } ?> //如果会话存在往下走 也就是cookie <img src="../images/Logged-in.jpg"></br><font size="4" color="#FFFF00"></br></br> YOU ARE LOGGED IN AS </br> <?php echo $_SESSION["username"];//输出session中的username的值 ?> You can Change your password here. //如果修改密码跳转页面到passs_change.php页面 <form name="mylogin" method="POST" action="pass_change.php"> <strong>Current Password:</strong></font> <strong>New Password:</strong> <strong>Retype Password:</strong>
pass_change.php
<?PHP session_start(); if (!isset($_COOKIE["Auth"])) { if (!isset($_SESSION["username"])) { header('Location: index.php'); } header('Location: index.php'); } //以上同理查看是否存在cookie和session ?> <?php include("../sql-connections/sql-connect.php"); if (isset($_POST['submit'])) { $username= $_SESSION["username"];//获取session中的username $curr_pass= mysql_real_escape_string($_POST['current_password']);//同理去除非法字符 $pass= mysql_real_escape_string($_POST['password']);//同理 $re_pass= mysql_real_escape_string($_POST['re_password']);//同理 if($pass==$re_pass)//如果更改密码和确定更改密码输入的值一样 执行语句块 { $sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";//以用户名和密码为条件进行更改密码 $res = mysql_query($sql) or die('You tried to be smart, Try harder!!!! :( '); $row = mysql_affected_rows();//获取sql操作了数据库的几行数据 if($row==1)//如果一行 也就是正常的情况 { echo "Password successfully updated";//输出更改成功 } else//如果修改密码失败 跳转到failed.php页面 { header('Location: failed.php'); } } else//两次输出的修改密码不一样 跳转到首页面 { echo "Make sure New Password and Retype Password fields have same value"; header('refresh:2, url=index.php'); } } ?> <?php if(isset($_POST['submit1']))//删除cookie也就是退出登录 { session_destroy();//销毁当前会话的所有数据 setcookie('Auth', 1 , time()-3600);//清除cookie的有效时限 也就是清除cookie header ('Location: index.php');//跳转到登录界面 } ?>
failed.php
<?PHP session_start(); if (!isset($_COOKIE["Auth"])) { if (!isset($_SESSION["username"])) { header('Location: index.php'); } header('Location: index.php'); } //以上同理查看是否存在cookie和会话 //下面特别有意思 这个页面是因为输入的原始密码不对 所以给你个提示 滚开你个愚蠢的黑客 ?> <html> <head> </head> <body bgcolor="#000000"> <div align="right"> <a style="font-size:.8em;color:#FFFF00" href='index.php'><img src="../images/Home.png" height='45'; width='45'></br>HOME</a> </div> </div> <div style=" margin-top:150px;color:#FFF; font-size:24px; text-align:center"> <center> <img src="../images/slap1.jpg"> </center> </div> </body> </html>
new_user.php
<?php include '../sql-connections/sql-connect.php' ; ?> //创建新用户的页面 把参数传给login_create.php <a style="font-size:.8em;color:#FFFF00" href='index.php'><img src="../images/Home.png" height='45'; width='45'></br>HOME</a> <form name="mylogin" method="POST" action="login_create.php"> <h2 style="text-align:center;background-image:url('../images/Less-24-new-user.jpg');background-repeat:no-repeat;background-position:center center"> <div style="padding-top:300px;text-align:center;color:#FFFF00;"><?php echo $form_title_ns; ?></div> </h2> </html>
login_create.php
<?PHP session_start();//同理 ?> <?php include("../sql-connections/sql-connect.php"); if (isset($_POST['submit']))//判断是否存在submit也就是提交的参数 如果有进入语句块 { $username= mysql_escape_string($_POST['username']) ;//同理 对非法字符转义 $pass= mysql_escape_string($_POST['password']); //同理 $re_pass= mysql_escape_string($_POST['re_password']);//同理 $sql = "select count(*) from users where username='$username'"; //判断当前用户是否存在 $res = mysql_query($sql) or die('You tried to be smart, Try harder!!!! :( '); $row = mysql_fetch_row($res);//获取一行数据 if (!$row[0]== 0) //如果当前用户存在 { ?> <script>alert("The username Already exists, Please choose a different username ")</script>;//用户名已经存在请换一个用户名 <?php header('refresh:1, url=new_user.php');//跳转到创建用户的页面 } else //用户名不存在 { if ($pass==$re_pass)//两次密码输入的是否一致 一致执行代码块 { $sql = "insert into users ( username, password) values(\"$username\", \"$pass\")";//将数据插入数据库中 mysql_query($sql) or die('Error Creating your user account, : '.mysql_error());//执行sql语句如果报错提醒你 echo "<center><img src=../images/Less-24-user-created.jpg><font size='3' color='#FFFF00'>"; echo "</br>Redirecting you to login page in 5 sec................"; echo "</br>If it does not redirect, click the home button on top right</center>"; header('refresh:5, url=index.php'); } else// 不一致 提醒你重新输入 { ?> <script>alert('Please make sure that password field and retype password match correctly')</script> <?php header('refresh:1, url=new_user.php'); } } } ?>
代码其实不难理解
第一步
盲猜里面有一个admin的用户
新建一个admin'#的用户
走的login_create.php的文件
这个文件对所有的输入的非法字符转义(输入数据中的单引号注释符等)转成字符串
然后使用select count(*) from users where username='admin'#' 判断admin'#用户是否存在
不存在 使用 insert into users ( username, password) values(\"$username\", \"$pass\") 插入到数据库中(这个双引号加反斜杠就是确定双引号里面的是字符串 记住就行)
然后使用刚刚注册的进行登录
SELECT * FROM users WHERE username='$username' and password='$password'"; //把转义后的用户和密码带入到数据库中进行查找 查到后输出用户名 到这里都是没有问题的
先查看一下上帝视角users表里面的内容 原始admin账户密码是123456 刚刚我们注册时密码是 qwe
登录新建用户admin'#后我们进行更改密码为asd
服务器执行的代码是
UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'
这个时候就出现问题了 admin'#进入数据库的时候单引号和#号被当成了字符 但是从$username提取出来的admin'# 单引号和#号又被当成了特殊字符
于是语句就变成了
UPDATE users SET PASSWORD='asd' where username='admin'#' and password='$curr_pass'
标记红的是被注释掉了 这样就造成了无admin密码的情况下 就可以修改admin密码
这样就成功的无视原始用户密码的条件进行修改密码 前提你知道里面的用户是谁
其实这都不重要 重要的是我们发现了这个二次注入的注入点 和注入方式
有了这个我估计可以实施进一步注入 构造新的语句作为用户名
我看所有教程都是教更改密码的 没有进行下一步的注入
有可能是太难了 没人愿意演示
也有可能是不存在下一步注入
下一步注入也是我估计的 我先不进行下一步注入 如果以后碰到类似的题 我再回来做