|
| 1 | +### Title |
| 2 | +CVE-2021-33669 - SAP Mobile SDK Certificate Provider - Insecure Temporary File Storage - Potential Symlink Attack & Denial of Service |
| 3 | + |
| 4 | +### CVE ID |
| 5 | +CVE-2021-33669 |
| 6 | + |
| 7 | +### CVSS Score |
| 8 | +7.8 |
| 9 | + |
| 10 | +### Internal ID |
| 11 | +SICK-2021-032 |
| 12 | + |
| 13 | +### Vendor |
| 14 | +SAP |
| 15 | + |
| 16 | +### Product |
| 17 | +SAP Mobile SDK Certificate Provider |
| 18 | + |
| 19 | +### Product Versions |
| 20 | +3.0.7 and below |
| 21 | + |
| 22 | +### Vulnerability Details |
| 23 | + |
| 24 | +A vulnernability in the SAP Mobile SDK Certificate Provider version 3.0.7 and below causes a race condition in the execSync() function through the use of single-threaded file creation within the global read/write temporary folders for Windows, RiscOS, Linux. A local unprivileged attacker can read and potentially write to files created in almost every known insecure temporary directory: C:\TEMP, C:\TMP, \TEMP, \TMP, /tmp, /var/tmp, /usr/tmp. An attacker can abuse the execSync function by read/writing to either the stdoutFile or codeFile, as well as execute arbitrary code if any scriptFile is created, and used as well as potential Denial of Service via the sleepFile lockfile. |
| 25 | + |
| 26 | +### Vendor Response |
| 27 | +SAP Internal ID: SR-21-00474 |
| 28 | + |
| 29 | +Fixed in: [https://github.com/SAP/mobilesdk-certificateprovider/commit/88af36beb7c8081f3713a6ad53d6396f6ec825ee](https://github.com/SAP/mobilesdk-certificateprovider/commit/88af36beb7c8081f3713a6ad53d6396f6ec825ee) |
| 30 | + |
| 31 | +### Proof of Concept |
| 32 | + |
| 33 | +`./iOS/X509KapselSample/platforms/ios/cordova/node_modules/shelljs/shell.js` |
| 34 | + |
| 35 | +Note this may also affect "KapselSDK" |
| 36 | + |
| 37 | +Insecure filename generation (readable by all, potentially writable) |
| 38 | + |
| 39 | +```js |
| 40 | +// e.g. 'shelljs_a5f185d0443ca...' |
| 41 | +function randomFileName() { |
| 42 | + function randomHash(count) { |
| 43 | + if (count === 1) |
| 44 | + return parseInt(16*Math.random(), 10).toString(16); |
| 45 | + else { |
| 46 | + var hash = ''; |
| 47 | + for (var i=0; i<count; i++) |
| 48 | + hash += randomHash(1); |
| 49 | + return hash; |
| 50 | + } |
| 51 | + } |
| 52 | + |
| 53 | + return 'shelljs_'+randomHash(20); |
| 54 | +} |
| 55 | +``` |
| 56 | +Exploit is exactly explained below in the commented code below: |
| 57 | + |
| 58 | +```js |
| 59 | +// Hack to run child_process.exec() synchronously (sync avoids callback hell) |
| 60 | +// Uses a custom wait loop that checks for a flag file, created when the child process is done. |
| 61 | +// (Can't do a wait loop that checks for internal Node variables/messages as |
| 62 | +// Node is single-threaded; callbacks and other internal state changes are done in the |
| 63 | +// event loop). |
| 64 | +function execSync(cmd, opts) { |
| 65 | + var stdoutFile = path.resolve(tempDir()+'/'+randomFileName()), |
| 66 | + codeFile = path.resolve(tempDir()+'/'+randomFileName()), |
| 67 | + scriptFile = path.resolve(tempDir()+'/'+randomFileName()), |
| 68 | + sleepFile = path.resolve(tempDir()+'/'+randomFileName()); |
| 69 | + |
| 70 | + var options = extend({ |
| 71 | + silent: config.silent |
| 72 | + }, opts); |
| 73 | +``` |
| 74 | +
|
| 75 | +Known exploitable directories: |
| 76 | +
|
| 77 | +```js |
| 78 | +// Cross-platform method for getting an available temporary directory. |
| 79 | +// Follows the algorithm of Python's tempfile.tempdir |
| 80 | +// http://docs.python.org/library/tempfile.html#tempfile.tempdir |
| 81 | +function tempDir() { |
| 82 | + if (state.tempDir) |
| 83 | + return state.tempDir; // from cache |
| 84 | + |
| 85 | + state.tempDir = writeableDir(process.env['TMPDIR']) || |
| 86 | + writeableDir(process.env['TEMP']) || |
| 87 | + writeableDir(process.env['TMP']) || |
| 88 | + writeableDir(process.env['Wimp$ScrapDir']) || // RiscOS |
| 89 | + writeableDir('C:\\TEMP') || // Windows |
| 90 | + writeableDir('C:\\TMP') || // Windows |
| 91 | + writeableDir('\\TEMP') || // Windows |
| 92 | + writeableDir('\\TMP') || // Windows |
| 93 | + writeableDir('/tmp') || |
| 94 | + writeableDir('/var/tmp') || |
| 95 | + writeableDir('/usr/tmp') || |
| 96 | + writeableDir('.'); // last resort |
| 97 | + |
| 98 | + return state.tempDir; |
| 99 | +} |
| 100 | +``` |
| 101 | +
|
| 102 | +#### Disclosure Timeline |
| 103 | +* **2021-04-13** - Researcher discover vulnerabilities |
| 104 | +* **2021-06-08** - Vendor assigns CVE-2021-33669 & publishes advisory |
| 105 | +* **2021-10-04** - Researcher publishes their advisory after 3 month delay |
| 106 | +
|
| 107 | +### Links |
| 108 | +
|
| 109 | +[https://github.com/SAP/mobilesdk-certificateprovider/security/advisories/GHSA-r2j9-h6q9-cq8g](https://github.com/SAP/mobilesdk-certificateprovider/security/advisories/GHSA-r2j9-h6q9-cq8g) |
| 110 | +
|
| 111 | +[https://github.com/SAP/mobilesdk-certificateprovider](https://github.com/SAP/mobilesdk-certificateprovider) |
| 112 | +
|
| 113 | +[https://github.com/sickcodes/security/blob/master/advisories/SICK-2021-032.md](https://github.com/sickcodes/security/blob/master/advisories/SICK-2021-032.md) |
| 114 | +
|
| 115 | +[https://sick.codes/sick-2021-032](https://sick.codes/sick-2021-032) |
| 116 | +
|
| 117 | +### Researchers |
| 118 | +
|
| 119 | +Sick Codes: [https://github.com/sickcodes](https://github.com/sickcodes) || [https://twitter.com/sickcodes](https://twitter.com/sickcodes) |
| 120 | +
|
| 121 | +#### CVE Links |
| 122 | +
|
| 123 | +[https://sick.codes/sick-2021-032](https://sick.codes/sick-2021-032) |
| 124 | +
|
| 125 | +[https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-33669](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-33669) |
| 126 | +
|
| 127 | +[https://nvd.nist.gov/view/vuln/detail?vulnId=CVE-2021-33669](https://nvd.nist.gov/view/vuln/detail?vulnId=CVE-2021-33669) |
0 commit comments