PyxYuYu/MyBlog

XSS(一)

PyxYuYu opened this issue · 0 comments

A goal is a dream with a deadline.

0x01 XSS

  • 反射型XSS
    • 非持久化,需要欺骗用户自己去点击链接才能触发 XSS 代码,服务器中没有这样的页面和内容
    • 目前多数主流浏览器都有 XSS 过滤器(测试一般用 IE6IE7,或者更高级的手动关闭 XSS 筛选),所以常规的 反射型XSS 一般会被过滤,需要绕过
    • 在防范这类 XSS 时,通常可以在服务器段对传入的参数进行过滤,来防范这类攻击
  • DOM型XSS
    • DOM-based XSS 是基于文档对象模型 Document Object Model 的一种漏洞
      • DOM 是一个与平台、编程语言无关的接口,它允许程序或脚本动态地访问或更新文档内容、结构、样式,处理后的结果能够成为显示页面的一部分
      • DOM 中有很多对象,其中一些是用户可以操纵的,比如 form、referrer、location
      • 客户端的脚本程序(JavaScript)可以通过 DOM 动态地检查和修改页面内容,它不依赖于提交数据到服务器端,而从客户端获得 DOM 中的数据在本地执行
      • 如果 DOM 中的数据没有经过严格确认,就会产生 DOM-based XSS 漏洞
    • DOM型XSS 输入点(即可能之后导致发生 XSS 的前提)-- JavaScript
      • location
        • location.href
        • location.search
          • IE 没有将 <> 进行 URL 编码
        • location.hash
        • location.pathname
      • window.name
      • document.cookie
      • localStorage
      • document.title
      • getAttribute
      • document.referrer
      • innerText
      • .value
      • .dataset
      • postMessage
        • 使用 \ 绕过初始检测
      • innerHTML
    • DOM型XSS 触发点(即可插入 XSS 代码处) -- JavaScript
      • location
        • location='javasc&#114ipt&#58alert&#40~1&#41'
      • eval
      • innerHTML
      • document.write
      • appendChild
      • Function
      • setTimeout
      • setInterval
      • createElement
        *
           with(document)body.appendChild(createElement('iframe onload=&#97&#108&#101&#114&#116(1)>'),body.innerHTML+="(IE)
        
    • 显示输出
      • URL 提交后,右键查看源代码可以看到输出的内容
      • innerHTML
         <div id="a">xxx</div>
         <script>
             document.getElementById("a").innerHTML="yyyy";
         </script>
      
      • innerHTML="[输出]",可以通过 JS 脚本改变 a 的值
        • [输出] 这里只能使用 <img src=1 onerror=alter(1)> 这种方式来触发 JS
        • 不能使用 <script>alert(1)</script> 来触发
        • IE 下可以使用 <script defer>alert(1)</script>
      • < 被过滤的话,可以使用 \u003c、\x3c 代替
      • > 被过滤的话,可以使用 \u003e、\x3e 代替
      • 空格可以使用 \u0020 代替
      • 所以上面的 Payload 可以写成 \x3cimg\u0020src=1\u0020onerror=alert(1)\x3e
      • 除了 innerHTML 只要与改变页面 HTML 内容相关的操作,都可能导致这种问题
      • 除了 JS,一些使用了第三方库,譬如 jQuery 也会: $("#x").html("yyyy")
    • 隐式输出
      • 输出操作在查看源代码中无法看见,通常发生在 JavaScript 代码中
        • 比如:var x=location.href;
        • JavaScript 进行了一个隐藏的输出操作,将 location.href 的内容输出到了变量 x
      • location.href
         function getParam(name){
             var x = locaton.search; //或者是 location.hash
             var v = x.match(new RegExp("[?&#]"+name+"=([^&]*)",""));
             return v?v[1]:"";
         }
      
      • 上面函数定义了一个利用正则匹配获取 URLname 参数后的参数值的方法
         <div id="nick">加载中...</div>
         <script>
             var a = getParam("name");  // 获取地址栏里的name参数值
             document.getElementById("nick").innerHTML = a;
         </script>
      
      • a 改写成 <img src=1 oneror=alert(1)> 即可触发 XSSa 就是从 getParam 函数通过 name 参数获得的参数值
      • Fuzz 步骤
        • 隐式输出,源代码中搜索不到参数值,F12 调试工具,搜索输出
        • 搜索到输出后,两种方法
          • 直接根据查看到的 HTML 代码,进行构造,注意闭合,注意过滤的情况
            • 优点:省时
            • 缺点:有过滤的情况,会比较难闭合
          • 查看 JavaScript 代码,寻找对应的函数,分析函数,是否进行了过滤,编码,解码,如果先编码,后解码,就等同于没有过滤
            • 优点:明白逻辑,可以进行复杂构造
            • 缺点:费时
        • 注意: Chrome 浏览器会自动对 "、>、< 进行转义成 %22、%3c、%3eIE 不会
    • eval
      • 显示输出隐式输出 最终 JavaScript 都会通过 document.writeinnerHTML 将内容输出到网页中,所以总是有办法可以查看到输出到哪里,但是如果没有通过它们,而是通过函数,利用 eval 来进行输出,就无法通过源代码或者 F12 调试工具查找
         var getarg = function()
         {
             var url = window.location.href;
             var allargs = url.split("?")[1];
             if (allargs!=null && allargs.index0f("=")>0)
             {
                 var args = allargs.split("&");
                 for(var i=0; i<args.length; i++)
                 {
                     var arg = args[i].split("=");
                     eval('this.'+arg[0]+'="'+arg[1]+'";');
                 }
             }
         }
      
      • 上面函数是获取 URL,之后将参数分割,分割后执行 eval
      • 如果这里 arg[0] 或者 arg[1] 可控的话,就可以插入 XSS 代码,导致漏洞产生
      • 原来的 eval 应该执行
         eval('this.a="bbb";')
      
      • arg[0] 就是 aarg[1] 就是 "bbb"
      • 修改 arg[0] 构造 XSS,即
         eval('this.a;alert(1);//="bbb";')
         // 需要加上等号,因为上面的代码逻辑是根据等号来分割,注释掉后面即可
         // arg[0] 为 a;alert(1);//
         // www.xxx.com/1.html?a;alert(1);//=bbb
      
      • 修改 arg[1] 构造 XSS,即
         eval('this.a="bbb";alert(1);//"')
         // " 是代码后面加上的,所以这里需要自己闭合前面的双引号,后面的双引号可以注释掉
         // www.xxx.com/1.html?a=bbb";alert(1);//
      
      • 注意:修改 arg[1] 这里自己闭合了双引号,在 Chrome 中双引号会被主动过滤,所以只有在 IE 下才会成功
    • iframe
      • <iframe src="[输出]"></iframe>
      • iframesrc 属性本来应该是一个网站,但是 iframe 可以使它同样可以执行 JavaScript,而且可以使用不同的姿势来执行,这一类问题,可以归为 [路径可控] 问题
      • onload 执行 JS
         <iframe onload="alert(1)"></iframe>
      
      • src 执行 JS
         <iframe src="javascript:alert(1)"></iframe>
      
      • IEsrc 执行 vbscript
         <iframe src="vbscript:msgbox(1)"></iframe>
      
      • Chromesrc 执行 data 协议
         <iframe src="data:text/html,<script>alert(1)</script>"></iframe>
         // 转义
         <iframe src="data:text/html,&lt;script&gt;alert(1)&lt;/script&gt;"></iframe>
      
      • Chromesrcdoc 执行 JS
         <iframe srcdoc="&lt;script&gt;alert(1)&lt;/script&gt;"></iframe>
      
      • Fuzz 步骤
        • F12 调试工具,查看有无可见输出
        • 查到参数被带入到 <iframe src="[参数]"></iframe> 之中
        • 查看相关函数,是否有一些过滤
           function OpenFrame(url) {
               if (url.toLowerCase().indexOf('http://') != '-1' || url.toLowerCase().indexOf('https://') != '-1' || url.toLowerCase().indexOf('javascript:') != '-1') return false;
                   document.getElementById("toolframe").src = url;
           }
        
        • 上面函数过滤了 http:// https:// javescript:
        • document.getElementById("toolframe").src = url; 这里导致了执行 XSS
        • url 参数可控制,过滤不完善,所以
          • IE 下,可以使用 vbscript 来执行代码,vbscript' 单引号表示注释,类似 JS 中的 //
             http://www.xxx.com/1.html?url=vbscript:msgbox(1)'&gid=yl
          
          • Chrome 下,可以使用 data 协议来执行 JS
             http://www.xxx.com/1.html?url=data:text/html,<script>alert(1)</script>//
          
    • 路径con
      • 同域的时候,可以使用 AJAX 动态地加载 json 数据,而有时候,数据所在域和当前页面所在域不同,所以需要跨域请求,跨域请求数据中,有一种方法叫做 JSONP
        • 用代码表示的话,就是
           somescript.src="http://otherdomain.com/xx?jsonp=callback"
        
        • 有时,程序员会在调用外部数据的时候带上可控的参数,这个可控参数就可能导致 XSS
           somescript.src="http://otherdomain.com/xx?jsonp=callback&id="+id;
        
      • 跨域请求
        • JSON 是一种基于文本的数据交换格式,或者称为数据描述格式
          • JSON 只有两种数据类型描述符,大括号和方括号,其余冒号是映射符,逗号是分隔符,双引号是定义符,对象表示为键值对
        • JSONPJSON with Padding
          • JSONPJSON 的一种使用模式,可以让网页从别的域名获取资料,即跨域读取数据
          • 由于同源策略的限制,XmlHttpRequest 只允许请求当前源(域名、协议、端口)的资源,为了实现跨域请求,可以通过 script 标签实现跨域请求,然后在服务端输出 JSON 数据并执行回调函数,从而解决跨域的数据请求
          • Web 页面上调用 JS 文件不受是否跨域的影响,不仅如此,凡是拥有 src 这个属性的标签都拥有跨域的能力,比如 script、img、 iframe
          • JSONP 协议允许用户传递一个 callback 参数给服务端,然后服务端返回数据时会将这个 callback 参数作为函数名来包裹住 JSON 数据,这样客户端可以随意定制自己的函数来处理返回的数据(动态执行回调函数)
      • 跨域请求 src 地址可控可以分为三种
        • script src="[完全可控]"
          • 直接将地址换为 JS 地址
        • script src="/path/xxx/[路径可控]/1.js"
          • 路径可控,被利用的话,需要同域名下有可控的文件,可控文件分两类
            • 直接上传文本至同域名下,不一定要是 HTML 文件,需要上传点有过滤缺陷
            • 参数可控,利用可用的 JSON 接口
          • 最终变为 script src="/path/xxx/.../yyy/xx.json?callback=alert(1)"
        • script src="/xxxx/json.php?callback=xxxx&param1=yyy&param2=[参数可控]"
          • 类似上面的参数可控,如果参数可控,且 JSON 的参数没有做好过滤,就可以导致 XSS
      • Fuzz 步骤
        • F12 调试工具,刷新查看是否有加载外部 JS 文件
        • 修改原始 URL 中参数值,查看是否有参数被传入到外部 JS 文件中
        • 有参数传入的话,打开这个 JS 文件地址,修改地址内参数,查看哪些参数可控
        • 判断可控参数是否过滤 < > ,
        • callback 参数可控,且未被双引号包裹,所以这里可以构造
           http://xxx.xxx.com/comm.json?callback=alert(1);
        
        • 将原始页面调用上面的 JS 文件即可导致 XSS
        • callback 参数可以从之前探测出的传入到外部 JS 文件中的参数一起带入
        • 即将原始 URL 中的参数 param=xx 修改为 param=xx&callback=alert(1); 覆盖掉外部 JS 文件中的 callback
        • & 也可以写成 %26
        • 查看函数,明白参数是如何传递到 comm_json 接口
           var keyword = decodeURIComp($getQuery('keyword')),
        
        • 此处 decodeURIComp 解码,即 & 会变成 %26,便不是连接符了
        • 所以,最后应该为 %26 即:
           http://yyy.xxx.com/1.html?keyword=1%26callback=alert(1);&PTAG=2005.13.1
        
    • DOM型XSS 总结
      • 修改参数值,查看源代码,调试工具,是否有改变
      • 如果有,查看是否存在过滤 <、>、"、'
      • 查看参数值外是否有 DOM型XSS 的触发点
      • 如果有,根据上下文,尝试闭合语句,字符也可以用 Unicode 编码替换(此处需要 \ 未被过滤)
      • 构造完整 Payload
  • 存储型XSS
    • 存储型需要进入数据库,输出可能出现在任何用到数据的地方,不一定出现在输入的位置,输入大部分来自 POST/GET 请求
    • Fuzz 思路
      • 先找到输出点,猜测此处输出是否会被过滤
      • 如果觉得可能没过滤,再找这个输出是从哪输入的
      • 开始测试输入,看输出效果
      • 如果没过滤,那么 存储型XSS 成功
    • 富文本
      • 很多应用含有富文本内容,最典型的特性是具有编辑器,这类应用往往允许使用一定的 HTML 代码,为了在用户体验和安全之间寻找平衡,一般有两种方法
        • 白名单
          • 只允许使用白名单内的合法 HTML 标签
        • 黑名单
          • 厂商构建一个有危害的 HTML 标签、属性列表,通过分析用户提交的 HTML 代码,去除其中有害的部分
      • 黑名单这种方式往往会被绕过,白名单则安全的多
      • 通过抓包的方式,修改抓包内容,插入 XSS 代码,提交修改后的数据包,查看 XSS 代码是否被过滤
  • FlashXSS
    • FlashActionScript 脚本目前网络上存在两种版本,即 2.03.0
    • 利用 Google 搜索
      • site:xx.com filetype:swf inurl:下面的关键词
      • 已知存在缺陷的 Flash 文件名或参数名:如 swfuploadjwplayer
      • 多媒体功能的 Flash 文件名:如 uploadplayermusicvideo
      • 调用的外部配置或数据文件后缀:如: xmlphp
      • 前期经验积累下来的程序员特征参数名用词:如: callbackcbfunction
    • Flash 缺陷参数
      • Flash 提供相关的函数,可以执行 JS 代码
        • getURL(AS2)
        • navigateToURL(AS3)
        • ExternalInterface.call