目录
前言:本篇博客主要记录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);
}