Level 1
通过GET方式传入name,会在页面上显示出来
写入payload
1  | <?php  | 
在代码中没有看到过滤、转义,直接将输入显示在页面上
Level 2
通过GET方式传入keyword,会在页面上显示出来
并且在<form>标签的value属性上也会显示输入
尝试写入payload,发现没有正确的显示出来
使用Firebug查看,发现<h2>标签中的输入被HTML实体化编码
<form>标签中value属性的值同样被HTML实体化,不过由于在标签内部,所以可以使用事件触发xss,而不需要加上会被转义的<>
payload
1  | <?php  | 
查看代码,可以看到htmlspecialchars()对输入进行了转义
Level 3
通过GET方式传入keyword,显示方式和Level 2相同,在<h2>和<form>标签上显示
输入Level 2的payload,发现没有成功闭合
使用'代替",成功闭合
payload
1  | <?php  | 
代码上和第二关不同的地方在于,value=属性后引号变成了单引号,所以需要使用'进行闭合。由于浏览器会将'变为"显示,所以使用Firebug审查元素时,无法区分
Level 4
通过GET方式传入keyword,显示方式和Level 2略有不同,在<h2>标签上显示和输入的是相同的,不过依然被HTML实体化,而在<form>标签上显示的没有<>
使用Level 2的payload
1  | <?php  | 
可以看到str3是被过滤掉<>的,不过由于使用的on事件,而且本身在标签内部,所以不需要使用<>
Level 5
测试显示效果
使用Level 2的payload
on事件被过滤为o_n O_o
使用javascript:alert(/xss/)绕过
payload
1  | <?php  | 
查看代码,发现不仅过滤了on,还过滤了<script,不过str3没有进行HTML实体化转义
Level 6
测试显示效果
两个输出点的<>都被HTML实体编码
测试on事件
使用"闭合,on被过滤为o_n
测试javascript:alert()
这里href也被过滤了,变成了hr_ef。有个奇怪的地方,刚才测试显示效果时<>被转义掉,但这次并没有被转义掉
被过滤掉的还有src、script
然后发现大小写可以绕过,明明前面都不能绕过的
payload
1  | <?php  | 
查看代码发现<script、on、src、data、href都被过滤,但是并没有strtolower()函数过滤大小写
Level 7
测试显示效果
这次使用带<Chessur>测试显示效果,发现变成小写了
测试on事件
发现下面的on被过滤为空
尝试双写绕过
1  | <?php  | 
查看代码,这一关又有大小写过滤了….
将关键词替换为空,所以双写直接绕过
Level 8
看起来像DOM型XSS
测试显示效果
这次有2个输出点,一个是<form>标签里,一个是在<a>标签里
查看过滤情况
发现on、script、src都被过滤掉了,而且大小写无法绕过
由于输出点在href属性中,所以使用<a href=javascript:alert()</a>使用
来绕过过滤
payload
1  | <?php  | 
查看代码,script、on、src、data、href、"都被过滤掉了
Level 9
测试显示效果
使用了新的测试payload
1  | ";!–'<CheSSur>=&{(OnonSrcsrcscriptScRIPt)}  | 
大小写转为小写,没有过滤,有HTML实体编码转义
在href标签处会判断链接是否合法
判断链接是否合法的规则是输入中是否有http://
使用Level 8的payload加上//http://
1  | <?php  | 
查看代码发现和Level 8基本相同,在下面添加了判断URL是否合法的规则,不过由于使用的是strpos()函数,只判断字符串中是否出现过字符,而没有判断出现位置,所以可以添加到行尾,使用注释符注释掉进行绕过
Level 10
测试显示效果
进行了HTML实体化编码转义,对on、src、script进行了过滤
但是在<h2标签下面有隐藏的<form>标签,测试发现只有t_sort可以被更改type显示出来
payload
1  | <?php  | 
查看代码,发现t_sort接收从页面传来的值,过滤掉了<>,使用on事件绕过
Level 11
测试显示效果

和Level 10类似,都有隐藏的<form标签
从Level 10跳转来会看到Referer,直接打开并没有

使用FireFox浏览器无法修改为Payload,用BurpSuite抓包修改Referer

Forward

1  | <?php  | 
查看代码
$str11获取Referer,过滤掉了<>,再输出到t_ref
Level 12
直接用Firebug审查元素

