[CVE-2023-30148] Multiple cross-site scripting (XSS) vulnerabilities in the Multi html block (opartmultihtmlblock) module and multihtmlblock* sub-modules from Opart for PrestaShop

PrestaShop Security Advisory

Multiple cross-site scripting (XSS) vulnerabilities of Type 2 (Stored XSS) B2F (Back to front) in the Multi html block (opartmultihtmlblock) module and multihtmlblock* sub-modules from Opart for PrestaShop, prior to version 2.0.12, allows remote attackers to inject arbitrary web script or HTML via the body_text or body_text_rude field.

Summary

  • CVE ID: CVE-2023-30148
  • Published at: 2023-10-10
  • Advisory source: Friends-Of-Presta
  • Platform: PrestaShop
  • Product: opartmultihtmlblock and multihtmlblock* sub-modules
  • Impacted release: For opartmultihtmlblock <= 2.0.11 (Fixed in 2.0.12), for multihtmlblock* : = 1.0.0
  • Product author: Opart
  • Weakness: CWE-79
  • Severity: medium (6.1)

Description

Prior to version 2.0.12 of the Prestashop Multi html block (opartmultihtmlblock) module and multihtmlblock* sub-modules for PrestaShop, scripts can be injected into the database by the admin configuration form or chained by an SQL injection, which can then be executed in user browsers.

WARNING: This vulnerability has been seen as exploited to inject malicious code into the payment page using the displayBanner hook from the multihtmlblockmessageheader sub-module (exploited by a compromised admin).

CVSS base metrics

  • Attack vector: network
  • Attack complexity: low
  • Privilege required: high
  • User interaction: high
  • Scope: unchanged
  • Confidentiality: high
  • Integrity: high
  • Availability: none

Vector string: CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:N

Possible malicious usage

  • Hijack payment modules
  • Redirect users to another website
  • Technical and personal data leaks

Patch

Patches listed below will:

  1. Sanitize the admin form (removing scripts thanks to isCleanHtml validate, and removing iframes is not authorized in HTML fields
  2. Sanitize the string saved in the database before displaying it (to disable corrupted data from SQL injections)

Please note that these patches should be applied to the main module opartmultihtmlblock and all multihtmlblock* sub-modules. For the main module, the component to modify is the class BlockhtmlClass in sourcefiles directory and well as the main class Blockhtml, and for the sub-modules, the component to edit is the Multihtmlblock*Class as well as the main class Multihtmlblock*

--- a/sourcefiles/BlockhtmlClass.php
+++ b/sourcefiles/BlockhtmlClass.php
@@ -62,8 +62,8 @@ class %Modulename%Class extends ObjectModel
                'fields' => array(
                        'id_shop' =>                            array('type' => self::TYPE_INT, 'validate' => 'isunsignedInt', 'required' => true),
                        // Lang fields
-                       'body_text' =>                  array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isString'),
-                        'body_text_rude' =>            array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isString'),
+                       'body_text' =>                  array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isCleanHtml'),
+                        'body_text_rude' =>            array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isCleanHtml'),
                         'all_pages' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
                         'show_on_home' =>            array('type' => self::TYPE_STRING, 'validate' => 'isBool'),
                         'category_id' =>            array('type' => self::TYPE_STRING, 'validate' => 'isString'),
--- a/sourcefiles/blockhtml.php
+++ b/sourcefiles/blockhtml.php
@@ -384,9 +384,27 @@ class %Modulename% extends Module
                             $blockhtml=new %Modulename%Class();
                             $blockhtml->id_shop=$id_shop;                                
                             $blockhtml->copyFromPost();
+                            // Validate if our html fields contains an iframe
+                            $isIframeValidated = $this->validateIframe($blockhtml->body_text);
+                            $isIframeValidated = $isIframeValidated ?
+                                $this->validateIframe($blockhtml->body_text_rude) :
+                                $isIframeValidated;
+                            if (!$isIframeValidated) {
+                                // There is an iframe that is not allowed, we stop here
+                                return false;
+                            }
                             $blockhtml->save();
                        }
                         $blockhtml->copyFromPost();
+                        // Validate if our html fields contains an iframe
+                        $isIframeValidated = $this->validateIframe($blockhtml->body_text);
+                        $isIframeValidated = $isIframeValidated ?
+                            $this->validateIframe($blockhtml->body_text_rude) :
+                            $isIframeValidated;
+                        if (!$isIframeValidated) {
+                            // There is an iframe that is not allowed, we stop here
+                            return false;
+                        }
                         $blockhtml->update();
                         
                        $this->messages[]=$this->l('Block successfuly update');
@@ -395,6 +413,25 @@ class %Modulename% extends Module
                }
        }
 
+    /**
+     * Validate a string depending if iframes are allowed in HTML fields
+     *
+     * @param string $htmlBody
+     *
+     * @return bool
+     */
+    protected function validateIframe($htmlBody)
+    {
+        foreach ($htmlBody as $stringToValidate) {
+            if (!Configuration::get('PS_ALLOW_HTML_IFRAME') &&
+                preg_match('//isU', $stringToValidate)) {
+                $this->erreurs[] = $this->trans('To use