1.反射型
LOW:
没有过滤,直接键入PAYLOAD
查看源码

这里没有任何过滤,使用htmlspecialchars()过滤

结果不弹窗

MEDIUM:
LOW等级的方法不奏效了

观察输出可能是过滤了<script>标签
审查元素发现确实过滤了<script>标签

使用大小写混写绕过 <scrIpt>alert(1)</sCript>

查看代码发现只过滤了<script>

而且只过滤了一次,所以可以嵌套<script>绕过
<scr<script>ipt>alert(1)</scrip<script>t>
还可以使用htmlspecialchars()过滤


HIGH:
MEDIUM也不会弹窗了

发现发生了过滤,而且script都被过滤了
输入<img src=1 onerror=alert(1)>

查看源码,发现仅仅是过滤了script

过滤时不推荐使用黑名单,基本上总有办法绕过
IMPOSSIBLE:

发现输入的代码变成了HTML实体查看源码发现使用了htmlspecialchars处理,并且使用了token,防止了CSRF

2.存储型
LOW:
这里Name的maxlength是10,可以审查元素给修改成大的值

输入<script>alert(1)</script>弹窗出现两次,说明在Name和Message处都存在存储型XSS

查看源码发现只是去除了两端的空白字符

使用htmlspecialchars处理


MEDIUM:
使用LOW的PAYLOAD已经不行了

还是过滤了script

在Name处成功弹窗,Message处被过滤了

查看源码

HIGH:

查看源码

IMPOSSIBLE:
直接看源码

对name,message都过滤了
3.DOM型
LOW:

直接弹窗
查看源码

emmm..毛都没有..
MEDIUM:
输入PAYLOAD

发现没有弹窗,查看元素

发现在<option>标签里,再次尝试一次,这次闭合<option>标签

还是没又弹窗,中再次查看元素

再次向上闭合<select>标签


成功弹窗
查看源码

如果出现<script,会重定向到English
HIGH:
输入MEDIUM的PAYLOAD

发现重定向到English了
URL中 #后面的字符会被当做定位标识符,所以不会被传递给服务器,只与浏览器交互,而DOM型XSS也是只与浏览器交互
所以尝试#,修改完#之后,浏览器不会重载,需要手动刷新

审查元素

剩下就是类似于MEDIUM等级,闭合标签


查看源码

只允许French,English,German,Spanish四种语言
IMPOSSIBLE:
直接看源码

告诉我们代码防御在客户端
查看index.php


如果是impossible等级的,不会解码URL,直接置为空,并不会进行解码

果然没有解码
将上面代码注释


注意:
防御XSS即使用了htmlspecialchars,只要我们在前端又进行了操作
也可能有危险,请看下面的例子
<html> <?php $a=htmlspecialchars($_GET['id']); //$a=$_GET['id']; echo 'id: '.$a; echo '</br>'; echo 'urldecodeId: '.urldecode($a); echo '</br>'; ?> html: <input type='text' value="<?=$a?>"/> <br/> <script> var lang = document.location.href.substring(document.location.href.indexOf("id=")); document.write('JS: '+lang); document.write('<br/>'); document.write('decodeURI: '+decodeURI(lang)); </script> </html>

最后的转码会造成XSS