Исследование безопасности десктопных приложений на основе Electron

n1r0wxujrcya-xari75dsoabmia.jpeg

Electron — фреймворк с открытым исходном кодом для создания кросс-платформенных десктопных приложений с помощью JavaScript, HTML и CSS. Это крутая технология, но с ней связаны многие ИБ-риски.

В статье я разберу основы безопасной работы с этим фреймворком и расскажу:


  • как анализировать структуру десктоп-приложений на Electron и находить в них уязвимости;
  • какие распространенные ошибки допускают при работе с фреймворком и насколько он защищен.

Начнем с инструментов и методов, с помощью которых я провожу анализ кода приложений. Затем продемонстрирую конкретные примеры эксплуатации уязвимостей на примере специальных приложений-мишеней: DVEA, Electro-xxs и Notable.


Привет, Хабр! Меня зовут Александр, я работаю специалистом по информационной безопасности. Эта статья подготовлена на основе доклада, который я делал на программе стажировки, организованной компанией Бастион.

Atom, Visual Studio Code, WordPress Desktop, Github Desktop, Basecamp3, Mattermost — лишь несколько примеров приложений, созданных с использованием Electron. В основе фреймворка лежит сочетание Chromium (обеспечивает отображение контента с использованием HTML5, CSS3 и JavaScript) и Node.js (предоставляет среду выполнения для JavaScript, открывая разработчикам доступ к серверным функциям). Это дает фреймворку целый ряд преимуществ.

В то же время Electron наследует ряд проблем безопасности 1.97 256GB, характерных для обычных веб-приложений, и при этом обладает куда большими возможностями. Фреймворк имеет доступ к файловой системе, пользовательским скриптам и т. д. Взять, например, приложение, в котором есть несколько вкладок или окон. Возможен сценарий, когда вредоносный код выполняется на одной вкладке или в одном окне и приводит к негативным последствиям в других вкладках или приложениях.

Для решения этой проблемы в Electron используется мультипроцессорная модель. Она включает в себя два основных типа процессов:


  • Main Process, управляющий основными аспектами приложения;
  • Renderer Process, отвечающий за рендеринг содержимого в окнах приложения и выполнение кода JavaScript.

Разделение процессов обеспечивает изоляцию и независимость между различными компонентами приложения, что повышает уровень безопасности и предотвращает нежелательное взаимодействие между вкладками. По сути, main process может создавать renderer process, обеспечивая тем самым контролируемую и безопасную среду выполнения для каждого окна.

or3k4kziyjfjjjgto037di3u-f8.png

eca68vr7fn6wupqr85_inx-1w_a.png

Примерно так выглядит связь между renderer process и окном браузера в Electron:


  1. Renderer Process загружает и отображает страницу или HTML-контент в окне приложения;
  2. В окне браузера отображается визуальный интерфейс приложения (например, если стартовой страницей является index.html, в окне браузера будет выводиться содержимое из файла index.html).

usepyix7adei1h6ae_3pbbpwrzg.png
8flxiwlfbr7yg5ksux2r8hd05xw.png

Для гибкой настройки Electron существуют webPreferences — параметры, связанные с определением различных характеристик веб-страницы.

e8avb8lvaplbquhxa-4ourebiny.png
Пример webPreferences. nodeIntegration: true — страница имеет доступ к Node.js API

Среди них есть параметры, которые дают новые возможности для renderer process. Так, для nodeIntegration дает разрешение на использование Node.js внутри процесса отображения, а contextIsolation отвечает за управление прямым доступом к API Node.js из кода страницы. Посмотрите, как Electro-XSS меняет поведение в зависимости от настроек webPreferences.

Активный доступ к Node.js API, который дает nodeIntegration в сочетании с XSS в renderer process, открывает возможность для Remote Code Execution дистанционного выполнения кода, несмотря на мультипроцессорную модель Electron.
kjydrwungko3ug5mxmbc0yweq1u.png
nodeIntegration + XSS в renderer process = RCE

Для автоматизированного анализа кода и поиска подобных ошибок в Electron широко используют популярные статические и динамические анализаторы.

