• 本地搭建靶站进行漏洞复现和防御(SQL注入、文件上传、XSS漏洞的多种形式)


    目录

    注册登录模块

    源码

    测试

    源码加固

    文件上传模块

    源码

    测试

    源码加固

    发布动态模块

    源码

    测试

    源码加固


    本地搭建靶站进行测试,旨在提高自己的开发能力以及对漏洞的理解。

    源码:利用PHP开发具有注册、登陆、文件上传、发布动态功能的网站_MUNG东隅的博客-CSDN博客

    这个靶站其实可以说是我出的第一道web题吧,里面藏了三个flag,拼接为一个完整的flag

    三个flag的位置分别在:数据库中、admin用户的cookie中、网站源码文件flag.php中,分别对应sql注入漏洞、xss漏洞、文件上传漏洞,我想出第四个flag部分,对应csrf漏洞。

    注册登录模块

    源码

    1. login.php
    2. PHP
    3. error_reporting(0);
    4. session_start();
    5. if((isset($_COOKIE['isLogin']) && $_COOKIE['isLogin'] == 1)){
    6.   session_start(); //创建session
    7.   header("refresh:0;url=./welcome.php");//如果成功跳转至welcome.html页面
    8.   exit;
    9. }        
    10. header("Content-type:text/html;charset=utf-8");
    11.    include('./conn.php');//链接数据库
    12.    $username = $_POST['username'];//post获得用户名表单值   #addslashes()函数
    13.    $passowrd = $_POST['password'];//post获得用户密码单值
    14.    $_SESSION['user'] = $_POST['username'];
    15.    if ($username && $passowrd){//如果用户名和密码都不为空
    16.             $sql = "select * from flag where username = ('$username') and password='$passowrd'";//检测数据库是否有对应的username和password的sql
    17.             $result = mysqli_query($conn,$sql);//执行sql
    18.             $rows=mysqli_num_rows($result);//返回一个数值
    19.             if($rows){//0 false 1 true
    20.                session_start(); //创建session
    21.                if(!isset($_COOKIE["username"])){
    22.                  if($username=='admin'){
    23.                      setCookie("username",$username,time()+3600);//..设置一个用户名COOKIE
    24.                      setCookie("isLogin",1,time()+3600);//..设置一个登录判断的标记isLogin
    25.                      setCookie("flag3",'s_y0uR_F14g}',time()+3600);
    26.                 }else{
    27.                  setCookie("username",$username,time()+3600);//..设置一个用户名COOKIE
    28.                  setCookie("isLogin",1,time()+3600);//..设置一个登录判断的标记isLogin
    29.               }
    30.               }
    31.                   header("refresh:0;url=./welcome.php");//如果成功跳转至welcome.html页面
    32.                   exit;
    33.             }else{
    34.               echo mysqli_error($conn);
    35.                //echo "";
    36.                
    37.             }
    38.   }
    39.    
    40.    mysqli_close($conn);//关闭数据库
    41. ?>
    42. register.php
    43. session_start();
    44. header("Content-type:text/html;charset=utf-8");
    45. include('./conn.php');//链接数据库
    46. $username = addslashes($_POST['username']);
    47. $password = $_POST['password'];
    48. if($username&&$password)
    49. {
    50.    mysqli_query($conn,"insert into flag(id,username,password,pic) values(null,('$username'),'$password','./headpic/headpic.png');");
    51.    echo "注册成功,即将跳转至登录页面";
    52.    header("refresh:1.5;url=./index.html");
    53.    exit;
    54. }
    55. mysqli_close($conn);
    56. ?>

    测试

    先进行正常的注册操作

     

    登录,观察

    登录进去以后显示用户名,存在默认头像,具有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. 1%df' or 1=1%23
    2. 1%df' or 1=2%23

    如果参数使用addslashes()进行转义,并且编码为GBK就会出现,测试了非常非常久,一直复现不出这个漏洞,不搞了,也就那么回事

     

    另外记录一种登陆方式:

    payload:

    1. 1' union select 1,2,3,4-- -
    2. 3

     

     

    源码加固

    • PDO预编译

      由于SQL注入是因为参数改变了SQL语句的原有结构导致的,因此通过绑定参数可以达到参数是参数,结构是结构,从而避免结构被改变的情况。

      当调用 prepare() 时,查询语句已经发送给了数据库服务器,此时只有占位符 ? 发送过去,没有用户提交的数据;当调用到 execute()时,用户提交过来的值才会传送给数据库,他们是分开传送的,两者独立的,SQL攻击者没有一点机会

      需要注意的是,不要将变量直接拼接到PDO语句中,而是使用占位符进行数据库的增删改查。

    pdo连接数据库

     
    
    1.    header("Content-Type:text/html;charset=utf-8"); //设置页面编码格式
    2.    $dbms='mysql';                                  //数据库类型
    3.    $dbName='sqlinject';                           //数据库名称
    4.    $user='root';                                   //数据库用户名
    5.    $pwd='';                                        //数据库密码
    6.    $host='localhost';                              //主机名称
    7.    $dsn="$dbms:host=$host;dbname=$dbName";        //数据源名称
    8.    try{                                             //捕获异常
    9.        $pdo=new PDO($dsn,$user,$pwd);             //实例化对象
    10.        echo "PDO连接MySQL成功";
    11.   }catch(Exception $e){
    12.        echo $e->getMessage()."
      "
      ;
    13.   }
    14. ?>

     

    • 编码不要设置为gbk

    • ban掉一些关键字

    • 不允许空格

    • addslashes()函数进行转义

    • md5()加密存储

    1. if(strlen($username)>6){
    2. die();
    3. }

    文件上传模块

    源码

    upload.php

    1.    session_start();
    2.    header("Content-Type:text/html;charset=utf-8");
    3.    include('./conn.php');
    4. // 附件的存储位置、附件的名字
    5. $path='./headpic/'.$_FILES['file']['name'];
    6. echo '文件路径'.$path."
      "
      ;
    7. $username = $_SESSION['user'];
    8. // 拼接成该文件在服务器上的名称
    9. if($_FILES['file']['error']>0) {
    10.    die("出错了!".$_FILES['file']['error']);
    11. }
    12. if(move_uploaded_file($_FILES['file']['tmp_name'],$path)){
    13.    //echo "
      "."Upload Success!";
    14.    
    15.    mysqli_query($conn,"update flag set pic='$path' where username='$username';");
    16.    echo "恭喜您,上传成功!"."
      3秒后将自动跳转到主页!"
      ;    
    17.    header("refresh:3;url=./welcome.php");
    18. }else{
    19.    //echo "
      "."Upload Failed!".$_FILES['photo']['error'];  
    20.    echo "对不起,上传头像失败了!";
    21.    header("refresh:2;url=./welcome.php");
    22. }
    23. ?>

    测试

    直接上传脚本文件,发现存在前端验证,这是很好绕过的,抓包改包就好了

     

    返回了上传文件的路径

     

    图片马?

    00截断?

    upload-labs pass12

     

     

     

    源码加固

    • 设置上传文件目录权限不能给执行权限

       

    • 前端、后端验证(白名单)

    • 二次渲染

    • 对上传后的文件进行重命名

    • 不要暴露上传文件的位置

    • 禁用上传文件的执行权限

    • 黑白名单

    • 对上传的文件重命名,不易被猜测

    • 对文件内容进行二次渲染

    • 对上传的内容进行读取检查

    1.    session_start();
    2.    header("Content-Type:text/html;charset=utf-8");
    3.    include('./conn.php');
    4. // 附件的存储位置、附件的名字
    5. $path='./headpic/'.$_FILES['file']['name'];
    6. // $ext=explode('.',$_FILES['file']['name']); //划分数组
    7. // $ext=end($ext);
    8. // $path='./headpic/'.time().'.'.$ext;
    9. $username = $_SESSION['user'];
    10. // 拼接成该文件在服务器上的名称
    11. //deldot()函数
    12. // function deldot($s){
    13. // for($i = strlen($s)-1;$i>0;$i--){
    14. // $c = substr($s,$i,1);
    15. // if($i == strlen($s)-1 and $c != '.'){
    16. // return $s;
    17. // }
    18. // if($c != '.'){
    19. // return substr($s,0,$i+1);
    20. // }
    21. // }
    22. // }
    23. if($_FILES['file']['error']>0) {
    24.    die("出错了!".$_FILES['file']['error']);
    25. }
    26. // if (($_FILES['file']['type'] == 'image/jpeg') || ($_FILES['file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif'))
    27. // {
    28. //   $deny_ext = array(".png",".jpg",".gif",".jpeg"); //白名单
    29. //   $file_name = trim($_FILES['file']['name']);       //收尾去空
    30. //   $file_name = deldot($file_name);                 //删除文件名末尾的点
    31. //   $file_ext = strrchr($file_name, '.');             //返回字符串中.后面的部分,也就是后缀名
    32. //   $file_ext = strtolower($file_ext); //转换为小写
    33. //   $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
    34. //   $file_ext = trim($file_ext); //收尾去空
    35. // $path='./headpic/'.time().$file_ext;
    36. echo '文件路径'.$path."
      "
      ;
    37. //   if (in_array($file_ext, $deny_ext)) {
    38.        if(move_uploaded_file($_FILES['file']['tmp_name'],$path)){       //上传成功会返回Ture
    39.        //echo "
      "."Upload Success!";
    40.    
    41.              mysqli_query($conn,"update flag set pic='$path' where username='$username';");
    42.              echo "恭喜您,上传成功!"."
      3秒后将自动跳转到主页!"
      ;    
    43.              header("refresh:3;url=./welcome.php");
    44.           }else{
    45.               //echo "
      "."Upload Failed!".$_FILES['photo']['error'];  
    46.               echo "对不起,上传头像失败了!";
    47.               header("refresh:2;url=./welcome.php");
    48.                 }
    49.  // }else{
    50.   //     echo "WAF!"."您上传的文件类型为".$file_ext."不允许上传"."
      ";    
    51.     //   header("refresh:3;url=./headpic.html");
    52.   // }
    53. // }
    54. ?>

    发布动态模块

    源码

    1. session_start();
    2. header("Content-type:text/html;charset=utf-8");
    3. $username=$_SESSION['user'];
    4. $dbtable=substr($username,0,8).'blog';
    5. include('./blogconn.php');//链接数据库
    6. include('./allblogconn.php');//链接数据库
    7. $sql22="create table $dbtable(id int auto_increment primary key, blog varchar(300) not null);";
    8. $result=mysqli_query($conn2,$sql22);
    9. $conn2->query($sql22);
    10. $blog=$_POST['blog'];
    11. if(isset($blog)){
    12. $blogsql="insert into $dbtable(id,blog) values(null,'$blog');";
    13.                
    14. $result=mysqli_query($conn2,$blogsql);
    15. $allblogsql="insert into allblog(id,username,blog) values(null,'$username','$blog');";
    16. $result10=mysqli_query($conn10,$allblogsql);
    17. }
    18. mysqli_close($conn);//关闭数据库
    19.   ?>

    测试

  • http://dongyu29.xyz/xss.html
  • xss.html

    1. html>
    2. <html lang="en">
    3. <head>
    4.    <meta charset="UTF-8">
    5.    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6.    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7.    <title>Documenttitle>
    8. head>
    9. <body>
    10. <script type="text/javascript">location="https://www.bilibili.com/"script>
    11. body>
    12. html>

    源码加固

    $blog=htmlspecialchars($blog);  

  • 相关阅读:
    git commit规范提交
    YOLOv5图像分割--SegmentationModel类代码详解
    微容器相对于大型容器的优势
    【从头构筑C#知识体系】0.1 背景故事
    Hadoop运行模式
    向量数据库—加速大模型训练推理
    cocoaPods源码之从入口Pod学起
    下载遥感数据慢的原因
    Vue中 事件总线(eventBus)详解及使用
    【蓝桥杯每日一题】4.4 扫雷
  • 原文地址:https://blog.csdn.net/qq_61778128/article/details/126899580