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挑战之旅–游戏闯关