Однако существуют и менее известные, но более узкоспециализированные утилиты, как консольные, так и снабженные графическим интерфейсом.


Electronegativity

Этот инструмент предназначен для выявления неправильных конфигураций и антипаттернов безопасности в приложениях.

Мажорные релизы Electronegativity можно установить из хранилища пакетов NPM при помощи консольной команды: $ npm install @doyensec/electronegativity -g

Затем, чтобы проверить приложение на на наличие уязвимостей, введите: $ npm audit

Пример запуска сканирования: electronegativity -i DVEA

Electronegativity представляет структуру кода в древовидном формате и анализирует его иерархическую структуру, проверяет структуру веб-страницы (DOM) и формирует подробный отчет.

y7oepz0u11dhdtxzyt1ic1z2x5e.png

Кроме того, стоит обратить внимание на ElectroNG — специализированный сканер безопасности, разработанный создателями Electronegativity для проведения автоматизированных проверок.


NodeJsScan

Это бесплатный и открытый сканер статического кода. Он способен выявлять небезопасные паттерны в коде Node.js и HTML-шаблонах и предоставляет удобный веб-интерфейс для управления обнаруженными проблемами безопасности. Одно из его преимуществ — легкая интеграция с различными CI/CD конвейерами: Github Actions, Gitlab CI/CD, Travis и т. д.

wq_hq_cjthlmh0mt503o_1f3kl8.png

Запуск инструмента выглядит следующим образом:


  1. Загрузка последней версии образа Nodejsscan из Docker Hub.
    docker pull opensecurity/nodejsscan:latest
  2. Запуск контейнера (порт 9090) для веб-интерфейса Nodejsscan.
    docker run -it -p 9090:9090 opensecurity/nodejsscan:latest
  3. Переход на страницу Nodejsscan.
    http://localhost:9090

Протестируем Nodejsscan на примере уязвимого приложения Damn Vulnerable ElectronJS App (DVEA).

qryz_14ehfx17mbgnrx3p56oxkm.png

Сканер выдает развернутый отчет:

4q_kbswmzcm4yf8d3tvqm00l_is.png
dsqpmpgpjw8btkx4qg_s4wu0tvw.png

Выбрав интересующую нас уязвимость через Hide Code, можно получить детальную информацию, об ее особенностях:

hisfkkbf2mwknl1vq1t0du1qmss.png


Njsscan (CLI)

Этот статический анализатор обнаруживает уязвимости, при помощи сопоставления паттернов из библиотеки libsast.

Для установки введите команду: pip install njsscan

Njsscan использует семантический поиск шаблонов кода с помощью инструмента semgrep.

hbaolyoqtmf7sosickhgivp0iwm.png

Команды semgrep запускаются с различными конфигурациями (rulesets), которые определяют, какие конкретные проверки и тесты будут выполнены.


Например:

$ semgrep --config=r/javascript.browser.security.insufficient-postmessage-origin-validation.insufficient-postmessage-origin-validation --config=r/javascript.lang.security.audit.incomplete-sanitization.incomplete-sanitization --config=r/javascript.browser.security.dom-based-xss.dom-based-xss --config=r/typescript.react.security.audit.react-css-injection.react-css-injection --config=r/typescript.react.security.audit.react-href-var.react-href-var --config=p/owasp-top-ten __CODE_DIRECTORY__


Snyk CLI

Snyk представляет собой облачный инструмент безопасности, предназначенный для поиска потенциальных уязвимостей в коде приложения в режиме реального времени. Умеет он и обнаруживать ошибки в образах контейнеров Kubernetes, а также небезопасные конфигурации Terraform и Kubernetes.

Snyk CLI устанавливается при помощи npm: sudo npm install snyk@latest -g

Проверка работоспособности Snyk CLI выполняется через команду: snyk --help

Чтобы начать использовать Snyk CLI, необходимо произвести аутентификацию с помощью: snyk auth

Затем можно начинать сканировать проект:

