山东大学软件学院项目实训-创新实训-网络安全靶场实验平台(十四)

本文详细讲解了XSS漏洞,包括反射型XSS的利用流程、代码示例和存储型XSS的持久危害,以及如何在实际场景中构造payload实现攻击。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、XSS介绍

二、反射型(非持久型)XSS漏洞

 三、存储型(持久型)XSS


前言:本篇博客主要记录XSS漏洞的实现,包括反射型XSS漏洞、存储型XSS漏洞。

一、XSS介绍

跨站脚本(Cross-site scripting,简称为:CSS, 但这会与层叠样式表(Cascading Style Sheets,CSS)的缩写混淆。因此,跨站脚本攻击缩写为XSS)是一种网站应用程序的安全漏洞攻击。

XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、 LiveScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。


二、反射型(非持久型)XSS漏洞

反射型XSS只是简单的把用户输入的数据从服务器反射给用户浏览器,要利用这个漏洞,攻击者必须以某种方式诱导用户访问一个精心设计的URL(恶意链接),才能实施攻击。

攻击流程:

具体代码实现:

<!--题目名字:XSS-Reflect-->
<!--题目类型:XSS-->
<!--题目描述:反射型XSS漏洞-->
<!--题目难度:3星-->
<template>
  <div id="building">
    <div style="margin-top: 1%;margin-left: 50%">
      <el-input v-model="xss_reflect" style="width: 45%;margin-right: 5%;" placeholder="payload"></el-input>
      <el-button @click="xss_reflect_fun" type="success" plain>搜索</el-button>
      <el-button @click="problem" type="success" plain>题目要求</el-button>
    </div>
  </div>

  <el-dialog v-model="problemdetail" title="题目要求" width="30%">
    <p>该页面存在反射型XSS漏洞,能否构造payload,使得页面出现弹窗(弹窗内容为你的学号)?</p>
  </el-dialog>

</template>

<script>
import request from "@/utils/request";

export default {
  data(){
    return{
      xss_reflect:'',
      myresult:'',
      problemdetail:false,
      user:localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : {},
    }
  },
  methods:{
    xss_reflect_fun(){
      request.get("/xss/reflect",{
        params:{
          xss:this.xss_reflect,
          username:this.user.username
        }
      }).then(res =>{
        this.myresult=res.data;
        console.log(res.code)
        console.log(res.data)
        if(res.code==200)
          document.write(this.myresult);
        else
          location.reload()
      })
    },
    problem(){
      this.problemdetail=true
    }

  }
}
</script>
<style scoped>
#building{
  background:url("../../../assets/img/bugimg/MOOC.jpg");
  width:100%;
  height:100%;
  position:fixed;
  background-size:100% 100%;
}
/deep/ .el-input__inner {
  background-color: rgba(255, 255, 255, 0.5) !important;
}

</style>

 

    @GetMapping("/reflect")
    public @ResponseBody  Result reflect(@RequestParam(value = "xss") String xss,
                                         @RequestParam(value = "username") String username) {

        String problemid = "pro012";
        String flag = null;
        String flagMD5 = null;
        try {
            Connection connection = dataSource.getConnection();
            // 预编译
            String sql = "select flag from flag where username = ? and problemid = ?";
            String sql_flag = null;
            PreparedStatement st = connection.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
            st.setString(1, username);
            st.setString(2, problemid);
            System.out.println(sql);
            ResultSet rs = st.executeQuery();
            // 通过此对象可以得到表的结构,包括,列名,列的个数,列数据类型
            rs.last();
            int row = rs.getRow();

            rs.beforeFirst();
            System.out.println("查找到行数为"+row);
            if(row==1){

                rs.next();
                flag = rs.getString("flag");
                System.out.println("flag已存在:"+ flag);
            }
            else {
                FlagMake flagMake = new FlagMake();
                flag = flagMake.getFlag();
                System.out.println("生成flag:"+ flag);
                //将flag MD5加密后存入数据库
                flagMD5 = MD5.getMD5String(flag);
                sql = "insert into flag (`username`, `problemid`, `flag`) values ('"+username+
                        "', '"+problemid+"', '"+flag+"');";
                //将flag存入数据库(插入),提供给用户使用SQL注入获得flag
                sql_flag = "insert into sqlifl4g (`username`, `problemid`, `fl4g`) values ('"+username+
                        "', '"+problemid+"', '"+flag+"');";
                Statement stmt = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
                        ResultSet.CONCUR_UPDATABLE);

                stmt.executeUpdate(sql);
                stmt.executeUpdate(sql_flag);

            }
            rs.close();
            connection.close();

        } catch (SQLException e) {
            System.out.println("输入内容错误,数据库查询错误");
            System.out.println(e.toString());
            //return "输入内容错误,数据库查询错误";
        }
            return Result.success("<script>alert(\"" +"弹窗正确!flag为:"+ flag + "\")</script>");
        else
            return Result.error();
    }

 三、存储型(持久型)XSS

