关于靶场的搭建:
关于工具:HackBar(目前只能在火狐浏览器的插件使用)、Burpsuite
概要:xss主要分为三种
反射型
·非持久性跨站点脚本攻击
·攻击是一次性的,仅对当次的页面访问产生影响
存储型
·持久型跨站点脚本
·攻击者的数据存储在服务器端,攻击行为将伴随着攻击数据-直存在
DOM型
·既可能是反射型的,也有可能是存储型的
·基于文档对象模型
(Document Objeet Model,DOM)的一种漏洞
xss-labs主要是针对GET方式进行注入,POST方法抓包就行了
第一关
打开第一关源码,发现参数是通过GET方法传递的,并且对传过去的参数没有作过滤
同时该变量的值是直接插入的,所以不需要闭合
payload:
name=<script>alert(1)</script>
第二关
分析代码,还是通过GET传参并将变量进行html实体化输出。
htmlspecialchars()是一个PHP函数,用于将特殊字符转换为HTML实体。它可以将一些特殊字符转换为HTML实体,以防止这些字符被解释为HTML标签或JavaScript代码,从而增强了网页的安全性。
htmlspecialchars()函数将以下字符转换为HTML实体:
&(和号)转换为 &
"(双引号)转换为 "
'(单引号)转换为 '
<(小于号)转换为 <
>(大于号)转换为 >
这样做可以确保用户输入的内容不会被误解释为HTML标签或JavaScript代码,从而防止跨站点脚本(XSS)攻击。通常在输出用户输入的内容到HTML页面时,应该使用htmlspecialchars()函数进行转义,以增强网页的安全性。
但是value的值是通过 表单提交,并没有对表单提交的值进行html实体化,因此只用针对value进行payload的构造
还输入上一关的payload,发现需要闭合
进行双引号闭合
"><script>alert(1)</script>
第三关
输入上一关的payload,发现输入输出的值都被实体化了,并且使用了单引号闭合。
但我们知道,htmlspecialchar()函数只会针对一些特定的字符转化为HTML实体,既然<>" ’ 被过滤了不妨用JavaScript中的事件进行绕过。
事件可以直接嵌入到标签当中,因此不需要进行标签的闭合,从而可以绕过标签被闭合的情况。
这里我们使用onclick构造payload,当点击输入框时就会触发onclick事件(因为onclick在input标签里,input自己会产生一个输入框)
直接输入οnclick=alert(1)发现前后单引号需要闭合
先闭合一个单引号发现不行
发现前一个已经闭合了,只需再闭合后面的就成功了
但是不能将第二个引号放在最后
‘οnclick=alert(1)’
因此payload
'onclick='alert(1)
第二种方法是用onerror事件
onerror
事件是 JavaScript 中的一个事件,用于处理当文档、图像、脚本或其他资源加载过程中发生错误时的情况。当浏览器尝试加载一个资源时,如果该资源无法加载(如文件不存在、网络错误等),就会触发 onerror
事件。
在 HTML 中,onerror
事件通常用于图像 ()、脚本 (
) 和样式表 (``) 等元素上,以便在加载资源失败时执行一些特定的操作,例如显示备用图像、向用户报告错误等。
因此我们可以故意写一个让他报错的代码,从而触发onerror事件
第四关
直接输入
<script>alert(1)</script>
发现我们输入的<>都被去掉了
查看源码发现
$str = $_GET["keyword"];
$str2=str_replace(">","",$str);
$str3=str_replace("<","",$str2);
它使用了一个str_replace函数
str_replace()函数用于在字符串中替换指定的子字符串。它的基本用法是:
str_replace($search, $replace, $subject)
其中:
$search
:要查找并替换的字符串或字符串数组。$replace
:替换成的字符串或字符串数组。如果search和search和search和replace是数组,那么search中的每个元素都会被search中的每个元素都会被search中的每个元素都会被replace中相应位置的元素替换。$subject
:要在其中进行查找和替换的字符串或字符串数组。
这个函数返回一个新的字符串,其中search中的每个元素都被相应位置的search中的每个元素都被相应位置的search中的每个元素都被相应位置的replace元素替换了。如果search和search和search和replace都是数组,并且search的长度不等于search的长度不等于search的长度不等于replace的长度,那么search中多余的元素将被忽略,而search中多余的元素将被忽略,而search中多余的元素将被忽略,而subject中的多余元素将保持不变。
示例:
// 替换单个字符串
$str = "Hello world!";
$new_str = str_replace("world", "PHP", $str);
echo $new_str; // 输出:Hello PHP!
// 替换多个字符串
$str = "Apples and oranges";
$find = array("apples", "oranges");
$replace = array("bananas", "pears");
$new_str = str_replace($find, $replace, $str);
echo $new_str; // 输出:Bananas and pears
// 替换数组中的元素
$search = array("black", "brown", "beige");
$replace = "green";
$subject = array("black shoes", "brown belt", "beige jacket");
$new_subject = str_replace($search, $replace, $subject);
print_r($new_subject); // 输出:Array ( [0] => green shoes [1] => green belt [2] => green jacket )
这里既然将<>给替换为空,那么就可以延用上一关的思路,当<>被过滤时使用事件进行绕过
payload
"onclick="alert(1)
第五关
直接输入
<script>alert(1)</script>
试试水,发现
在我们的第一个<script标签中多了一个_ ,查看代码看看他到底做了什么手脚
$str = strtolower($_GET["keyword"]);
$str2=str_replace("<script","<scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
通过代码分析发现:首先对传过来的参数进行了strtolower()处理
strtolower()函数是PHP中的一个字符串函数,用于将字符串中的所有字母转换为小写字母。
例如:
$str = "Hello World!";
$new_str = strtolower($str);
echo $new_str; // 输出:hello world!
然后还是用str_replace函数进行替换
发现不仅<script被替换了,on也被替换了
这意味着我们我们不能使用Script标签和on事件了
但是他并没有对<>进行过滤,因此我们使用a标签来构造payload
当进行点击时,会跳转到herf的值对应的链接。
但是herf后面跟链接对我们解出payload并没有什么帮助,此时就要用到JavaScript伪协议了
JavaScript 伪协议(JavaScript pseudo-protocol)是一种特殊的 URL 格式,用于在网页中执行 JavaScript 代码。它通常以 “javascript:” 开头,后面跟随着 JavaScript 代码。
JavaScript 伪协议最常见的用途是在 HTML 的链接 (`` 标签) 的 href
属性中,或者在 HTML 的事件处理器中,如 onclick
事件。
例如,以下是一个在链接中使用 JavaScript 伪协议的例子:
<a href="javascript:alert('Hello, world!');">Click me</a>
点击这个链接会弹出一个包含 “Hello, world!” 的警告框
因此我们用这个来构造payload
"><a href=javascript:alert(1)>1</a>
点击1后触发了payload,成功绕过!
第六关
输入上一关的payload等,发现<script , on事件,和href都被过滤了
查看源码
$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);
发现过滤了好多标签啊,汗流浃背了?
但是前一关不是使用了strtolower函数吗?这关咋没了?
很明显就是想让你用这个来绕过啊
在 HTML 中,对于标签名和属性名,是不区分大小写的。这意味着
href
、
HREF
、
HRef
都表示同一个属性。
但是,对于标签和属性的值,HTML 是区分大小写的。例如,在 [Link](https://example.com)
中,https://example.com
和 HTTPS://example.com
被认为是不同的链接地址。
在 JavaScript 和 CSS 中,通常也是对于标签名和属性名不区分大小写的,但是对于属性值是区分大小写的。
因此
"><Script>alert(1)</script>
第七关
一点儿一点儿探测太累了怎么办?
用xss万能语句来进行探测
<SCRscriptIPT>'"()Oonnjavascript
输入后查看网页源码
与原来的对比发现他过滤了script,on,同时大写也变成了小写。
查看源码
$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);
与上一关比,他多了个strtolower()函数来使所有的字母都变成小写,那么说明我们无法用大小写进行绕过了,但是通过万能语句发现,进行拼接而成的最后变成了
"><sscriptcript>alert(1)</sscriptcript>
第八关
添加友情链接?什么鬼
先用万能语句试试
发现双写不管用了,同时双引号也被实体化了,但是单引号没有,说明对过滤没有使用实体化函数,而是将双引号替换为了"
查看源码
$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);
果然如我们所推理的一样
但是双引号被实体编码了,我们已经没法闭合href标签了,同时双写,大小写都失效了,该怎么办呢?
我们观察href可以知道,如果我们插入的是javascript:alert(1)就可以直接执行payload,可惜的是被过滤了,但是倘若在传参给$str的时候就是编码格式是不是就能绕过呢?
这里我们可以对payload进行Unicode编码或者十六进制编码
Unicode:
javascript:alert(1)
Hex:
javascript:alert(1)
在线编码网站:CTF在线工具-CTF工具|CTF编码|CTF密码学|CTF加解密|程序员工具|在线编解码 (hiencode.com)
或者使用HackBar
用HTML Characters也可完成编码
第九关
还是让我们添加一个链接,试试上一关的payload
javascript:alert(1)
提示不合法?正常的链接是不是应该有http://
加个http://试试
http://javascript:alert(1)
发现再次点击友情链接并不会报错了,说明后台代码有检测链接合法不合法的机制,让我们查看源码
<?php
if(false===strpos($str7,'http://'))
{
echo '<center><BR><a href="您的链接不合法?有没有!">友情链接</a></center>';
}
else
{
echo '<center><BR><a href="'.$str7.'">友情链接</a></center>';
}
?>
这关与上一关相比,多了一个检测机制
这里还用到了strpos()函数
strpos()
函数用于在字符串中查找第一次出现子字符串的位置,并返回其位置的索引。如果找到子字符串,则返回第一次出现的位置(索引值),如果没有找到,则返回 false
。
语法如下:
strpos(string $haystack, string $needle, int $offset = 0): int|false
参数说明:
$haystack
:要搜索的字符串。$needle
:要查找的子字符串。$offset
(可选):指定搜索的起始位置,默认为 0。
示例用法:
$string = 'Hello, world!';
$substring = 'world';
$pos = strpos($string, $substring);
if ($pos !== false) {
echo "子字符串 '$substring' 在字符串中的位置为: $pos";
} else {
echo "未找到子字符串 '$substring'";
}
意思是他将经过检测后的字符串 s t r 7 传入 s t r p o s ()函数中,检索字符串中是否含有 h t t p : / / ,如果没有返回 f a l s e ;否则就将 str7传入strpos()函数中,检索字符串中是否含有http://,如果没有返回false;否则就将 str7传入strpos()函数中,检索字符串中是否含有http://,如果没有返回false;否则就将str7直接传入href中
但是http://存在时,代码也没法正常执行,想办法不让http:// 出现
可以使用注释
javascript:alert(1)/* http:// */
(注释不能放在前面,否则无法正常执行)
第十关
这一关看了一圈都没有输入框
但是看见
URL栏好像可以传参,他用的还是GET方法
先输入万能语句看看过滤了什么
发现应该是只用了htmlspecialchars()函数
查看源码
$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>
但是实际值应该传给t_sort而不是传给keyword
发现他对t_sort传来的值过滤了<>
还记不记之前提的,过滤了<>就用on事件,但是这次并没有输入框啊
那就加个属性吧
"onclick=javascript:alert(1) type="text
点击出现的输入框即可完成本关
这里还有一种更简单的办法
F12打开开发者模式,直接修改前端的内容进行绕过
双击就可以修改了,这样绕过嘎嘎快
然后点击框框就可以绕过了
第十一关
还使用刚刚的方法试试
但是这样算是走捷径了
因为这个函数,只要弹出框就算通过了,所以我们还是用正常的方法过吧
F12发现有四个值可以传,且最后一个t_ref的值是上一关的地址,我们不难猜出,这个t_ref是http-referer的意思
那我们对前面三个参数传值
t_sort=<SCRscriptIPT>'"()Oonnjavascript &t_link=<SCRscriptIPT>'"()Oonnjavascript &t_history=<SCRscriptIPT>'"()Oonnjavascript
发现没啥用,唯一可以显示出来的值t_sort还被实体化了,用不了事件也闭合不了,那就只能从referer下手了
通过观察我们不难发现t_ref的值是上一关的referer,并且没有对refer进行过滤
那我们就可以构造恶意的referer从而进行绕过
打开HackBar
勾选Referer,然后在下面直接修改为我们的payload
"onclick=javascript:alert(1) type="text
点击Execute(执行)
点击文本框,成功!
另一种方法是通过BurpSuite进行抓包,我们先返回第十关
这时候抓包
把referer改成11关的payload就可以了
不过这种方法没有使用HackBar好用
第十二关
打开12关,也是没有什么头绪,那就看看页面源码吧
上一关是referer那这一关很明显就是关于UA的了
和上一关一样轻轻松松
第十三关
前两关是referer和UA我猜这次是cookie。
。。。猜对了
记得不要删去cookie中的user,否则会传参失败
第十四关
这关挂了,不用做了。。。
第十五关
点击上一关的进入下一关会跳转到错误的url,改一下你原本的url就好
没啥思路就看看网页源码吧,发现之前的表单提交都没了,多了一个ng-include:,且url传的值放在了ng-include后面
ng-include
是 AngularJS 框架中的一个指令,用于将外部 HTML 文件或 AngularJS 模板包含到当前页面中。
具体来说,ng-include
指令可以在页面中指定一个 HTML 文件或者 AngularJS 模板的 URL,并将其包含到当前页面中的指定位置。这样可以实现页面模块化和重用性,使得页面结构更加清晰和易于维护。
简单来说
他的作用就是这样,可以引用其他的文件也就是能够包含其他的文件
前面测了一下绕过什么了,就不展示了也就是给实体化
payload
src='./level1.php?name=<img src=1 onerror=alert(1)>'
第十六关
输入我们的万能语句
发现大写变成了小写,但是<>没有说明没有实体化,同时可以发现script被替换为了  ;也就是空格,从而避免我们拼接script
那我们试试这个payload
</center><img src=1 onerror=alert(1)><center>
使用img src=1进行错误的语法从而触发onerror事件
但是发现/,空格,也被  ; 替换掉了
空格被替换了问题也不大,我们用换行符用url编码就好了
<img%0Asrc=1%0Aonerror=alert(1)>
(换行不影响代码的执行,只要他在标签里面就好了)
第十七关
这关使用到了embed标签
`` 标签是 HTML 中用来嵌入外部内容的标签,通常用于嵌入多媒体文件(如音频、视频、Flash 等)或其他插件(如 PDF、SVG 等)到网页中。
具体来说,`` 标签可以通过指定 src
属性来指定要嵌入的外部资源的 URL,以及通过其他属性来设置嵌入内容的属性,如宽度、高度、类型等。
示例用法:
<embed src="video.mp4" width="400" height="300">
但是这关需要flash插件的支持,由于flash插件漏洞太多了
使用img src=1进行错误的语法从而触发onerror事件
但是发现/,空格,也被  ; 替换掉了
空格被替换了问题也不大,我们用换行符用url编码就好了
<img%0Asrc=1%0Aonerror=alert(1)>
(换行不影响代码的执行,只要他在标签里面就好了)
这关需要flash插件的支持,由于flash插件漏洞太多了
并且性能与技术早已落后,所以17-20关就不做了…
总结
XSS漏洞一直被评估为web漏洞中危害较大的漏洞,在OWASP TOP10的排名中一直属于前三的江湖地位。
XSS是一种发生在前端浏览器端的漏洞,所以其危害的对象也是前端用户。
形成XSS漏洞的主要原因是程序对输入和输出没有做合适的处理,导致“精心构造”的字符输出在前端时被浏览器当作有效代码解析执行从而产生危害。
因此在XSS漏洞的防范上,一般会采用“对输入进行过滤”和“输出进行转义”的方式进行处理:
输入过滤:对输入进行过滤,不允许可能导致XSS攻击的字符输入;
输出转义:根据输出点的位置对输出到前端的内容进行适当转义
以下是一些防范存储型XSS攻击的建议:
- 输入过滤和验证:对用户输入的数据进行严格的过滤和验证,确保只允许合法的数据格式输入。
- 转义输出:在显示用户输入的内容时,确保对特殊字符进行转义,以防止恶意脚本的执行。比如,在Web页面中显示用户输入的内容时,可以使用HTML编码来转义特殊字符。
- 内容安全策略(CSP):实施内容安全策略,限制页面可以加载的资源,包括脚本文件、样式表等,从而减少XSS攻击的风险。
- HTTPOnly标记:对于Cookie,使用HTTPOnly标记可以防止JavaScript访问敏感的Cookie信息,减少会话劫持的风险。
- 定期安全审计:定期对网站进行安全审计和漏洞扫描,及时发现并修复潜在的安全问题。
- 敏感操作的二次验证:对于涉及敏感操作的页面,如修改密码、支付等,应该实施二次验证机制,增加安全性。
下面是一些防范DOM型XSS攻击的建议:
- 输入验证和过滤:与其他类型的XSS攻击一样,对用户输入的数据进行严格的验证和过滤,确保不会执行恶意脚本。
- 不要信任客户端数据:不要直接信任客户端提供的数据,始终在服务器端对数据进行验证和处理。
- 避免使用eval():避免使用eval()函数执行动态生成的JavaScript代码,因为这可能会导致DOM型XSS漏洞。
- 安全的编码:在操作DOM时,确保对用户输入的内容进行适当的编码,以防止恶意脚本的执行。
- 使用安全的JavaScript框架:使用经过安全审计的JavaScript框架,这些框架通常会提供一些内置的安全机制来防范XSS攻击。
- 定期更新和监控:及时更新浏览器和相关的安全补丁,监控网站的安全情况,发现潜在的漏洞并及时修复。
xss基础测试语句:
'';!--"<XSS>=&{()}
<script>alert(/1/)</script>
<img scr=1 onerror="alert(/1/)">
<img src="javascript:alert('1');">
<a href="javascript:alert(1)">
同时关于xss还有许多使用的工具:
https://blog.csdn.net/p36273/article/details/131263927
https://blog.csdn.net/weixin_54977781/article/details/123555545