CVE-2023-1881: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Cross-site Scripting (XSS) - Stored in GitHub repository microweber/microweber prior to 1.3.3.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 5.4
Published: 2023-04-05T17:15Z
Repository: https://github.com/microweber/microweber
Language: PHP
Files changed: src/MicroweberPackages/User/helpers/helpers.php, userfiles/modules/site_stats/src/Tracker.php
Commit date: 2023-02-23 13:53:40 +0200
Commit message: update

Diff: diff --git a/src/MicroweberPackages/User/helpers/helpers.php b/src/MicroweberPackages/User/helpers/helpers.php
index 254fab08853..a85e8ad728f 100644
--- a/src/MicroweberPackages/User/helpers/helpers.php
+++ b/src/MicroweberPackages/User/helpers/helpers.php
@@ -2,14 +2,15 @@
 
 
 function user_ip()
 {
     $ipaddress = '127.0.0.1';
+    $ipaddressDefault = '127.0.0.1';
 
     if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
         $ipaddress = $_SERVER['HTTP_CF_CONNECTING_IP'];
-    }  else if (isset($_SERVER['HTTP_CLIENT_IP'])) {
+    } else if (isset($_SERVER['HTTP_CLIENT_IP'])) {
         $ipaddress = $_SERVER['HTTP_CLIENT_IP'];
     } else if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
         $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
     } else if (isset($_SERVER['HTTP_X_FORWARDED'])) {
         $ipaddress = $_SERVER['HTTP_X_FORWARDED'];
@@ -23,10 +24,19 @@ function user_ip()
         $ipaddress = $_SERVER['HTTP_X_REAL_IP'];
     } else if (isset($_SERVER['REMOTE_ADDR'])) {
         $ipaddress = $_SERVER['REMOTE_ADDR'];
     }
 
+    $ipv4_validation_regex = "/^(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/";
+    $ipv6_validation_regex = "/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/";
+
+    if (!preg_match($ipv4_validation_regex, $ipaddress) and !preg_match($ipv6_validation_regex, $ipaddress)) {
+        //invalid ip is sent, so we return default ip
+        return $ipaddressDefault;
+    }
+
+
     return $ipaddress;
 }
 
 
 if (!defined('MW_USER_IP')) {
@@ -239,11 +249,11 @@ function only_admin_access()
     return app()->user_manager->admin_access();
 }
 
 function is_admin()
 {
-    if(app()->bound('user_manager')){
+    if (app()->bound('user_manager')) {
         return app()->user_manager->is_admin();
     }
 }
 
 function is_live_edit()
@@ -262,16 +272,16 @@ function is_live_edit()
     $editModeParam = app()->url_manager->param('editmode');
     if ($editModeParam == 'y') {
         return true;
     }
 
-    $editModeParam2 = app()->url_manager->param('editmode',true);
+    $editModeParam2 = app()->url_manager->param('editmode', true);
     if ($editModeParam2 == 'y') {
         return true;
     }
 
-    if(defined('IN_EDIT') and IN_EDIT){
+    if (defined('IN_EDIT') and IN_EDIT) {
         return true;
     }
 
     $editModeSession = app()->user_manager->session_get('editmode');
 
@@ -332,20 +342,20 @@ function get_users($params = false)
 /**
  * get_user.
  *
  * get_user get the user info from the DB
  *
- * @category users
+ * @param bool $id
  *
- * @author   Microweber
  *
+ * @return array
  * @link     http://microweber.com
  *
- * @param bool $id
+ * @category users
  *
+ * @author   Microweber
  *
- * @return array
  */
 function get_user($id = false)
 {
     return app()->user_manager->get($id);
 }
@@ -361,35 +371,35 @@ function user_can_access($permission)
     if ($user->is_admin == 1) {
         return true;
     }
 
     return false;
-   // return $user->can($permission);
+    // return $user->can($permission);
 }
 
 function module_permissions($module)
 {
 
     return \MicroweberPackages\Role\Repositories\Permission::generateModulePermissionsSlugs($module);
 }
 
 function user_can_destroy_module($module)
 {
- //   $permissions = \MicroweberPackages\Role\Repositories\Permission::generateModulePermissionsSlugs($module);
+    //   $permissions = \MicroweberPackages\Role\Repositories\Permission::generateModulePermissionsSlugs($module);
 
     $user = \Illuminate\Support\Facades\Auth::user();
     if (!$user) {
         return false;
     }
 
     if ($user->is_admin == 1) {
         return true;
     }
 
-   /* if ($user->can($permissions['destroy'])) {
-        return true;
-    }*/
+    /* if ($user->can($permissions['destroy'])) {
+         return true;
+     }*/
 
     return false;
 }
 
 function user_can_view_module($module)
@@ -404,21 +414,21 @@ function user_can_view_module($module)
 
     if ($user->is_admin == 1) {
         return true;
     }
 
- /*   if ($user->can($permissions['index'])) {
-        return true;
-    }*/
+    /*   if ($user->can($permissions['index'])) {
+           return true;
+       }*/
 
     return false;
 
 }
 
 
