CVE-2022-24871 (published 2022-04-20T19:15Z)

Shopware is an open commerce platform based on Symfony Framework and Vue. In affected versions an attacker can abuse the Admin SDK functionality on the server to read or update internal resources. Users are advised to update to the current version 6.4.10.1. For older versions of 6.1, 6.2, and 6.3, corresponding security measures are also available via a plugin. There are no known workarounds for this issue.

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

Weakness information:
cwe_id: CWE-918
cwe_name: Server-Side Request Forgery (SSRF)
description: The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.
extended_description: By providing URLs to unexpected hosts or ports, attackers can make it appear that the server is sending the request, possibly bypassing access controls such as firewalls that prevent the attackers from accessing the URLs directly. The server can be used as a proxy to conduct port scanning of hosts in internal networks, use other URLs such as that can access documents on the system (using file://), or use other protocols such as gopher:// or tftp://, which may provide greater control over the contents of requests.
         

Fix information:
repo_url: https://github.com/shopware/platform
commit_details: repo_url: https://github.com/shopware/platform
author: Soner Sayakci
author_date: 2022-04-12 11:44:17+02:00
msg: NEXT-21034 - Dont restore permissions
repository: repo_url: https://github.com/shopware/platform
repo_name: shopware/shopware
description: Shopware 6 is an open commerce platform based on Symfony Framework and Vue and supported by a worldwide community and more than 1.500 community extensions
repo_language: PHP
owner: shopware
file_changes: filename: SalesChannelProxyController.php
change_type: ModificationType.MODIFY
diff: @@ -198,6 +198,7 @@ class SalesChannelProxyController extends AbstractController
             PlatformRequest::HEADER_CONTEXT_TOKEN => $salesChannelContext->getToken(),
         ], \JSON_THROW_ON_ERROR);
         $response = new Response();
+        $response->headers->set('content-type', 'application/json');
         $response->setContent($content ?: null);
 
         return $response;

programming_language: PHP
filename: CartRestorer.php
change_type: ModificationType.MODIFY
diff: @@ -46,7 +46,7 @@ class CartRestorer
             $customerId
         );
 
-        if (empty($customerPayload) || !($customerPayload['expired'] ?? false) && $customerPayload['token'] === $currentContext->getToken()) {
+        if (empty($customerPayload) || !empty($customerPayload['permissions']) || !($customerPayload['expired'] ?? false) && $customerPayload['token'] === $currentContext->getToken()) {
             return $this->replaceContextToken($customerId, $currentContext);
         }
 
@@ -114,6 +114,7 @@ class CartRestorer
                 'customerId' => $customerId,
                 'billingAddressId' => null,
                 'shippingAddressId' => null,
+                'permissions' => [],
             ],
             $currentContext->getSalesChannel()->getId(),
             $customerId

programming_language: PHP
filename: SalesChannelContextPersister.php
change_type: ModificationType.MODIFY
diff: @@ -32,11 +32,14 @@ class SalesChannelContextPersister
         $this->lifetimeInterval = $lifetimeInterval ?? 'P1D';
     }
 
-    public function save(string $token, array $parameters, string $salesChannelId, ?string $customerId = null): void
+    public function save(string $token, array $newParameters, string $salesChannelId, ?string $customerId = null): void
     {
         $existing = $this->load($token, $salesChannelId, $customerId);
 
-        $parameters = array_replace_recursive($existing, $parameters);
+        $parameters = array_replace_recursive($existing, $newParameters);
+        if (isset($newParameters['permissions']) && $newParameters['permissions'] === []) {
+            $parameters['permissions'] = [];
+        }
 
         unset($parameters['token']);
 

programming_language: PHP
filename: CartRestorerTest.php
change_type: ModificationType.MODIFY
diff: @@ -12,13 +12,10 @@ use Shopware\Core\Checkout\Cart\LineItem\LineItem;
 use Shopware\Core\Checkout\Cart\LineItem\LineItemCollection;
 use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
 use Shopware\Core\Checkout\Customer\CustomerEntity;
-use Shopware\Core\Checkout\Payment\Cart\PaymentHandler\PrePayment;
 use Shopware\Core\Content\Product\Aggregate\ProductVisibility\ProductVisibilityDefinition;
 use Shopware\Core\Defaults;
 use Shopware\Core\Framework\Context;
-use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
 use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
-use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
 use Shopware\Core\Framework\Feature;
 use Shopware\Core\Framework\Test\TestCaseBase\IntegrationTestBehaviour;
 use Shopware\Core\Framework\Util\Random;
@@ -33,6 +30,7 @@ use Shopware\Core\System\SalesChannel\SalesChannelContext;
 use Shopware\Core\Test\TestDefaults;
 use Symfony\Component\EventDispatcher\EventDispatcher;
 use Symfony\Contracts\EventDispatcher\Event;
+use function json_encode;
 
 class CartRestorerTest extends TestCase
 {
@@ -325,33 +323,25 @@ class CartRestorerTest extends TestCase
         static::assertEquals(5, $p2->getQuantity());
     }
 
-    private function getStateId(string $state, string $machine)
+    public function testPermissionsAreIgnoredOnRestoer(): void
     {
-        return $this->getContainer()->get(Connection::class)
-            ->fetchColumn('
-                SELECT LOWER(HEX(state_machine_state.id))
-                FROM state_machine_state
-                    INNER JOIN  state_machine
-                    ON state_machine.id = state_machine_state.state_machine_id
-                    AND state_machine.technical_name = :machine
-                WHERE state_machine_state.technical_name = :state
-            ', [
-                'state' => $state,
-                'machine' => $machine,
-            ]);
-    }
+        $currentContextToken = Random::getAlphanumericString(32);
 
-    private function getPrePaymentMethodId(): string
-    {
-        /** @var EntityRepositoryInterface $repository */
-        $repository = $this->getContainer()->get('payment_method.repository');
+        $currentContext = $this->createSalesChannelContext($currentContextToken, []);
 
-        $criteria = (new Criteria())
-            ->setLimit(1)
-            ->addFilter(new EqualsFilter('active', true))
-            ->addFilter(new EqualsFilter('handlerIdentifier', PrePayment::class));
+        $con = $this->getContainer()->get(Connection::class);
+
+        $con->insert('sales_channel_api_context', [
+            'token' => Random::getAlphanumericString(32),
+            'payload' => json_encode(['expired' => false, 'customerId' => $this->customerId, 'permissions' => ['foo']], \JSON_THROW_ON_ERROR),
+            'sales_channel_id' => Uuid::fromHexToBytes($currentContext->getSalesChannelId()),
+            'customer_id' => Uuid::fromHexToBytes($this->customerId),
+            'updated_at' => (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT),
+        ]);
+
+        $restoreContext = $this->cartRestorer->restore($this->customerId, $currentContext);
 
-        return $repository->searchIds($criteria, Context::createDefaultContext())->getIds()[0];
+        static::assertSame([], $restoreContext->getPermissions());
     }
 
     private function createProduct(Context $context): string

programming_language: PHP