存储型(或 HTML 注入型/持久型)XSS 攻击最常发生在由社区内容驱动的网站或 Web 邮件网站,不需要特制的链接来执行。黑客仅仅需要提交 XSS 漏洞利用代码(反射型XSS通常只在url中)到一个网站上其他用户可能访问的地方。这些地区可能是博客评论,用户评论,留言板,聊天室,HTML 电子邮件,wikis,和其他的许多地方。一旦用户访问受感染的页,执行是自动的。

存储型XSS漏洞的成因与反射型的根源类似,不同的是恶意代码会被保存在服务器中,导致其它用户(前端)和管理员(前后端)在访问资源时执行了恶意代码,用户访问服务器-跨站链接-返回跨站代码。

攻击流程:

主要代码如下:

<!--题目名字:XSS-Store-->
<!--题目类型:XSS-->
<!--题目描述:存储型XSS漏洞-->
<!--题目难度:4星-->
<template>
<div id="building">
  <div style="margin-top: 0.5%;">
    <el-button @click="problem" style="float: left;margin-left: 15%">题目要求</el-button>
    <el-input v-model="xss_store" style="width: 25%;margin-left:20%;" placeholder="payload"></el-input>
    <el-button @click="xss_store_fun" style="margin-left: 1%">搜索</el-button>
    <el-button v-if="payload==1" @click="show"> 查看 </el-button>
  </div>

</div>

  <el-dialog v-model="problemdetail" title="题目要求" width="30%">
    <p>该页面存在存储型XSS漏洞,能否构造payload,使得在控制台输出你的学号?</p>
    <p>输入payload,搜索后,点击查看按钮,查看结果。</p>
  </el-dialog>

</template>

<script>
import request from "@/utils/request";

export default {
  data(){
    return{
      xss_store:'',
      myresult:'',
      payload:0,
      problemdetail:false,
      user:localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : {},
    }
  },
  methods:{
    xss_store_fun(){
      request.get("/xss/stored/store",{
        params:{
          xss:this.xss_store,
          username:this.user.username
        }
      }).then(res =>{
        console.log(res)
        this.payload=1
      })
    },
    show(){
      request.get("/xss/stored/show",{
        params:{
          username:this.user.username
        }
      }).then(res =>{
        if(res.code==200){
          alert("答案正确!")
          console.log(res.data)
          document.write(res.msg)
        }
        else if(res.code==500){
          alert("答案错误!")
          document.write(res.msg)
        }
      })
    },
    problem(){
      this.problemdetail=true
    }
  }
}
</script>
<style scoped>
#building{
  background:url("../../../assets/img/bugimg/weibo.jpg");
  width:100%;
  height:100%;
  position:fixed;
  background-size:100% 100%;
}
</style>

 

    @GetMapping("/stored/store")
    public @ResponseBody Result store(@RequestParam(value = "xss") String xss,
                                      @RequestParam(value = "username") String username) {
        if(xssstoreMapper.sel(username)==0){
            xssstoreMapper.add(username,xss);
        }else{
            xssstoreMapper.refresh(username,xss);
        }

        String problemid = "pro011";
        String flag = null;
        String flagMD5 = null;
        try {
            Connection connection = dataSource.getConnection();
            // 预编译
            String sql = "select flag from flag where username = ? and problemid = ?";
            String sql_flag = null;
            PreparedStatement st = connection.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
            st.setString(1, username);
            st.setString(2, problemid);
            System.out.println(sql);
            ResultSet rs = st.executeQuery();
            // 通过此对象可以得到表的结构,包括,列名,列的个数,列数据类型
            rs.last();
            int row = rs.getRow();

            rs.beforeFirst();
            System.out.println("查找到行数为"+row);
            if(row==1){
                rs.next();
                flag = rs.getString("flag");
                System.out.println("flag已存在:"+ flag);
            }
            else {
                FlagMake flagMake = new FlagMake();
                flag = flagMake.getFlag();
                System.out.println("生成flag:"+ flag);
                //将flag MD5加密后存入数据库
                flagMD5 = MD5.getMD5String(flag);
                sql = "insert into flag (`username`, `problemid`, `flag`) values ('"+username+"', '"+problemid+"', '"+flag+"');";
                System.out.println(sql);
                //将flag存入数据库(插入),提供给用户使用SQL注入获得flag
                sql_flag = "insert into sqlifl4g (`username`, `problemid`, `fl4g`) values ('"+username+"', '"+problemid+"', '"+flag+"');";
                Statement stmt = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
                        ResultSet.CONCUR_UPDATABLE);

                stmt.executeUpdate(sql);
                stmt.executeUpdate(sql_flag);

            }
            rs.close();
            connection.close();

        } catch (SQLException e) {
            System.out.println("输入内容错误,数据库查询错误");
            System.out.println(e.toString());
            //return "输入内容错误,数据库查询错误";
        }

        return Result.success();
    }
    @GetMapping("/stored/show")
    public @ResponseBody Result show(@RequestParam(value = "username") String username) {

        String problemid="pro011";
        String xss=xssstoreMapper.getContent(username);
        String flag=flagMapper.getFlag(username,problemid);

        if(xss.equals("<script>console.log(\"" + username + "\")</script>"))
            return Result.success(xss,"flag为:"+ flag);
        else
            return Result.error(Constants.CODE_500,xss);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值