s6iuyykeucyshg5hfswbym00ovs.png

Например, перейдем по ссылке со snapshot:

2a7r6obeus8zc-0axseyk4jtlzs.jpeg

Результат сканирования немного предсказуем:

xbo84d3xtmtsluxzdldiybw7kac.png

Попробуем другое демонстрационное приложение — Electro-XSS:

nm3rfzcsco0ag8lxbwhula2drpu.png

Здесь Snyk также находит уязвимости:
jwcifjtudi_afcxjxlfuzydxsqi.png

Общий порядок действий при тестировании десктопных Electron-приложений разбивается на три этапа.

Попробуем подробнее рассмотреть эту последовательность.


Декомпиляция

Ручное тестирование приложения начинается с распаковки файлов в формате .asar. Их можно обнаружить в каталоге resources. Если у вас установлен NodeJS, используйте команду npm, чтобы убедиться в корректности работы менеджера пакетов Node.

Для этого используйте команду npm install --engine-strict asar, которая отвечает за установку приложения asar при помощи менеджера пакетов npm.

cef0d2on4zlnuvm7fijjggibu3c.png

Команда npm install -g asar отвечает за установку asar глобально.

rqmtpnv_ddq6tjnli-wkgbidoge.png

С помощью команды asar extract app.asar app извлеките исходный код из архива.


Модификация и перекомпиляция

Если нужно модифицировать исходный код и применить изменения в момент запуска приложения, повторно упакуйте файл app.asar.

tdris8ewabpwgcwd27brcwf0g8y.jpeg

Я модифицировал функцию createWindow, добавив новую отладочную строку, как показано на скрине.

ubaym91rtj65ndt9-p6pogk0fgq.jpeg


Настройка каналов связи

Чтобы осуществить захват трафика и затем модифицировать какой-либо запрос в процессе работы приложения, потребуется настроить прокси через Burp Suite. Здесь можно действовать двумя путями.


  1. Проксирование на уровне ОС

    Такой подход полезен, когда вам нужно видеть HTTP/HTTPS-запросы, выдаваемые целевым приложением. В этом случае добавляется электронный аргумент командной строки. Если мы вернемся к функции createWindow, то увидим уже два примера:


e5z2ry3hsewqaqqbl3otzztuao0.png

createWindow — функция, показывающая commandLine.appendSwitch. В 58 строке находится уже добавленный переключатель: app.commandLine.appendSwitch('proxyserver','127.0.0.1:8080');
Далее папка app снова упаковывается в файл app.asar, и Electron загружает chromium (не забудьте установить сертификат CA certificate Burp, как показано здесь).

После настройки прокси вы увидите, как весь HTTP/HTTPS-трафик переходит в burp, и сможете заняться запросами на стороне сервера.


  1. Проксирование на уровне приложения

    Реализация этого подхода будет зависеть от архитектуры конкретного приложения и используемых в нем технологий. Рассмотрим процесс настройки прокси-сервера для перехвата трафика Windows-машины в Burp Suite.


Первым делом необходимо настроить системный прокси с помощью команды: netsh winhttp set proxy proxy-server="http=127.0.0.1:8080;https=127.0.0.1:8080" bypass-list="*.local"

Так вы установите системный прокси-сервер для HTTP и HTTPS трафика на адрес 127.0.0.1 (localhost) и порт 8080. Файлы *.local будут обходить прокси. Чтобы убедиться, что настройки были применены, выполните: netsh winhttp show proxy В выводе вы должны увидеть настроенные параметры прокси.

Затем убедитесь, что прокси-сервер в Burp Suite запущен и настроен на прослушивание того же порта (в данном случае, 8080).

seubzhknc0juxhkvr7oqphailds.jpeg

Экспортируйте сертификат Burp и откройте Консоль с помощью команды mmc.
r6coadchm6d9prbn0xl36xeq27u.jpeg

Перейдите в меню «Файл→Добавить/удалить оснастку…», а затем — в раздел «Сертификат → Добавить → Учетная запись компьютера → Далее».

lltq9wqwqa00syzsfel4p1zyw0y.jpeg

