CVE-2021-43836 (published 2021-12-15T20:15Z)

Sulu is an open-source PHP content management system based on the Symfony framework. In affected versions an attacker can read arbitrary local files via a PHP file include. In a default configuration this also leads to remote code execution. The problem is patched with the Versions 1.6.44, 2.2.18, 2.3.8, 2.4.0. For users unable to upgrade overwrite the service `sulu_route.generator.expression_token_provider` and wrap the translator before passing it to the expression language.

Severity: MEDIUM
CVSS v2 base score: 6.5 (AV:N/AC:L/Au:S/C:P/I:P/A:P)
CVSS v3 base score: 8.8, HIGH (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-22
cwe_name: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
description: The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
extended_description: 
            Many file operations are intended to take place within a restricted directory. By using special elements such as ".." and "/" separators, attackers can escape outside of the restricted location to access files or directories that are elsewhere on the system. One of the most common special elements is the "../" sequence, which in most modern operating systems is interpreted as the parent directory of the current location. This is referred to as relative path traversal. Path traversal also covers the use of absolute pathnames such as "/usr/local/bin" to access unexpected files. This is referred to as absolute path traversal.
         
         

Fix information:
repo_url: https://github.com/sulu/sulu
commit_details: repo_url: https://github.com/sulu/sulu
author: Johannes Wachter
author_date: 2021-12-07 13:16:26+01:00
msg: Merge pull request from GHSA-vx6j-pjrh-vgjh
repository: repo_url: https://github.com/sulu/sulu
repo_name: sulu/sulu
description: Core framework that implements the functionality of the Sulu content management system
repo_language: PHP
owner: sulu
file_changes: filename: SymfonyExpressionTokenProvider.php
change_type: ModificationType.MODIFY
diff: @@ -44,7 +44,10 @@ class SymfonyExpressionTokenProvider implements TokenProviderInterface
                 $this->translator->setLocale($entity->getLocale());
             }
 
-            $result = $this->expressionLanguage->evaluate($name, ['object' => $entity, 'translator' => $this->translator]);
+            $result = $this->expressionLanguage->evaluate($name, [
+                'object' => $entity,
+                'translator' => new TranslatorWrapper($this->translator),
+            ]);
             $this->translator->setLocale($locale);
 
             return $result;

programming_language: PHP
filename: TranslatorWrapper.php
change_type: ModificationType.ADD
diff: @@ -0,0 +1,41 @@
+<?php
+
+namespace Sulu\Bundle\RouteBundle\Generator;
+
+use Symfony\Component\Translation\TranslatorInterface;
+
+/**
+ * @internal
+ */
+class TranslatorWrapper implements TranslatorInterface
+{
+    /**
+     * @var TranslatorInterface
+     */
+    private $translator;
+
+    public function __construct(TranslatorInterface $translator)
+    {
+        $this->translator = $translator;
+    }
+
+    public function trans($id, array $parameters = [], $domain = null, $locale = null)
+    {
+        return $this->translator->trans($id, $parameters, $domain, $locale);
+    }
+
+    public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null)
+    {
+        return $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
+    }
+
+    public function setLocale($locale)
+    {
+        throw new \Exception('Not supported.');
+    }
+
+    public function getLocale()
+    {
+        return $this->translator->getLocale();
+    }
+}

programming_language: PHP
filename: SymfonyExpressionTokenProviderTest.php
change_type: ModificationType.MODIFY
diff: @@ -11,9 +11,11 @@
 
 namespace Sulu\Bundle\RouteBundle\Tests\Unit\Generator;
 
+use Prophecy\Argument;
 use Sulu\Bundle\RouteBundle\Generator\CannotEvaluateTokenException;
 use Sulu\Bundle\RouteBundle\Generator\SymfonyExpressionTokenProvider;
 use Sulu\Bundle\RouteBundle\Model\RoutableInterface;
+use Symfony\Component\Translation\Translator;
 use Symfony\Component\Translation\TranslatorInterface;
 
 class SymfonyExpressionTokenProviderTest extends \PHPUnit_Framework_TestCase
@@ -37,7 +39,7 @@ class SymfonyExpressionTokenProviderTest extends \PHPUnit_Framework_TestCase
         $translator = $this->prophesize(TranslatorInterface::class);
         $translator->getLocale()->willReturn('de');
         $translator->setLocale('de')->shouldBeCalled();
-        $translator->trans('test-key')->willReturn('TEST');
+        $translator->trans('test-key', Argument::cetera())->willReturn('TEST');
         $entity = $this->prophesize(RoutableInterface::class);
         $entity->getLocale()->willReturn('en');
 
@@ -45,6 +47,23 @@ class SymfonyExpressionTokenProviderTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals('TEST', $provider->provide($entity, 'translator.trans("test-key")'));
     }
 
+    public function testResolveTranslationAddResource()
+    {
+        $this->setExpectedException(CannotEvaluateTokenException::class);
+
+        $translator = $this->prophesize(Translator::class);
+        $translator->getLocale()->willReturn('de');
+        $translator->setLocale('de')->shouldBeCalled();
+        $entity = $this->prophesize(RoutableInterface::class);
+        $entity->getLocale()->willReturn('en');
+
+        $entity->getLocale = function() {
+            return 'en';
+        };
+        $provider = new SymfonyExpressionTokenProvider($translator->reveal());
+        $provider->provide($entity, 'translator.addResource("php", "/test.php")');
+    }
+
     public function testResolveNotExists()
     {
         $this->setExpectedException(CannotEvaluateTokenException::class);

programming_language: PHP