CVE-2023-37897: Getgrav/grav Grav Server-side Template Injection (SSTI) Vulnerability

HIGH
Advisory Identifier: GHSA-9436-3gmp-4f53
CVSS 7.2
CWE-74 CWE-393
Published
Advisory Summary

CVE-2023-37897 is a HIGH (CVSS 7.2) grav server-side template injection (ssti) vulnerability (CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')) affecting Getgrav/grav libraries in the Packagist ecosystem. The issue involves grav server-side template injection (ssti) mitigation bypass. Remediation is available by upgrading affected packages to version 1.7.42.2.

CVE-2023-37897 at a Glance

CVE Identifier CVE-2023-37897
GHSA Identifier GHSA-9436-3gmp-4f53
Severity HIGH
CVSS v3.1 Base Score 7.2
CWE Classification CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
Affected Product Getgrav/grav
Package Ecosystem Packagist
Published Date
Last Updated

Security Impact

CVSS: 7.2

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required High (PR:H)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity High (I:H)
Availability High (A:H)

How to Fix CVE-2023-37897

To remediate this vulnerability, upgrade all affected Getgrav/grav dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

getgrav/grav fixed: 1.7.42.2
Upgrade getgrav/grav to 1.7.42.2
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for getgrav/grav

How to Check if You Are Affected

To determine whether your application is affected by CVE-2023-37897, inspect your project dependencies for Getgrav/grav:

inspect dependencies for getgrav/grav

Analyze the terminal output to locate any version of Getgrav/grav in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.7.42.2), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection'), where the product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component. In Getgrav/grav, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### Summary The fix for SSTI using `|map`, `|filter` and `|reduce` twigs implemented in the commit [71bbed1](https://github.com/getgrav/grav/commit/71bbed12f950de8335006d7f91112263d8504f1b) introduces bypass of the denylist due to incorrect return value from `isDangerousFunction()`, which allows to execute the payload prepending double backslash (`\\`) ### Details The `isDangerousFunction()` check in version 1.7.42 and onwards retuns `false` value instead of `true` when the `\` symbol is found in the `$name`. ```php ... if (strpos($name, "\\") !== false) { return false; } if (in_array($name, $commandExecutionFunctions)) { return true; } ... ``` Based on the code where the function is used, it is expected that any dangerous condition would return `true` ```php /** * @param Environment $env * @param array $array * @param callable|string $arrow * @return array|CallbackFilterIterator * @throws RuntimeError */ function mapFunc(Environment $env, $array, $arrow) { if (!$arrow instanceof \Closure && !is_string($arrow) || Utils::isDangerousFunction($arrow)) { throw new RuntimeError('Twig |map("' . $arrow . '") is not allowed.'); } ``` when `|map('\system')` is used in the malicious payload, the single backslash is dropped prior to reaching `strpos($name, '\\')` check, thus `$name` variable already has no backslash, and the command is blacklisted because it reaches the `if (in_array($name, $commandExecutionFunctions)) {` validation step. However if `|map('\\system')` is used (i.e. double backslash), then the `strpos($name, "\\") !== false` takes effect, and `isDangerousFunction()` returns `false` , in which case the `RuntimeError` is not generated, and blacklist is bypassed leading to code execution. ### Exploit Conditions This vulnerability can be exploited if the attacker has access to: 1. an Administrator account, or 2. a non-administrator, user account that has Admin panel access and Create/Update page permissions ### Steps to reproduce 1. Log in to Grav Admin using an administrator account. 2. Navigate to `Accounts > Add`, and ensure that the following permissions are assigned when creating a new low-privileged user: - Login to Admin - Allowed - Page Update - Allowed 3. Log out of Grav Admin 4. Login using the account created in step 2. 5. Choose `Pages -> Home` 6. Click the `Advanced` tab and select the checkbox beside `Twig` to ensure that Twig processing is enabled for the modified webpage. 7. Under the `Content` tab, insert the following payload within the editor: ```{{ ['id'] | map('\\system') | join() }}``` 8. Click the `Preview` button. Observe that the output of the id shell command is returned in the preview. ### Mitigation ```diff diff --git a/system/src/Grav/Common/Utils.php b/system/src/Grav/Common/Utils.php index 2f121bbe3..7b267cd0f 100644 --- a/system/src/Grav/Common/Utils.php +++ b/system/src/Grav/Common/Utils.php @@ -2069,7 +2069,7 @@ abstract class Utils } if (strpos($name, "\\") !== false) { - return false; + return true; } if (in_array($name, $commandExecutionFunctions)) { ```

CVE-2023-37897 Affected Getgrav/grav Versions

1 component(s)
Fixed Versions:
1.7.42.2
Product / Package Ecosystem Affected Versions Fixed Version
getgrav/grav
Packagist
< 1.7.42.2
1.7.42.2

References

Frequently Asked Questions

