mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/network-services-pentesting/pentesting-web/electron-des
This commit is contained in:
parent
09f5fec5d0
commit
08857072dc
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,3 +10,4 @@ scripts/*
|
||||
book
|
||||
book/*
|
||||
hacktricks-preprocessor.log
|
||||
hacktricks-preprocessor-error.log
|
||||
|
@ -7,7 +7,14 @@ from os import path
|
||||
from urllib.request import urlopen, Request
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(filename='hacktricks-preprocessor.log', filemode='w', encoding='utf-8', level=logging.DEBUG)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
handler = logging.FileHandler(filename='hacktricks-preprocessor.log', mode='w', encoding='utf-8')
|
||||
handler.setLevel(logging.DEBUG)
|
||||
logger.addHandler(handler)
|
||||
|
||||
handler2 = logging.FileHandler(filename='hacktricks-preprocessor-error.log', mode='w', encoding='utf-8')
|
||||
handler2.setLevel(logging.ERROR)
|
||||
logger.addHandler(handler2)
|
||||
|
||||
|
||||
def findtitle(search ,obj, key, path=(),):
|
||||
@ -27,7 +34,7 @@ def findtitle(search ,obj, key, path=(),):
|
||||
|
||||
|
||||
def ref(matchobj):
|
||||
logger.debug(f'Match: {matchobj.groups(0)[0].strip()}')
|
||||
logger.debug(f'Ref match: {matchobj.groups(0)[0].strip()}')
|
||||
href = matchobj.groups(0)[0].strip()
|
||||
title = href
|
||||
if href.startswith("http://") or href.startswith("https://"):
|
||||
@ -45,19 +52,29 @@ def ref(matchobj):
|
||||
try:
|
||||
if href.endswith("/"):
|
||||
href = href+"README.md" # Fix if ref points to a folder
|
||||
chapter, _path = findtitle(href, book, "source_path")
|
||||
logger.debug(f'Recursive title search result: {chapter["name"]}')
|
||||
title = chapter['name']
|
||||
if "#" in href:
|
||||
chapter, _path = findtitle(href.split("#")[0], book, "source_path")
|
||||
title = " ".join(href.split("#")[1].split("-")).title()
|
||||
logger.debug(f'Ref has # using title: {title}')
|
||||
else:
|
||||
chapter, _path = findtitle(href, book, "source_path")
|
||||
logger.debug(f'Recursive title search result: {chapter["name"]}')
|
||||
title = chapter['name']
|
||||
except Exception as e:
|
||||
try:
|
||||
dir = path.dirname(current_chapter['source_path'])
|
||||
logger.debug(f'Error getting chapter title: {href} trying with relative path {path.normpath(path.join(dir,href))}')
|
||||
chapter, _path = findtitle(path.normpath(path.join(dir,href)), book, "source_path")
|
||||
logger.debug(f'Recursive title search result: {chapter["name"]}')
|
||||
title = chapter['name']
|
||||
if "#" in href:
|
||||
chapter, _path = findtitle(path.normpath(path.join(dir,href.split('#')[0])), book, "source_path")
|
||||
title = " ".join(href.split("#")[1].split("-")).title()
|
||||
logger.debug(f'Ref has # using title: {title}')
|
||||
else:
|
||||
chapter, _path = findtitle(path.normpath(path.join(dir,href.split('#')[0])), book, "source_path")
|
||||
title = chapter["name"]
|
||||
logger.debug(f'Recursive title search result: {chapter["name"]}')
|
||||
except Exception as e:
|
||||
logger.debug(f'Error getting chapter title: {path.normpath(path.join(dir,href))}')
|
||||
print(f'Error getting chapter title: {path.normpath(path.join(dir,href))}')
|
||||
logger.debug(e)
|
||||
logger.error(f'Error getting chapter title: {path.normpath(path.join(dir,href))}')
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@ -69,6 +86,7 @@ def ref(matchobj):
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def files(matchobj):
|
||||
logger.debug(f'Files match: {matchobj.groups(0)[0].strip()}')
|
||||
href = matchobj.groups(0)[0].strip()
|
||||
@ -76,19 +94,19 @@ def files(matchobj):
|
||||
|
||||
try:
|
||||
for root, dirs, files in os.walk(os.getcwd()+'/src/files'):
|
||||
logger.debug(root)
|
||||
logger.debug(files)
|
||||
if href in files:
|
||||
title = href
|
||||
logger.debug(f'File search result: {os.path.join(root, href)}')
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(e)
|
||||
logger.debug(f'Error searching file: {href}')
|
||||
print(f'Error searching file: {href}')
|
||||
logger.error(f'Error searching file: {href}')
|
||||
sys.exit(1)
|
||||
|
||||
if title=="":
|
||||
logger.debug(f'Error searching file: {href}')
|
||||
print(f'Error searching file: {href}')
|
||||
logger.error(f'Error searching file: {href}')
|
||||
sys.exit(1)
|
||||
|
||||
template = f"""<a class="content_ref" href="/files/{href}"><span class="content_ref_label">{title}</span></a>"""
|
||||
@ -97,6 +115,7 @@ def files(matchobj):
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def add_read_time(content):
|
||||
regex = r'(<\/style>\n# .*(?=\n))'
|
||||
new_content = re.sub(regex, lambda x: x.group(0) + "\n\nReading time: {{ #reading_time }}", content)
|
||||
@ -126,15 +145,15 @@ if __name__ == '__main__':
|
||||
context, book = json.load(sys.stdin)
|
||||
|
||||
logger.debug(f"Context: {context}")
|
||||
logger.debug(f"Env: {context['config']['preprocessor']['hacktricks']['env']}")
|
||||
|
||||
for chapter in iterate_chapters(book['sections']):
|
||||
logger.debug(f"Chapter: {chapter['path']}")
|
||||
current_chapter = chapter
|
||||
regex = r'{{[\s]*#ref[\s]*}}(?:\n)?([^\\\n]*)(?:\n)?{{[\s]*#endref[\s]*}}'
|
||||
# regex = r'{{[\s]*#ref[\s]*}}(?:\n)?([^\\\n]*)(?:\n)?{{[\s]*#endref[\s]*}}'
|
||||
regex = r'{{[\s]*#ref[\s]*}}(?:\n)?([^\\\n#]*(?:#(.*))?)(?:\n)?{{[\s]*#endref[\s]*}}'
|
||||
new_content = re.sub(regex, ref, chapter['content'])
|
||||
regex = r'{{[\s]*#file[\s]*}}(?:\n)?([^\\\n]*)(?:\n)?{{[\s]*#endfile[\s]*}}'
|
||||
new_content = re.sub(regex, files, chapter['content'])
|
||||
new_content = re.sub(regex, files, new_content)
|
||||
new_content = add_read_time(new_content)
|
||||
chapter['content'] = new_content
|
||||
|
||||
|
@ -36,11 +36,11 @@ Le impostazioni del **renderer process** possono essere **configurate** nel **ma
|
||||
|
||||
L'applicazione electron **potrebbe accedere al dispositivo** tramite le API di Node, anche se può essere configurata per prevenirlo:
|
||||
|
||||
- **`nodeIntegration`** - è `off` per impostazione predefinita. Se attivato, consente di accedere alle funzionalità di node dal renderer process.
|
||||
- **`nodeIntegration`** - è `off` per impostazione predefinita. Se attivato, consente di accedere alle funzionalità di Node dal renderer process.
|
||||
- **`contextIsolation`** - è `on` per impostazione predefinita. Se disattivato, i processi main e renderer non sono isolati.
|
||||
- **`preload`** - vuoto per impostazione predefinita.
|
||||
- [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - è disattivato per impostazione predefinita. Restriggerà le azioni che NodeJS può eseguire.
|
||||
- Integrazione Node nei Workers
|
||||
- Integrazione di Node nei Workers
|
||||
- **`nodeIntegrationInSubframes`** - è `off` per impostazione predefinita.
|
||||
- Se **`nodeIntegration`** è **abilitato**, questo consentirebbe l'uso delle **API di Node.js** nelle pagine web che sono **caricate in iframe** all'interno di un'applicazione Electron.
|
||||
- Se **`nodeIntegration`** è **disabilitato**, allora i preload verranno caricati nell'iframe.
|
||||
@ -132,7 +132,7 @@ preload: _path2.default.join(__dirname, 'perload.js'),
|
||||
}
|
||||
});
|
||||
```
|
||||
Pertanto, lo script può esportare node-features nelle pagine:
|
||||
Pertanto, lo script può esportare node-features su pagine:
|
||||
```javascript:preload.js
|
||||
typeof require === "function"
|
||||
window.runCalc = function () {
|
||||
@ -148,7 +148,7 @@ runCalc()
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
> [!NOTE] > **Se `contextIsolation` è attivo, questo non funzionerà**
|
||||
> [!NOTE] > **Se `contextIsolation` è attivato, questo non funzionerà**
|
||||
|
||||
## RCE: XSS + contextIsolation
|
||||
|
||||
@ -157,7 +157,7 @@ Il _**contextIsolation**_ introduce i **contesti separati tra gli script della p
|
||||
Se i contesti non sono isolati, un attaccante può:
|
||||
|
||||
1. Eseguire **JavaScript arbitrario nel renderer** (XSS o navigazione verso siti esterni)
|
||||
2. **Sovrascrivere il metodo incorporato** che viene utilizzato nel preload o nel codice interno di Electron con una funzione propria
|
||||
2. **Sovrascrivere il metodo incorporato** che viene utilizzato nel preload o nel codice interno di Electron con una propria funzione
|
||||
3. **Attivare** l'uso della **funzione sovrascritta**
|
||||
4. RCE?
|
||||
|
||||
@ -175,7 +175,7 @@ electron-contextisolation-rce-via-electron-internal-code.md
|
||||
electron-contextisolation-rce-via-ipc.md
|
||||
{{#endref}}
|
||||
|
||||
### Bypass dell'evento click
|
||||
### Bypass dell'evento di clic
|
||||
|
||||
Se ci sono restrizioni applicate quando clicchi su un link, potresti essere in grado di aggirarle **facendo un clic centrale** invece di un normale clic sinistro.
|
||||
```javascript
|
||||
@ -185,14 +185,14 @@ window.addEventListener('click', (e) => {
|
||||
|
||||
Per ulteriori informazioni su questi esempi, controlla [https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8](https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8) e [https://benjamin-altpeter.de/shell-openexternal-dangers/](https://benjamin-altpeter.de/shell-openexternal-dangers/)
|
||||
|
||||
Quando si distribuisce un'applicazione desktop Electron, è fondamentale garantire le impostazioni corrette per `nodeIntegration` e `contextIsolation`. È stato stabilito che **l'esecuzione remota di codice (RCE)** lato client che mira a script di preload o al codice nativo di Electron dal processo principale è efficacemente prevenuta con queste impostazioni in atto.
|
||||
Quando si distribuisce un'applicazione desktop Electron, è fondamentale garantire le impostazioni corrette per `nodeIntegration` e `contextIsolation`. È stato stabilito che **l'esecuzione remota di codice lato client (RCE)** mirata a script di preload o al codice nativo di Electron dal processo principale è efficacemente prevenuta con queste impostazioni in atto.
|
||||
|
||||
Quando un utente interagisce con i link o apre nuove finestre, vengono attivati specifici listener di eventi, che sono cruciali per la sicurezza e la funzionalità dell'applicazione:
|
||||
```javascript
|
||||
webContents.on("new-window", function (event, url, disposition, options) {}
|
||||
webContents.on("will-navigate", function (event, url) {}
|
||||
```
|
||||
Questi listener sono **sovrascritti dall'applicazione desktop** per implementare la propria **logica aziendale**. L'applicazione valuta se un link navigato dovrebbe essere aperto internamente o in un browser web esterno. Questa decisione viene solitamente presa tramite una funzione, `openInternally`. Se questa funzione restituisce `false`, indica che il link dovrebbe essere aperto esternamente, utilizzando la funzione `shell.openExternal`.
|
||||
Questi listener sono **sovrascritti dall'applicazione desktop** per implementare la propria **logica aziendale**. L'applicazione valuta se un link navigato debba essere aperto internamente o in un browser web esterno. Questa decisione viene tipicamente presa attraverso una funzione, `openInternally`. Se questa funzione restituisce `false`, indica che il link deve essere aperto esternamente, utilizzando la funzione `shell.openExternal`.
|
||||
|
||||
**Ecco un pseudocodice semplificato:**
|
||||
|
||||
@ -200,7 +200,9 @@ Questi listener sono **sovrascritti dall'applicazione desktop** per implementare
|
||||
|
||||
.png>)
|
||||
|
||||
Le migliori pratiche di sicurezza di Electron JS sconsigliano di accettare contenuti non attendibili con la funzione `openExternal`, poiché potrebbe portare a RCE attraverso vari protocolli. I sistemi operativi supportano diversi protocolli che potrebbero attivare RCE. Per esempi dettagliati e ulteriori spiegazioni su questo argomento, si può fare riferimento a [questa risorsa](https://positive.security/blog/url-open-rce#windows-10-19042), che include esempi di protocolli Windows in grado di sfruttare questa vulnerabilità.
|
||||
Le migliori pratiche di sicurezza di Electron JS sconsigliano di accettare contenuti non attendibili con la funzione `openExternal`, poiché potrebbe portare a RCE attraverso vari protocolli. I sistemi operativi supportano diversi protocolli che potrebbero attivare RCE. Per esempi dettagliati e ulteriori spiegazioni su questo argomento, si può fare riferimento a [questa risorsa](https://positive.security/blog/url-open-rce#windows-10-19042), che include esempi di protocolli Windows capaci di sfruttare questa vulnerabilità.
|
||||
|
||||
In macos, la funzione `openExternal` può essere sfruttata per eseguire comandi arbitrari come in `shell.openExternal('file:///System/Applications/Calculator.app')`.
|
||||
|
||||
**Esempi di exploit di protocolli Windows includono:**
|
||||
```html
|
||||
@ -222,9 +224,9 @@ window.open(
|
||||
)
|
||||
</script>
|
||||
```
|
||||
## Lettura di file interni: XSS + contextIsolation
|
||||
## Lettura di File Interni: XSS + contextIsolation
|
||||
|
||||
**Disabilitare `contextIsolation` consente l'uso di `<webview>` tag**, simile a `<iframe>`, per leggere ed esfiltrare file locali. Un esempio fornito dimostra come sfruttare questa vulnerabilità per leggere il contenuto di file interni:
|
||||
**Disabilitare `contextIsolation` consente l'uso di `<webview>` tags**, simile a `<iframe>`, per leggere ed esfiltrare file locali. Un esempio fornito dimostra come sfruttare questa vulnerabilità per leggere il contenuto di file interni:
|
||||
|
||||
.png>)
|
||||
|
||||
@ -266,16 +268,104 @@ Nel caso in cui il **regex** utilizzato dalla funzione sia **vulnerabile a bypas
|
||||
window.open("<http://subdomainagoogleq.com/index.html>")
|
||||
</script>
|
||||
```
|
||||
## **Strumenti**
|
||||
## Modulo remoto
|
||||
|
||||
Il modulo Remote di Electron consente ai **processi di rendering di accedere alle API del processo principale**, facilitando la comunicazione all'interno di un'applicazione Electron. Tuttavia, abilitare questo modulo introduce rischi significativi per la sicurezza. Espande la superficie di attacco dell'applicazione, rendendola più suscettibile a vulnerabilità come gli attacchi di cross-site scripting (XSS).
|
||||
|
||||
> [!TIP]
|
||||
> Anche se il modulo **remote** espone alcune API dal principale ai processi di rendering, non è semplice ottenere RCE solo abusando dei componenti. Tuttavia, i componenti potrebbero esporre informazioni sensibili.
|
||||
|
||||
> [!WARNING]
|
||||
> Molte app che utilizzano ancora il modulo remoto lo fanno in un modo che **richiede l'abilitazione di NodeIntegration** nel processo di rendering, il che rappresenta un **enorme rischio per la sicurezza**.
|
||||
|
||||
Dalla versione 14 di Electron, il modulo `remote` di Electron potrebbe essere abilitato in diversi passaggi, poiché per motivi di sicurezza e prestazioni è **consigliato non usarlo**.
|
||||
|
||||
Per abilitarlo, è prima necessario **abilitarlo nel processo principale**:
|
||||
```javascript
|
||||
const remoteMain = require('@electron/remote/main')
|
||||
remoteMain.initialize()
|
||||
[...]
|
||||
function createMainWindow() {
|
||||
mainWindow = new BrowserWindow({
|
||||
[...]
|
||||
})
|
||||
remoteMain.enable(mainWindow.webContents)
|
||||
```
|
||||
Quindi, il processo di rendering può importare oggetti dal modulo come:
|
||||
```javascript
|
||||
import { dialog, getCurrentWindow } from '@electron/remote'
|
||||
```
|
||||
Il **[post del blog](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)** indica alcune interessanti **funzioni** esposte dall'oggetto **`app`** del modulo remoto:
|
||||
|
||||
- **`app.relaunch([options])`**
|
||||
- **Riavvia** l'applicazione **uscendo** dall'istanza corrente e **lanciando** una nuova. Utile per **aggiornamenti dell'app** o significativi **cambiamenti di stato**.
|
||||
- **`app.setAppLogsPath([path])`**
|
||||
- **Definisce** o **crea** una directory per memorizzare i **log dell'app**. I log possono essere **recuperati** o **modificati** utilizzando **`app.getPath()`** o **`app.setPath(pathName, newPath)`**.
|
||||
- **`app.setAsDefaultProtocolClient(protocol[, path, args])`**
|
||||
- **Registra** l'eseguibile corrente come **gestore predefinito** per un **protocollo** specificato. Puoi fornire un **percorso personalizzato** e **argomenti** se necessario.
|
||||
- **`app.setUserTasks(tasks)`**
|
||||
- **Aggiunge** attività alla **categoria Attività** nella **Jump List** (su Windows). Ogni attività può controllare come l'app viene **lanciata** o quali **argomenti** vengono passati.
|
||||
- **`app.importCertificate(options, callback)`**
|
||||
- **Importa** un **certificato PKCS#12** nel **negozio di certificati** del sistema (solo Linux). Un **callback** può essere utilizzato per gestire il risultato.
|
||||
- **`app.moveToApplicationsFolder([options])`**
|
||||
- **Sposta** l'applicazione nella **cartella Applicazioni** (su macOS). Aiuta a garantire un'**installazione standard** per gli utenti Mac.
|
||||
- **`app.setJumpList(categories)`**
|
||||
- **Imposta** o **rimuove** una **Jump List personalizzata** su **Windows**. Puoi specificare **categorie** per organizzare come le attività appaiono all'utente.
|
||||
- **`app.setLoginItemSettings(settings)`**
|
||||
- **Configura** quali **eseguibili** si avviano al **login** insieme alle loro **opzioni** (solo macOS e Windows).
|
||||
```javascript
|
||||
Native.app.relaunch({args: [], execPath: "/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
|
||||
Native.app.exit()
|
||||
```
|
||||
## systemPreferences module
|
||||
|
||||
L'**API principale** per accedere alle preferenze di sistema e **emettendo eventi di sistema** in Electron. Metodi come **subscribeNotification**, **subscribeWorkspaceNotification**, **getUserDefault** e **setUserDefault** sono tutti **parte di** questo modulo.
|
||||
|
||||
**Esempio di utilizzo:**
|
||||
```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**
|
||||
|
||||
* **Ascolta** le **notifiche native macOS** utilizzando NSDistributedNotificationCenter.
|
||||
* Prima di **macOS Catalina**, potevi sniffare **tutte** le notifiche distribuite passando **nil** a CFNotificationCenterAddObserver.
|
||||
* Dopo **Catalina / Big Sur**, le app sandboxed possono ancora **iscriversi** a **molti eventi** (ad esempio, **blocco/sblocco dello schermo**, **montaggi di volume**, **attività di rete**, ecc.) registrando le notifiche **per nome**.
|
||||
|
||||
### **getUserDefault / setUserDefault**
|
||||
|
||||
* **Interfaccia** con **NSUserDefaults**, che memorizza le **preferenze** dell'**applicazione** o **globali** su macOS.
|
||||
|
||||
* **getUserDefault** può **recuperare** informazioni sensibili, come **posizioni di file recenti** o **posizione geografica dell'utente**.
|
||||
|
||||
* **setUserDefault** può **modificare** queste preferenze, potenzialmente influenzando la **configurazione** di un'app.
|
||||
|
||||
* Nelle **versioni più vecchie di Electron** (prima della v8.3.0), solo la **suite standard** di NSUserDefaults era **accessibile**.
|
||||
|
||||
## Shell.showItemInFolder
|
||||
|
||||
Questa funzione mostra il file dato in un gestore di file, che **potrebbe eseguire automaticamente il file**.
|
||||
|
||||
Per ulteriori informazioni controlla [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) è uno strumento per identificare misconfigurazioni e anti-pattern di sicurezza nelle applicazioni basate su Electron.
|
||||
- [**Electrolint**](https://github.com/ksdmitrieva/electrolint) è un plugin open source per VS Code per applicazioni Electron che utilizza Electronegativity.
|
||||
- [**nodejsscan**](https://github.com/ajinabraham/nodejsscan) per controllare le librerie di terze parti vulnerabili
|
||||
- [**nodejsscan**](https://github.com/ajinabraham/nodejsscan) per controllare librerie di terze parti vulnerabili
|
||||
- [**Electro.ng**](https://electro.ng/): Devi acquistarlo
|
||||
|
||||
## Laboratori
|
||||
## Labs
|
||||
|
||||
In [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s) puoi trovare un laboratorio per sfruttare le app Electron vulnerabili.
|
||||
In [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s) puoi trovare un laboratorio per sfruttare app Electron vulnerabili.
|
||||
|
||||
Al alcuni comandi che ti aiuteranno con il laboratorio:
|
||||
```bash
|
||||
@ -309,5 +399,6 @@ npm start
|
||||
- [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s)
|
||||
- Maggiori ricerche e articoli sulla sicurezza di Electron 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}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user