Выберите «Локальный компьютер», нажмите кнопку «Готово» и подтвердите выбор сертификата:

ofyvnfqpbfubntyeow97lh8zgeq.jpeg

Перейдите в раздел «Сертификаты → Все задачи → Импорт». Выберите путь к импортированному сертификату Burp и нажмите кнопку «Далее».

zvze5wa1ne65bl2tgh-asukl-mw.jpeg

Выберите «Разместить все сертификаты в следующих хранилищах» и нажмите кнопку «Далее». Нажмите «Finish».

sj5vi3hh0reczedhpv7iufeoela.jpeg

Наконец, убедитесь, что сертификат BurpSuite был установлен.

_mbu3lsc5ohzsq3adukj0z3vun4.jpeg

И запустите перехват трафика.

nuyxveardrhcirp0cx2ixb5oye8.jpeg

При разработке и тестировании приложений следует учитывать возможность возникновения целой россыпи различных проблем.

Рассмотрим некоторые из них подробнее


Cross Site Scripting

Этот вид атак представляет собой внедрение вредоносного кода в приложение. Cross-Site Scripting XSS-атаки на приложения на основе Electron в целом напоминают атаки на веб-приложения. Однако есть некоторые отличия в механизмах передачи вредоносного кода. Обозначим их.


  1. В десктоп-приложениях обычно отсутствует отдельная строка ввода URL, как в веб-браузерах. Как описано в разделе методологии, можно использовать DevTools Desktop-приложения для взаимодействия с API.
  2. Electron позволяет приложениям взаимодействовать с локальной файловой системой пользователя. Если входные данные из файловой системы недостаточно защищены, это может привести к возникновению патчей XSS.
  3. Работа с протоколами: Electron поддерживает основные протоколы (например, HTTP, HTTPS), а также позволяет создавать собственные протоколы. Если эти протоколы не защищены должным образом, они также могут стать причиной возникновения XSS-уязвимостей.

Эти атаки могут привести к краже данных пользователей, сеансов аутентификации, перенаправлению на вредоносные сайты, внедрению вредоносных скриптов и другим нежелательным последствиям. Предотвращение XSS включает в себя фильтрацию и экранирование ввода данных, использование безопасных API и регулярные обновления политик безопасности.

Запуск сценария эксплуатации процесса в поле ввода выглядит следующим образом:

Этот код будет выполняться в desktop-приложении пользователя, если оно некорректно обрабатывает или экранирует поступающие данные. В этом конкретном примере тег используется для вставки изображения, и при возникновении ошибки загрузки изображения (атрибут onerror) выполняется JavaScript-код alert (1), который отобразит диалоговое окно с сообщением »1».


XSS to RCE

Примеры payload’ов для RCE в данном контексте:


  • Для Linux и MacOS


  • Для Windows

В обоих случаях используется тег и событие onerror, которое вызывает require ('child_process').execSync () для выполнения команд в системном шелле. Подобные команды могут быть использованы злоумышленниками для выполнения произвольного кода на стороне клиента и создают серьезную угрозу для безопасности приложения.

Для защиты рекомендуется правильно настраивать политику безопасности контента (Content Security Policy, CSP) и ограничивать использование nodeIntegration.

Вот как это выглядит на практике:


