The fix for SSTI using |map
, |filter
and |reduce
twigs implemented in the commit 71bbed1 introduces bypass of the denylist due to incorrect return value from isDangerousFunction()
, which allows to execute the payload prepending double backslash (\\
)
The isDangerousFunction()
check in version 1.7.42 and onwards retuns false
value instead of true
when the \
symbol is found in the $name
.
...
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
/**
* @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.
This vulnerability can be exploited if the attacker has access to:
Accounts > Add
, and ensure that the following permissions are assigned when creating a new low-privileged user:
Pages -> Home
Advanced
tab and select the checkbox beside Twig
to ensure that Twig processing is enabled for the modified webpage.Content
tab, insert the following payload within the editor:
{{ ['id'] | map('\\system') | join() }}
Preview
button. Observe that the output of the id shell command is returned in the preview.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)) {
{ "nvd_published_at": "2023-07-18T21:15:15Z", "cwe_ids": [ "CWE-393", "CWE-74" ], "severity": "HIGH", "github_reviewed": true, "github_reviewed_at": "2023-07-19T22:11:07Z" }