zoukankan      html  css  js  c++  java
  • 危险的文件夹上传框

    分享一篇老文章。前些年在 ASRC 上的看了一篇文章「Html5新功能上的ui-redressing」后,写的一些改进方案。


    文件对话框

    文件上传对话框是一直以来就存在的网页控件。

    到了 HTML5 时代,增加了更多的功能,例如支持文件多选。Chrome 甚至还支持「上传文件夹」这一私有特征:

    <input type="file" webkitdirectory />
    

    在给用户方便的同时,其安全隐患也逐渐出现。用户平时在下载时,理所当然的弹出的是保存对话框,因此常常不仔细看就做出了选择。

    这极有可能被攻击者所利用。一些恶意网站在用户点击下载时,故意弹出一个上传对话框。只要用户一疏忽,就把选中的文件夹给上传了!

    下载对话框

    上传对话框

    当然,仅仅依靠默认的上传,这种攻击方式仍有较大难度。因为整个文件夹可能非常大,上传需要很久的时间。

    如果用户等了半天也没看见下载进度,或许就会刷新重试,甚至放弃了。

    选择即授权

    然而,HTML5 带来了一个新的规范 —— File API,允许脚本访问文件。

    但由于沙箱限制,脚本无法访问任何一个本地文件,除非用户主动授权。如何授权?最常见的,就是「上传对话框」了。

    事实上,如今的上传对话框,早已不是从前「选择哪个文件」的功能,而是「允许脚本访问哪个文件」的权限申请!只不过界面上没有提示罢了。

    例如,一个传统的文件上传控件。当用户选中文件后,即可通过 File API 读取文件内容:

    <input id="dialog" type="file" />
    <script>
        dialog.onchange = function(e) {
            var reader = new FileReader();
            reader.onload = function() {
                console.log(this.result);
            };
            reader.readAsText(this.files[0]);
        };
    </script>
    

    或许你已注意到,File 位于files[]而不是file,这正是给文件夹预留的!

    在 Chrome 里,上传控件只要加上 webkitdirectory 属性,就变成文件夹选择框。这时一旦用户选中某个文件夹,瞬间就赐予脚本访问整个文件夹的权限!

    <input id="dialog" type="file" webkitdirectory />
    <script>
        dialog.onchange = function(e) {
            var files = this.files;
            var table = {};
    
            for (var i = 0; i < files.length; i++) {
                var f = files[i];
                var dt = new Date(f.lastModified);
    
                table[i] = {
                    path: f.webkitRelativePath,
                    size: f.size,
                    modified: dt.toLocaleString()
                };
            }
    
            console.table(table);
        };
    </script>
    

    演示

    于是,用户本想将文件保存在桌面上,结果却将桌面上的所有资料,被攻击者的脚本拿到!

    优化上传

    一旦脚本可主动访问,我们可以用更灵活的方式处理这些文件,无需再用传统落后的方式上传。我们可以直接在前端分析出「有价值」的文件,例如:

    • 备注文件、脚本、批处理、电子表格等,很可能存有一些敏感信息,而且体积小价值大,优先将其上传;

    • 图片则可通过 canvas 缩放,先传较小的缩略图。当接收端发现有意义时,再传输原文件。

    • 对于一些体积较大但意义不大的文件,则可以直接忽略。

    由于 HTTP 上传是没有压缩的,因此在传输文本文件时效率很低。我们可以借助 Flash 内置的LZMA压缩算法,极大提升传输效率。如果不支持 Flash,也可以使用asm.js版的 LZMA 压缩器,配合Worker线程在后台压缩和传输。

    同时,将多个小文件合并后再压缩,可进一步提高压缩率。再多开几个连接,上传速度即可大幅提升。

    续点上传

    不过即使再优化,仍有传不完的可能。因此,我们得将没传完的内容储存起来,当用户再次回来时,继续传输。

    得益于 HTML5 的 Storage API,这不难实现。

    事实上,当用户授权了某个文件夹时,我们首先要做的不是发送,而是读出文件夹内容,立即备份到 Storage 里。毕竟,文件的读取需要用户主动配合,机会是非常珍贵的;而 Storage 的访问则无需任何条件。

    当备份完成后,再从 Storage 里一块一块的读取、发送、删除。这样,即使中途页面刷新或关闭了,下次回来时,仍能从 Storage 中继续。

    考虑到每个域的 Storage 容量有限,我们可以使用iframe嵌入多个不同域的页面,然后通过postMessage进行数据的分发和汇总,这样就不受容量限制了。

    当然,能不能无限容量还得看浏览器策略,不然硬盘会被撑满

    将数据存放在 Storage 里还有另一个好处,即使用户永不回来,但数据仍持久保存着。只要以后一旦进入其他的站点,只要是我们可控的,仍有机会继续上传。(例如将用户引到我们布置了 XSS 的站点上)

    延长上传

    在之前《延长 XSS 生命期》 中介绍过,可以使用各种黑魔法来提升脚本有效期。

    利用这个原理,即使当前页面关闭,其他关联的页面也能继续上传。事实上,除了文中提到的方法,如今还有一个新的 API —— SharedWorker,它可以让 Worker 共享于多个页面,只要有一个存在,线程就不会停止。可以让续点时丢失的数据更少。

    视觉欺骗

    由于上传控件有着独特的界面,怎样才能让用户不小心点到呢?万能的方法是点击劫持(Clickjacking)。

    不过本场景无需这么麻烦,只需简单的调用控件的click方法就可以了。

    <a href="ed2k://|file|xxx.avi" id="download">高速下载</a>
    <script>
        var uploader = document.createElement('input');
        uploader.type = 'file';
        uploader.webkitdirectory = true;
    
        download.onclick = function(e) {
            uploader.click();       // 弹出上传对话框
            e.preventDefault();     // 屏蔽下载对话框
        };
    </script>
    

    演示

    我们屏蔽超链接的默认行为,用上传控件的点击事件取而代之,即可召唤出「文件夹授权」对话框了!

    同时,为了不让眼亮的人发现对话框上的破绽,我们使用一些第三方的下载方式,例如电驴、迅雷等等,让人们误以为就是这样的。

    当然,这只是一个小例子。只要页面做的真实,下载内容引人入胜,用户自然就会中招。

    后记

    本以为 webkitdirectory 的这个私有属性很快就会放弃,至少是更强的安全提示。不过至少现在也没更新,因此上网时还是要多加留心,看清楚了再做决定。

    当然,这篇只是最早的「交互欺骗」探索。事实上,深入挖掘会发现可利用点远不仅此。

    如今的浏览器在视觉、音频上的体验已经非常完善,攻击者甚至可以在网页里,高度模拟一个本地应用的交互效果。让用户误以为是浏览器之外的程序弹出的界面,从而进行钓鱼。

  • 相关阅读:
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31
    知也atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31无涯 - I
  • 原文地址:https://www.cnblogs.com/index-html/p/dialog-phishing.html
Copyright © 2011-2022 走看看