What is CVE-2023-37897?
CVE-2023-37897 is a security vulnerability in Getgrav/grav involving grav Server-side Template Injection (SSTI) mitigation bypass under CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection').
Which Getgrav/grav versions are affected?
Affected versions include releases prior to 1.7.42.2 across affected packages: getgrav/grav.
What version fixes CVE-2023-37897?
Upgrading to 1.7.42.2 (or the latest patched release for your respective branch) resolves the vulnerability.
Is getgrav/grav affected?
Yes, getgrav/grav is affected in releases prior to 1.7.42.2. Upgrade your dependency to 1.7.42.2 or later.
What is the CVSS score of CVE-2023-37897?
CVE-2023-37897 has a CVSS v3.1 base score of 7.2 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H.
What CWE is associated with CVE-2023-37897?
CVE-2023-37897 is classified under CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection') (The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component.).
How can I check Packagist dependencies for CVE-2023-37897?
Run the dependency tree command: 'inspect dependencies for getgrav/grav'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-9436-3gmp-4f53",
  "modified" : "2023-07-19T22:11:07Z",
  "published" : "2023-07-19T22:11:07Z",
  "aliases" : [ "CVE-2023-37897" ],
  "summary" : "grav Server-side Template Injection (SSTI) mitigation bypass",
  "details" : "### Summary\nThe fix for SSTI using `|map`, `|filter` and `|reduce` twigs implemented in the commit [71bbed1](https://github.com/getgrav/grav/commit/71bbed12f950de8335006d7f91112263d8504f1b) introduces bypass of the denylist due to incorrect return value from `isDangerousFunction()`, which allows to execute the payload prepending double backslash (`\\\\`) \n\n### Details\nThe `isDangerousFunction()` check in version 1.7.42 and onwards retuns `false` value instead of `true` when the `\\` symbol is found in the `$name`.\n\n```php\n...\n        if (strpos($name, \"\\\\\") !== false) {\n            return false;\n        }\n\n        if (in_array($name, $commandExecutionFunctions)) {\n            return true;\n        }\n...\n```\nBased on the code where the function is used, it is expected that any dangerous condition would return `true`\n```php\n    /**\n     * @param Environment $env\n     * @param array $array\n     * @param callable|string $arrow\n     * @return array|CallbackFilterIterator\n     * @throws RuntimeError\n     */\n    function mapFunc(Environment $env, $array, $arrow)\n    {\n        if (!$arrow instanceof \\Closure && !is_string($arrow) || Utils::isDangerousFunction($arrow)) {\n            throw new RuntimeError('Twig |map(\"' . $arrow . '\") is not allowed.');\n\t}\n```\nwhen `|map('\\system')` is used in the malicious payload, the single backslash is dropped prior to reaching `strpos($name, '\\\\')` check, thus `$name` variable already has no backslash, and the command is blacklisted because it reaches the  `if (in_array($name, $commandExecutionFunctions)) {` validation step. \n\nHowever if `|map('\\\\system')` is used (i.e. double backslash), then the `strpos($name, \"\\\\\") !== false` takes effect, and `isDangerousFunction()` returns `false` , in which case the `RuntimeError` is not generated, and blacklist is bypassed leading to code execution.\n\n### Exploit Conditions\nThis vulnerability can be exploited if the attacker has access to:\n\n1. an Administrator account, or\n2. a non-administrator, user account that has Admin panel access and Create/Update page permissions\n\n### Steps to reproduce\n\n1. Log in to Grav Admin using an administrator account.\n2. Navigate to `Accounts > Add`, and ensure that the following permissions are assigned when creating a new low-privileged user: \n    - Login to Admin - Allowed\n    - Page Update - Allowed\n3. Log out of Grav Admin\n4. Login using the account created in step 2.\n5. Choose `Pages -> Home`\n6. Click the `Advanced` tab and select the checkbox beside `Twig` to ensure that Twig processing is enabled for the modified webpage.\n7. Under the `Content` tab, insert the following payload within the editor:\n```{{ ['id'] | map('\\\\system') | join() }}```\n8. Click the `Preview` button. Observe that the output of the id shell command is returned in the preview.\n\n### Mitigation\n\n```diff\ndiff --git a/system/src/Grav/Common/Utils.php b/system/src/Grav/Common/Utils.php\nindex 2f121bbe3..7b267cd0f 100644\n--- a/system/src/Grav/Common/Utils.php\n+++ b/system/src/Grav/Common/Utils.php\n@@ -2069,7 +2069,7 @@ abstract class Utils\n         }\n \n         if (strpos($name, \"\\\\\") !== false) {\n-            return false;\n+            return true;\n         }\n \n         if (in_array($name, $commandExecutionFunctions)) {\n                                                                         \n```\n\n",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "getgrav/grav"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "1.7.42.2"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 1.7.42.1"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/getgrav/grav/security/advisories/GHSA-9436-3gmp-4f53"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2023-37897"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/getgrav/grav/commit/71bbed12f950de8335006d7f91112263d8504f1b"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/getgrav/grav/commit/b4c62101a43051fc7f5349c7d0a5b6085375c1d7"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/getgrav/grav"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-393", "CWE-74" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2023-07-19T22:11:07Z",
    "nvd_published_at" : "2023-07-18T21:15:15Z"
  }
}