看到了<input name="t_ua" value="Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0" type="hidden">
用BurpSuite抓包修改UserAgent

Forward

1  | <?php  | 
查看代码
$str11获取User Agent,过滤掉<>再输出到t_ua
Level 13
Firebug审查元素

看到t_cook
使用BurpSuite抓包

Forward

可以看到t_cook的值是Cookie中user的值
抓包修改Cookie

Forward

1  | <?php  | 
$str11获取Cookie中的user,过滤掉<>再输出到t_cook
Level 14
使用Firebug审查元素

发现iframe标签,连接到http://www.exifviewer.org
以为要通过注入修改iframe标签,但查了一下是要上传xss图片到这个网页上,解析之后弹窗
开了纸飞机之后,页面加载成功

恶意图片

上传图片页面

Upload

1  | <html>  | 
查看代码没有任何输入点,只能访问http://www.exifviewer.org
原理是修改图片的exif信息,在解析器解析图片exif时触发XSS。

未加载的图片都是XSSpayload
Level 15
测试显示效果

好像没有输出…
页面加载了一个JavaScript脚本

在页面源代码里看到输出点

查了一下ng-include:,发现可以包含一个页面
包含一下第一关的Payload

1  | <?php  | 
好像Firebug对未加载的标签并不显示,因为没有1.gif这个文件,所以只能在源代码里查看
ng-include包含的文件需要用引号括起来
Level 16
测试显示效果
1  | ";!–'<CheSSurOnonSrcsrcscriptScRIPt>=&{()}  | 

script被过滤为空格,空格被转义为 ,大小写被过滤,src和on未被过滤,用<img>标签测试

发现/也被过滤成空格
使用%0a、%0c、%0d绕过空格检测

1  | <?php  | 
查看代码,script、、/都被过滤为 
Level 17
测试显示效果

闭合src

1  | <?php  | 
查看代码,发现2个变量都被HTML实体化编码转义,使用on事件可以绕过
Level 18
测试显示效果

闭合src

1  | <?php  | 
查看代码,发现和Level 17的代码区别在于引用了不同的文件,在过滤上并没有改动,所以Level 17的Payload依然可以用
这两关看起来像Flash XSS,但其实只是简单的注入
Level 19
这关真的是考察Flash XSS,并不懂怎么反编译flash,而且现在flash用的也少了,学习的价值并不高,忘记在哪里看到一句话
两年内用不到的知识,并不需要去学习。
两年后会被淘汰的知识,也不需要去学习。
这里只放上Payload From:XSS挑战之旅–游戏闯关
1  | ?arg01=version&arg02=<a href="javascript:alert(1)">123</a>  | 
Level 20
同Level 19
只放上Payload From:XSS挑战之旅–游戏闯关
1  | ?arg01=id&arg02=\%22))}catch(e){}if(!self.a)self.a=!alert(1)//%26width%26height  | 
总结
1.使用on事件绕过<>的转义 Level 2
2.使用javascript:alert()绕过对on事件的过滤 Level 5
3.测试不应该跳过任何一步,XSS挑战的难度设计并不是线性增加的,有时上一关无效的payload,可能下一关就有用了 Level 6
4.输出点在<a>标签中,可以使用<a href=javascript:alert()</a>绕过 Level 8
5.使用
等制表符来绕过过滤 Level 8
6.判断输入是否合法,可以根据函数特性绕过,如strpos()函数 Level 9
7.查看源码是个好习惯,希望我有 Level 10
8.修改referer、user agent、cookie注入xsspayload Level 11,Level 12,Level 13
9.有时Firebug不会显示某些元素,还是要多看源码 Level 15
10.ng-include包含的文件需要用引号括起来 Level 15
11.使用%0a、%0c、%0d绕过空格检测 Level 16
12.看起来像A,但要试过才知道是不是 Level 17 Level 18
感受
XSS Challenge并不像Sqli-Lab难度是递增的,有的关卡使用相同Payload都可以过去,不过还是学到了很多新的姿势。感谢作者做了这个挑战,也感谢各个写了WriteUp的大佬,学到很多新的姿势。
参考
[1] 某xss挑战赛闯关笔记
[2] XSS挑战之旅–游戏闯关