-
-function detect_user_id_from_params($params){
+function detect_user_id_from_params($params)
+{
 
     if (!empty($params)) {
         if (isset($params['username']) || isset($params['email'])) {
 
             if (isset($params['username']) && $params['username'] != false and filter_var($params['username'], FILTER_VALIDATE_EMAIL)) {
diff --git a/userfiles/modules/site_stats/src/Tracker.php b/userfiles/modules/site_stats/src/Tracker.php
index 3ebfcf9de6e..41b0a70346e 100644
--- a/userfiles/modules/site_stats/src/Tracker.php
+++ b/userfiles/modules/site_stats/src/Tracker.php
@@ -78,11 +78,13 @@ class Tracker
 
             foreach ($buffer as $key => $item) {
                 $browser_id = false;
                 $language = false;
 
-                if (isset($item['language']) and $item['language']) {
+                $item = array_map('strip_tags', $item);
+                $item = array_map('e', $item);
+                 if (isset($item['language']) and $item['language']) {
                     $language = $item['language'];
                 }
                 if (isset($item['browser_agent']) and $item['browser_agent']) {
                     $hash = md5($item['browser_agent']);
 
@@ -254,13 +256,15 @@ class Tracker
         if (is_ajax()) {
             if (isset($_POST['referrer'])) {
                 $ref = $_POST['referrer'];
             }
         }
-
+        $ref = e($ref);
 
         if ($last_page) {
+            $last_page = e($last_page);
+
             $last_page = rtrim($last_page, '?');
             $last_page = rtrim($last_page, '#');
         }
 
         if (strstr($ref, admin_url())) {

Vulnerable code:     }  else if (isset($_SERVER['HTTP_CLIENT_IP'])) {
    if(app()->bound('user_manager')){
    $editModeParam2 = app()->url_manager->param('editmode',true);
    if(defined('IN_EDIT') and IN_EDIT){
 * @category users
 * @author   Microweber
 * @param bool $id
 * @return array
   // return $user->can($permission);
 //   $permissions = \MicroweberPackages\Role\Repositories\Permission::generateModulePermissionsSlugs($module);
   /* if ($user->can($permissions['destroy'])) {
        return true;
    }*/
 /*   if ($user->can($permissions['index'])) {
        return true;
    }*/

function detect_user_id_from_params($params){
                if (isset($item['language']) and $item['language']) {

Fixed code:     $ipaddressDefault = '127.0.0.1';
    } else if (isset($_SERVER['HTTP_CLIENT_IP'])) {
    $ipv4_validation_regex = "/^(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/";
    $ipv6_validation_regex = "/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/";

    if (!preg_match($ipv4_validation_regex, $ipaddress) and !preg_match($ipv6_validation_regex, $ipaddress)) {
        //invalid ip is sent, so we return default ip
        return $ipaddressDefault;
    }


    if (app()->bound('user_manager')) {
    $editModeParam2 = app()->url_manager->param('editmode', true);
    if (defined('IN_EDIT') and IN_EDIT) {
 * @param bool $id
 * @return array
 * @category users
 * @author   Microweber
    // return $user->can($permission);
    //   $permissions = \MicroweberPackages\Role\Repositories\Permission::generateModulePermissionsSlugs($module);
    /* if ($user->can($permissions['destroy'])) {
         return true;
     }*/
    /*   if ($user->can($permissions['index'])) {
           return true;
       }*/
function detect_user_id_from_params($params)
{
                $item = array_map('strip_tags', $item);
                $item = array_map('e', $item);
                 if (isset($item['language']) and $item['language']) {
        $ref = e($ref);
            $last_page = e($last_page);