目录
本地搭建靶站进行测试,旨在提高自己的开发能力以及对漏洞的理解。
源码:利用PHP开发具有注册、登陆、文件上传、发布动态功能的网站_MUNG东隅的博客-CSDN博客
这个靶站其实可以说是我出的第一道web题吧,里面藏了三个flag,拼接为一个完整的flag
三个flag的位置分别在:数据库中、admin用户的cookie中、网站源码文件flag.php中,分别对应sql注入漏洞、xss漏洞、文件上传漏洞,我想出第四个flag部分,对应csrf漏洞。
- login.php
-
- PHP
- error_reporting(0);
- session_start();
- if((isset($_COOKIE['isLogin']) && $_COOKIE['isLogin'] == 1)){
- session_start(); //创建session
- header("refresh:0;url=./welcome.php");//如果成功跳转至welcome.html页面
- exit;
- }
-
- header("Content-type:text/html;charset=utf-8");
- include('./conn.php');//链接数据库
- $username = $_POST['username'];//post获得用户名表单值 #addslashes()函数
- $passowrd = $_POST['password'];//post获得用户密码单值
- $_SESSION['user'] = $_POST['username'];
-
- if ($username && $passowrd){//如果用户名和密码都不为空
- $sql = "select * from flag where username = ('$username') and password='$passowrd'";//检测数据库是否有对应的username和password的sql
- $result = mysqli_query($conn,$sql);//执行sql
- $rows=mysqli_num_rows($result);//返回一个数值
- if($rows){//0 false 1 true
- session_start(); //创建session
- if(!isset($_COOKIE["username"])){
- if($username=='admin'){
- setCookie("username",$username,time()+3600);//..设置一个用户名COOKIE
- setCookie("isLogin",1,time()+3600);//..设置一个登录判断的标记isLogin
- setCookie("flag3",'s_y0uR_F14g}',time()+3600);
- }else{
- setCookie("username",$username,time()+3600);//..设置一个用户名COOKIE
- setCookie("isLogin",1,time()+3600);//..设置一个登录判断的标记isLogin
- }
- }
- header("refresh:0;url=./welcome.php");//如果成功跳转至welcome.html页面
- exit;
- }else{
- echo mysqli_error($conn);
- //echo "";
-
- }
- }
-
-
- mysqli_close($conn);//关闭数据库
- ?>
- register.php
-
- session_start();
- header("Content-type:text/html;charset=utf-8");
- include('./conn.php');//链接数据库
-
- $username = addslashes($_POST['username']);
- $password = $_POST['password'];
-
- if($username&&$password)
- {
- mysqli_query($conn,"insert into flag(id,username,password,pic) values(null,('$username'),'$password','./headpic/headpic.png');");
- echo "注册成功,即将跳转至登录页面";
- header("refresh:1.5;url=./index.html");
- exit;
- }
-
- mysqli_close($conn);
- ?>
先进行正常的注册操作
登录,观察
登录进去以后显示用户名,存在默认头像,具有5个功能模块,存在cookie
首先我们看到登录页面
尝试万能密码登录,登陆成功
这个登录过程是没有回显的,我们来看其他的注入方式
报错注入:
是可行的
-1') and updatexml(1,concat(0x7e,(select database()),0x7e),1)-- -
-1') and updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema=database()),0x7e),1)-- -
解决方式:
限制username长度
关闭报错回显
有回显的原因就是这句话:
echo mysqli_error($conn);
当在数据库中查不到相应的用户名密码的时候,会返回mysql的错误,返回这类错误在开发的时候或许是方便我们进行测试的,但是项目上线以后要尽量在这种模块不进行回显
更改:
直接返回错误信息,并进行跳转
echo "";
特殊符号转义
时间注入:
这个测试了很久都没发现时间注入,百思不得其解,最后把sql语句里面的username改成id,发现可行了
测试语句:
1') and if(1=2,1,sleep(5))-- -
后面发现username的话前面的1应该变成字符串
admin')and If(ascii(substr(database(),0,1))='s',sleep(5),1)-- -
解决方式:
ban掉sleep(),benchmark()等
堆叠注入:
这玩意只有在PDO预编译中才能出现,使用PDO执行SQL语句可以执行多条,但是如果使用不当就会让堆叠注入成为可能,比如仍然将参数拼接到查询语句
宽字节注入:
$conn->query('set names gbk');
- 1%df' or 1=1%23
- 1%df' or 1=2%23
如果参数使用addslashes()进行转义,并且编码为GBK就会出现,测试了非常非常久,一直复现不出这个漏洞,不搞了,也就那么回事
另外记录一种登陆方式:
payload:
- 1' union select 1,2,3,4-- -
- 3
PDO预编译
由于SQL注入是因为参数改变了SQL语句的原有结构导致的,因此通过绑定参数可以达到参数是参数,结构是结构,从而避免结构被改变的情况。
当调用 prepare() 时,查询语句已经发送给了数据库服务器,此时只有占位符 ? 发送过去,没有用户提交的数据;当调用到 execute()时,用户提交过来的值才会传送给数据库,他们是分开传送的,两者独立的,SQL攻击者没有一点机会。
需要注意的是,不要将变量直接拼接到PDO语句中,而是使用占位符进行数据库的增删改查。
pdo连接数据库
- header("Content-Type:text/html;charset=utf-8"); //设置页面编码格式
- $dbms='mysql'; //数据库类型
- $dbName='sqlinject'; //数据库名称
- $user='root'; //数据库用户名
- $pwd=''; //数据库密码
- $host='localhost'; //主机名称
- $dsn="$dbms:host=$host;dbname=$dbName"; //数据源名称
- try{ //捕获异常
- $pdo=new PDO($dsn,$user,$pwd); //实例化对象
- echo "PDO连接MySQL成功";
- }catch(Exception $e){
- echo $e->getMessage()."
"; - }
- ?>
编码不要设置为gbk
ban掉一些关键字
不允许空格
addslashes()函数进行转义
md5()加密存储
- if(strlen($username)>6){
- die();
- }
upload.php
- session_start();
- header("Content-Type:text/html;charset=utf-8");
- include('./conn.php');
- // 附件的存储位置、附件的名字
-
- $path='./headpic/'.$_FILES['file']['name'];
- echo '文件路径'.$path."
"; - $username = $_SESSION['user'];
- // 拼接成该文件在服务器上的名称
-
- if($_FILES['file']['error']>0) {
- die("出错了!".$_FILES['file']['error']);
- }
- if(move_uploaded_file($_FILES['file']['tmp_name'],$path)){
- //echo "
"."Upload Success!"; -
- mysqli_query($conn,"update flag set pic='$path' where username='$username';");
- echo "恭喜您,上传成功!"."
3秒后将自动跳转到主页!"; - header("refresh:3;url=./welcome.php");
- }else{
- //echo "
"."Upload Failed!".$_FILES['photo']['error']; - echo "对不起,上传头像失败了!";
- header("refresh:2;url=./welcome.php");
- }
- ?>
直接上传脚本文件,发现存在前端验证,这是很好绕过的,抓包改包就好了
返回了上传文件的路径
图片马?
00截断?
upload-labs pass12
设置上传文件目录权限不能给执行权限
前端、后端验证(白名单)
二次渲染
对上传后的文件进行重命名
不要暴露上传文件的位置
禁用上传文件的执行权限
黑白名单
对上传的文件重命名,不易被猜测
对文件内容进行二次渲染
对上传的内容进行读取检查
- session_start();
- header("Content-Type:text/html;charset=utf-8");
- include('./conn.php');
- // 附件的存储位置、附件的名字
-
- $path='./headpic/'.$_FILES['file']['name'];
-
- // $ext=explode('.',$_FILES['file']['name']); //划分数组
- // $ext=end($ext);
- // $path='./headpic/'.time().'.'.$ext;
-
-
- $username = $_SESSION['user'];
- // 拼接成该文件在服务器上的名称
-
- //deldot()函数
- // function deldot($s){
- // for($i = strlen($s)-1;$i>0;$i--){
- // $c = substr($s,$i,1);
- // if($i == strlen($s)-1 and $c != '.'){
- // return $s;
- // }
-
- // if($c != '.'){
- // return substr($s,0,$i+1);
- // }
- // }
- // }
-
- if($_FILES['file']['error']>0) {
- die("出错了!".$_FILES['file']['error']);
- }
- // if (($_FILES['file']['type'] == 'image/jpeg') || ($_FILES['file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif'))
- // {
- // $deny_ext = array(".png",".jpg",".gif",".jpeg"); //白名单
- // $file_name = trim($_FILES['file']['name']); //收尾去空
- // $file_name = deldot($file_name); //删除文件名末尾的点
- // $file_ext = strrchr($file_name, '.'); //返回字符串中.后面的部分,也就是后缀名
- // $file_ext = strtolower($file_ext); //转换为小写
- // $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
- // $file_ext = trim($file_ext); //收尾去空
-
- // $path='./headpic/'.time().$file_ext;
- echo '文件路径'.$path."
"; - // if (in_array($file_ext, $deny_ext)) {
- if(move_uploaded_file($_FILES['file']['tmp_name'],$path)){ //上传成功会返回Ture
- //echo "
"."Upload Success!"; -
- mysqli_query($conn,"update flag set pic='$path' where username='$username';");
- echo "恭喜您,上传成功!"."
3秒后将自动跳转到主页!"; - header("refresh:3;url=./welcome.php");
- }else{
- //echo "
"."Upload Failed!".$_FILES['photo']['error']; - echo "对不起,上传头像失败了!";
- header("refresh:2;url=./welcome.php");
- }
- // }else{
- // echo "WAF!"."您上传的文件类型为".$file_ext."不允许上传"."
"; - // header("refresh:3;url=./headpic.html");
- // }
-
- // }
- ?>
-
-
-
- session_start();
- header("Content-type:text/html;charset=utf-8");
- $username=$_SESSION['user'];
- $dbtable=substr($username,0,8).'blog';
-
- include('./blogconn.php');//链接数据库
- include('./allblogconn.php');//链接数据库
-
- $sql22="create table $dbtable(id int auto_increment primary key, blog varchar(300) not null);";
- $result=mysqli_query($conn2,$sql22);
- $conn2->query($sql22);
-
- $blog=$_POST['blog'];
- if(isset($blog)){
- $blogsql="insert into $dbtable(id,blog) values(null,'$blog');";
-
-
-
-
- $result=mysqli_query($conn2,$blogsql);
-
- $allblogsql="insert into allblog(id,username,blog) values(null,'$username','$blog');";
- $result10=mysqli_query($conn10,$allblogsql);
- }
-
-
- mysqli_close($conn);//关闭数据库
- ?>
-
xss.html
- html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Documenttitle>
- head>
- <body>
- <script type="text/javascript">location="https://www.bilibili.com/"script>
- body>
- html>
httponly
对输入数据进行处理
对输出数据进行转义
$blog=htmlspecialchars($blog);