Примеры полезных нагрузок для демонстрации возможного удаленного выполнения кода (RCE) через уязвимость XSS:
  • Пример payload для Windows:
  • Примеры payload’ов для Linux и MacOS:
    
    
    
    ```


Эксплуатация XSS и RCE на примере DVEA

Damn Vulnerable ElectronJS App — уязвимое приложение ElectronJS, разработанное специально для обучения ИБ-специалистов и разработчиков. Оно спроектировано так, чтобы демонстрировать основные уязвимости, характерные для среды ElectronJS.

Чтобы запустить DVEA, используйте следующую команду:

cd DVEA
npm i
electron .

Запуск с использованием npm:

npm install yarn
npm start

DVEA позволяет увидеть примеры уязвимостей, включая XSS. Например, внутри приложения можно использовать такой payload:

3idsllhaj4afjmkwdwv7mmxpi3a.jpeg

Этот код выведет окно с предупреждением, содержащим произвольный текст. Тут же, если ввести правильную полезную нагрузку в renderer process DVEA, можно реализовать RCE-атаку:

-4isruyfwagtof9asel8fqd2peu.jpeg


Демонстрация атак на примере Electro-XSS

Как следует из названия, это приложение-мишень предназначено уже для демонстрации уязвимостей на основе XSS.

cqa8kqlvyoohhlrg-f5kpzygalu.png

Посмотрим на сценарий эксплуатации XSS, когда нужно внедрить код JavaScript в поле ввода страницы. Такой код может использоваться для атак на пользователя, например, в целях кражи сессионных данных.

mm8wwyjmchxteez3-yvxeh-dto0.png

Запустим сценарий эксплуатации процесса: XSS:

ukomnxkzihmo-9cudvqysvmtzx4.jpeg

RCE: 

При выполнении этого JavaScript-кода запустится калькулятор GNOME. Такие сценарии могут использоваться для атак на приложение, особенно в случае, если параметр nodeIntegration установлен в true, что позволяет выполнять код Node.js в процессе отображения.


RCE на примере Notable

XSS-атаки позволяют злоумышленникам внедрять и запускать свой код на стороне клиента. Например, в случае использования Node.js в приложении, построенном на Electron, может возникнуть угроза удаленного выполнения кода RCE (Remote Code Execution). Пример XSS-пейлоада, с помощью которого можно внедрить в уязвимое приложение команду на запуск калькулятора:

xknq50iwslyrgfxzw5ge98nmomq.jpeg

При отсутствии фильтрации или ограничений ввода злоумышленник может внедрять произвольные команды в различные поля приложения. Например, использование команды ls позволяет просмотреть содержимое текущего каталога и получить дополнительную информацию о файловой системе.

kt_optsalmukdot6lj1vxlsvhw8.jpeg

Чтобы увидеть, как это происходит, на практике, запустим приложение Notable version 1.5.0 и введем полезную нагрузку.

otu6nzue3u4qawqvve_vopt2w9u.png

После выхода из режима редактирования автоматически запустится команда полезной нагрузки. Останется только произвести эксплуатацию уязвимости:

if_u-ehft5bvg-n-ccneeehkozi.png

Анализ логики работы десктопного приложения перед началом тестирования играет ключевую роль в оценке его безопасности.

Reversing Electron Application — это метод, направленный на получение доступа к исходному коду приложения, который дает возможность более глубокого и детального анализа. Построение методологии пентеста в значительной степени зависит от этого этапа, поскольку доступ к исходному коду позволяет определить поток работы приложения, выявить логические цепочки и понять его поведение и внутреннее устройство.

В конечном счете это ускоряет и облегчает поиск и анализ потенциальных уязвимостей.

8xfqhwqdcuoa2s4hvwfmsouzms0.png


Методология пентеста на примере Notable

Для того, чтобы попрактиковаться и провести детальное исследование, используем notable версии 1.5.0 и скачаем файл Notable-1.5.0.dmg и Notable-1.8.4.AppImage. Не забудьте дать права на использование этого приложения:

2aiiosb1c7pp-mhsbcb9ekbbcda.png

Смонтируем образ приложения (во временную папку):

gr7fut7akepoqvobntpnzk0utra.png

И откроем эту папку:

-7uo_xf09j_up3rpaa8st_vqioa.png

В этой папке уже можно видеть файлы и ресурсы приложения.

k3ut6put5jdtvxvy9hmogezbur4.png

Далее необходимо скопировать файл app.asar в рабочую папку и изменить формат файла .dmg (для этой цели подойдет приложение HFSleuth).

pmc6lmltubr_vmk8xtz5dqzkctg.png

Нам необходимо запустить эту программу с указанием двоичного файла Notable-1.5.0.dmg.

hmdjae3jy65yle2_4bc3qennyci.png

Найдем файл Notable.app.

le9rgcz3bgzeltyuj2impp8w43s.png

И попробуем войти в него.

knr7njsbgslvbj5gj8v7mffgwy8.png

Загрузим файл app.asar (архив, содержащий исходный код для electron-приложения), записав его во временную папку.

Command: asar extract app.asar dest-folder

Для того чтобы провести реверс-инжиниринг файла необходимо:

wimmek9wtwiaxnnj2gxhnchmuao.png
iolcn-nlppol7iplzy9tlksyplu.png

Файл будет извлечен в обратном порядке. Далее потребуется запустить Sublime-text, чтобы просмотреть содержимое файлов:

zlgtsw41vduebnw3nif6myjywzk.png

Если требуется найти уязвимые места в зависимостях, пригодится npm audit.

zprhv0sarl6yp7zu6w3z0_h05zy.png

Чтобы решить эту проблему, необходимо отключить блокировку пакетов:

m7ahf-40vr2kjfagkzsbhetxum8.png
2nmnqrvwhvywlmkorqm3pm_mjx0.png


  • package.json содержит различные метаданные, а также сведения о зависимостях и версиях;
  • The main process выступает в качестве точки входа в приложение;
  • Index.html — это фронтенд приложения.

    Методология пентеста на примере Electro-XSS

Теперь посмотрим на работу по анализу уязвимостей на примере Electro-XSS.

nogmypkcpzgyoosbatq2xwpqh78.png

Развернув приложение, запустим Sublime-text, чтобы просмотреть его файлы:

ocajcbbvuzp-e5kd_yol2wc3520.png

Здесь можно увидеть точку входа в приложение:

ddsiw6tmb08zlueifmqvs5emsfq.png

В файле package.json можно увидеть поле main и найти точку входа.

Мы уже знаем, что параметры webPreferences отвечают за настройку веб-страницы. Когда параметр nodeIntegration установлен в true, Node.js API становится доступен. Если в приложении существует уязвимость типа Cross-Site Scripting (XSS), успешная атака позволит злоумышленнику выполнить произвольный код на стороне клиента, осуществив Remote Code Execution (RCE). В таких случаях рекомендуется использовать contextIsolation вместе с preload для предварительной загрузки скриптов:

const mainWindow = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    contextIsolation: true,
    preload: path.join(__dirname, 'preload.js'),
  },
});

Для примера попробуем изменить параметр nodeIntegration на false:

ujv_vsejmr4sijxfrxj3bbf3bu0.png

npm install 
npm run eletro-xss

tn45nzeegllf8dcgv5jbaabx9gy.png

С помощью Ctrl+Shift+I откроем Devtools:

qfzyxkbz2ocvgx1funvz7y_adcw.png

И попробуем через консоль получить доступ к API интерфейсу узлов.

n4wyz7txqzdtlezwbrxzidsc90c.png

Поскольку получить доступ не удается, попробуем отключить приложение и использовать nodeIntegration, , а затем отправим команду на перезапуск. Наша задача здесь — вызвать API interfaces node, что позволит удаленно выполнять любой код (RCE):

dkbz_o1_-rjsmdc49ov_solc_ig.jpeg

Попытка успешна. Смысл такой интеграции узлов состоит в том, чтобы вызвать API interfaces node для эксплуатации RCE.

Для обеспечения безопасности Electron-приложений стоит строго следовать рекомендациям по безопасности из репозитория Electron на github.

Ключевые шаги включают:


  • значение nodeIntegration в false и contextIsolation в true;
  • валидацию ввода в полях форм;
  • контроль над процессом создания новых окон (или их блокировка, если они не нужны);
  • использование актуальной версии Electron.js;
  • проверку всех параметров безопасности, установленных по умолчанию (особенно при использовании сторонних фреймворков);
  • контроль интеграций с Node.js.

Дополнительной мерой может служить блокировка лишних привилегий, предоставленных приложению. Это уменьшит поверхность атаки и предотвратит нежелательный доступ к системным ресурсам.

© Habrahabr.ru