xss-labs
level 1:
没有任何的编码和过滤,用户的输入直接输出到heml页面了。
所以payload:
1 | <script>alert(1)</script> |
level 2:
经过测试,本关有两个输出点。
当我尝试输入<script>
时,页面中两个输出点:
1 | <h2 align=center>没有找到和<script>相关的结果.</h2><center> |
我们可以发现<h2>
标签中的尖括号被过滤了,而<input>
标签中的属性值没有被过滤,所以利用这一漏洞点我们即可构造payload如下:
1 | " onclick="alert(1) |
我们得到的html页面中拼接好的<input>
标签如下:
1 | <input name=keyword value="" onclick="alert(1)"> |
所以当我们点击输入框时即可触发弹框。
注意:<h2>
处的过滤是通过htmlspecialchars()函数过滤的,后面的过滤也会用到这个函数。
level 3:
经过level2跳转过来,给的默认参数是level3.php?writing=wait
,但是向writing
传入值并没有在页面中发现输出点,所以此参数没有被输出到页面中来。
通过看前端的代码我们可以在<input>
标签中发现一个名为keyword
的参数名,向它传值,发现可以在前端中输出。
经过测试,可以发现两个输出点中过滤了尖括号、双引号,单引号没有被编码,由此可以推断出是后端是通过htmlspecialchars
函数进行过滤的,因为该函数默认情况下仅编码双引号,而恰好<input>
标签中的属性值的闭合符号是单引号,所以我们可以构建闭合,
payload:
1 | ' onclick='alert(1) |
同level2,点击输入框即可触发弹窗。
level 4:
测试发现两个输出点,
第一个输出点编码过滤了尖括号、双引号;
第二个输出点过滤了尖括号。
所以这里我们可以使用双引号进行属性的闭合来进行弹窗的注入。
payload:
1 | " onclick="alert(1) |
level 5:
经过测试:
第一个输出点,过滤了尖括号、双引号、没有过滤掉单引号;推测使用htmlspecialchars
函数。
第二个输出点,过滤了<script
和on
;推测是识别指定字符串然后进行替换过滤。
由此可以看出第二个输出点的余地是比较大的,毕竟没有把尖括号和引号完全过滤,我们可以使用>
来闭合标签的方法,来插入新的标签。
payload:
1 | "> <a href="javascript:alert(1)">colickme</a> |
注意:第二个输出点这里过滤使用的函数是:str_replace()
level 6:
测试发现被过滤的字段如下:<script
on
href
src
也是有两处输出点,第一处是htmlspecialchars
函数过滤,第二处是过滤指定字符串。
由于html大小写不敏感,所以我们可以尝试大小写绕过,
payload:
1 | " Onclick="alert(1) |
level 7:
这关是将敏感字符串置为空值,这类过滤方法我们可以使用双写来绕过。
payload:
1 | " oonnmouseover="alert(1) |
level 8:
什么是HTML实体编码?
由经验可以推测出<input>
标签中的输出点是通过htmlspecialchars()
函数过滤的
第二个输出点是通过str_replace()
函数过滤的,将指定的敏感字符过滤掉。
之前的绕过方法都不可行,所以这里我们可以试着尝试进行html实体编码绕过
我们要利用的是第二个输出点中的标签的属性值,对要输入的字符串进行html实体编码处理,来绕过过滤
payload:
1 | javascript:alert(1) |
html编码工具
属性值被html编码后还可以正常运行,但是标签一旦被html编码后就无法执行了
level 9:
这部分黑盒没出来,所以审计代码可知,如果要得到href参数的值,字符串中必须有http://
的值,字符串过滤与level8一样,通过html实体编码可以绕过对关键字的过滤
payload:
1 | javascript:alert('http://') |
level 10:
在url keyword变量输出参数查看返回的结果。
打开网页端源码进行检查,网页端源码表单并没有keyword,但是多了三个隐藏的<input>
标签,我们可以依次传值,查看输出点。如下:
我们可以发现,只有t_sort
值被输出,所以我们在这个点进行注入,并且闭合掉后面的隐藏属性:
payload:
1 | t_sort=" onfocus="alert(1)" type="text |
level 11:
这部分我们查看网页端源码可以发现,在表单中有一串url地址:
这是我们上一个页面的url地址,可以判断出这是http头中的REFERER值,所以我们可以抓包修改http请求头中的REFERER中的值构建payload,在http头尝试构建payload,发现只过滤了尖括号,所以我们可以构建payload如下:
1 | " onfocus="alert(1)" type="text |
level 12:
首先我们查看网页端源码发现表单中t_ua
中的值是User-Agent的值,
所以这里与level11同理,后端也是只过滤了尖括号,所以我们抓包修改User-Agent的值即可,payload同上。
level 13:
首先查看网页端代码,
抓包发现这次是注入点是cookie值,查看后端代码发现也是只过滤了尖括号,所以payload同level11
level 14:
exif xss漏洞
由于特殊原因链接中的站点已经无法访问了<iframe>
标签规定了一个内联框架,一个内联框架用来在当前HTML文档中嵌入另一个文档。
由于以上链接中的网站无法访问了,我们来修复这部分功能:
修改网站中level14.php
的源码,替换目标链接到本地路径:
创建exifviewer.php
文件,源码如下:
1 | <?php |
刷新页面,如下:
上传照片文件,从页面信息中我们可以得知,后端程序是读取照片中的exif信息输出到网页端中的,根据xss漏洞的原理,当exif信息过滤不严谨,我们构建的payload被输出到了网页端,就会造成xss攻击。
什么是EXIF?:
1 | 可交换图像文件格式(英语:Exchangeable image file format,官方简称Exif),是专门为数码相机的照片设定的文件格式,可以记录数码照片的属性信息和拍摄数据。 |
我们在Exif中写入payload:
注入成功:
level 15:
ng-include指令注入:
查看页面源代码,经过测试url中src的值是注入点,输出点在<span>
标签中
又看到ng-include指令可以利用,所以我们可以利用ng-include
指令引入外部html来构建payload
注意:ng-include,如果单纯指定地址,必须要加引号
payload:
1 | ?src='level1.php?name=<img src=1 onclick=alert(1)>' |
参考:
文章中的ng-include注意事项非常值得参考
ng-include官方文档
level 16:
首先看网页端的源码,发现我们传入的值显示在标签的外部,像这种位置,想要触发xss攻击,似乎只能构建新的标签来触发了。
经过测试,后端程序过滤替换的字符如下:
被替换的字符 | 替换后的字符 |
---|---|
script |
|
(空格,即 " " ) |
|
/ |
|
" " (5个空格) |
|
script
字符被过滤了,我们只能构建其他的标签了,程序并没有阻止我们构建标签,看来主要是目标是将空格替换为 
,来使得我们的标签无法触发。
现在我们要找能够替换空格的编码了。
可以替换空格的编码:
在 ASCII 编码及许多文本处理、HTML/CSS 渲染规范中,换行符 (LF, %0A)、回车符 (CR, %0D)、换页符 (FF, %0C)、制表符 (TAB, %09) 等都被视为“空白字符 (whitespace characters)” 的一部分,它们在很多场景下会被等同于空格或直接折叠成空格。这就是为什么在某些情况下 %0A、%0C、%0D 解码后表现得像空格一样。
所以我们可以构建payload如下:
1 | <input%0Conclick="alert(1)"> |