Portswigger web security academy:DOM-based vulnerabilities
DOM-based vulnerabilities
目录- DOM-based vulnerabilities
- 1 - DOM XSS using web messages
- 2 - DOM XSS using web messages and a JavaScript URL
- 3 - DOM XSS using web messages and JSON.parse
- 4 - DOM-based open redirection
- 5 - DOM-based cookie manipulation
- 6 - Exploiting DOM clobbering to enable XSS
- 7 - Clobbering DOM attributes to bypass HTML filters
材料里没列完,直接做题吧
1 - DOM XSS using web messages
-
题目描述
- 这个lab有一个简单的web-message漏洞
-
要求
- 利用exploit server给网站发送一个信息,使其执行
alert(document.cookie)
- 利用exploit server给网站发送一个信息,使其执行
-
解题过程
-
查看源码,发现如下代码
window.addEventListener('message', function(e) { document.getElementById('ads').innerHTML = e.data; })
-
去MDN看了下web message,是一个跨源通信的函数,可以通过
iframe
来实现这个功能 -
构造exp
- 先尝试了用
iframe
+script
标签的形式,但是发现script
标签不会等iframe
加载完,所以放进了iframe
中 postMessage()
的第二个参数使用通配符,允许目标站点为任意域(防止CORS被阻止)- 关于post进去的数据也进行了尝试(chrome),
svg,script
都不行,想了一下应该与标签的解析流有关(插入的标签没有被解析),这里用img
- 先尝试了用
-
2 - DOM XSS using web messages and a JavaScript URL
-
题目描述
- 此lab存在DOM-based跳转漏洞(通过web message诱发)
-
要求
- 构造页面,使访问者执行
alert(document.cookie)
- 构造页面,使访问者执行
-
解题过程
-
还是先找代码
window.addEventListener('message', function(e) { var url = e.data; if (url.indexOf('http:') > -1 || url.indexOf('https:') > -1) { //传入的url包含http(s): location.href = url;// 跳转 } }, false);
-
弹窗可以通过伪
javascript
伪协议调用let url = 'javscript:alert()-"http:"'; location.href = url; // 但是这样不好写进去,因为单双引号(所以需要借助编码环境进行编码,事件内部是js解析环境,会先进行unicode解码,所以可以进行编码 this.contentWindow.postMessage('javascript:alert(document.cookie)-"http:"',"*")
-
-
构造exp
-
3 - DOM XSS using web messages and JSON.parse
-
题目描述
- 此lab使用了
web messageing
并把消息当作json解析
- 此lab使用了
-
要求
- 构造页面,使访问者执行
alert(document.cookie)
- 构造页面,使访问者执行
-
解题过程
-
先看代码
window.addEventListener('message', function(e) { var iframe = document.createElement('iframe'), ACMEplayer = {element: iframe}, d; document.body.appendChild(iframe); try { d = JSON.parse(e.data); } catch(e) { return; } switch(d.type) { case "page-load": ACMEplayer.element.scrollIntoView(); break; case "load-channel": ACMEplayer.element.src = d.url; // 如果d.type=="load-channel",则讲url赋给iframe break; case "player-height-changed": ACMEplayer.element.style.width = d.width + "px"; ACMEplayer.element.style.height = d.height + "px"; break; } }, false);
-
构造exp
- 这里需要用
JSON.stringify()
把json转换成字符串,不能直接传输对象
- 这里需要用
-
4 - DOM-based open redirection
-
题目描述
- 此lab有一个DOM型的url跳转漏洞
-
要求
- 把受害者拐进exploit server
-
解题过程
-
点进一个详情页面,发现返回链接比较特殊
Back to Blog
- 把
location
(地址栏里全部的东西,包括#
后面的内容)用正则url=(https?:\/\/.+)
匹配,如果能匹配到,就跳转到匹配到的url
- 把
-
构造exp
- 这块想了半天,把受害者拐进exploit server需要点击按钮,总不能继续xss吧,然后去看了solution,自己就是受害者???
- 第二个,使用
#
也可以达到目的,但是不给过,只能用&
(猜测后端通过检测url
参数判断)
https://ac891f911e4e7dcb80201fd4009d0060.web-security-academy.net/post?postId=4#url=https://acc61fdf1e577d2480831f0b019e002b.web-security-academy.net solution: # -> &
-
5 - DOM-based cookie manipulation
-
题目描述
- 此lab存在DOM型客户端cookie修改
-
要求
- 插入一个可以实现XSS(弹cookie)的cookie
-
解题过程
-
在商品详情页面看到如下代码
document.cookie = 'lastViewedProduct=' + window.location + '; SameSite=None; Secure'
可以通过
&
/#
插入内容 -
在主页,发现在访问过之后,会出现浏览记录,而且会被
'
逃逸'>Last viewed product 之前访问的是https://aca21f141f41e76480123c5f005500d9.web-security-academy.net/product?productId=1#'-alert()-'>
-
构造exp
-
6 - Exploiting DOM clobbering to enable XSS
-
题目描述
- 评论功能点允许安全的HTML
-
要求
- 构造HTML注入,污染(clobber)变量?,调用
alert()
- hint:预期解只在chrome有效
- 构造HTML注入,污染(clobber)变量?,调用
-
解题过程
-
在详情页面看到函数调用
loadComments('/post/comment')
,看看函数定义function loadComments(postCommentPath) { let xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { let comments = JSON.parse(this.responseText); displayComments(comments); } }; xhr.open("GET", postCommentPath + window.location.search); xhr.send(); function escapeHTML(data) { return data.replace(/[<>'"]/g, function(c){ return '' + c.charCodeAt(0) + ';'; }) } function displayComments(comments) { let userComments = document.getElementById("user-comments"); for (let i = 0; i < comments.length; ++i) { comment = comments[i]; let commentSection = document.createElement("section"); commentSection.setAttribute("class", "comment"); let firstPElement = document.createElement("p"); let defaultAvatar = window.defaultAvatar || {avatar: '/resources/images/avatarDefault.svg'} let avatarImgHTML = ''; let divImgContainer = document.createElement("div"); divImgContainer.innerHTML = avatarImgHTML if (comment.author) { if (comment.website) { let websiteElement = document.createElement("a"); websiteElement.setAttribute("id", "author"); websiteElement.setAttribute("href", comment.website); firstPElement.appendChild(websiteElement) } let newInnerHtml = firstPElement.innerHTML + DOMPurify.sanitize(comment.author) firstPElement.innerHTML = newInnerHtml } if (comment.date) { let dateObj = new Date(comment.date) let month = '' + (dateObj.getMonth() + 1); let day = '' + dateObj.getDate(); let year = dateObj.getFullYear(); if (month.length < 2) month = '0' + month; if (day.length < 2) day = '0' + day; dateStr = [day, month, year].join('-'); let newInnerHtml = firstPElement.innerHTML + " | " + dateStr firstPElement.innerHTML = newInnerHtml } firstPElement.appendChild(divImgContainer); commentSection.appendChild(firstPElement); if (comment.body) { let commentBodyPElement = document.createElement("p"); commentBodyPElement.innerHTML = DOMPurify.sanitize(comment.body); commentSection.appendChild(commentBodyPElement); } commentSection.appendChild(document.createElement("p")); userComments.appendChild(commentSection); } } };
-
挨着看了一遍,感觉29、30行可能存在问题,但是不知道怎么利用
- 试了一下在提交参数的时候增加
avatar
,没有用
- 试了一下在提交参数的时候增加
-
放着先测一下能用哪些标签
-
a audio b big br button canvas center cite code datalist dfn del details filedset h1 hr i input ins kdb label li mark marquee meter optgroup progress q rp s samp select svg textarea u
-
有点多,挑一个最喜欢的svg测测
-
然后发现,返回的数据包是没有过滤的,过滤全部在前端的
DOMPurify.sanitize()
中进行 -
本以为这条路走不通了,然后在搜这个函数的时候看到一篇Bypass DOMPurify的文章
-
-
-