CVE-2024-31823: Insufficient Information (NVD-CWE-noinfo)
value: An issue in Ecommerce-CodeIgniter-Bootstrap commit v. d22b54e8915f167a135046ceb857caaf8479c4da allows a remote attacker to execute arbitrary code via the removeSecondaryImage method of the Publish.php component.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-04-29T18:15Z
Repository: https://github.com/kirilkirkov/Ecommerce-CodeIgniter-Bootstrap
Language: PHP
Files changed: application/modules/admin/controllers/advanced_settings/Languages.php, application/modules/admin/controllers/ecommerce/Publish.php, application/modules/admin/models/Orders_model.php
Commit date: 2024-01-02 21:59:46 +0200
Commit message: Vulnerability fixes from Lion Tree

Diff: diff --git a/application/modules/admin/controllers/advanced_settings/Languages.php b/application/modules/admin/controllers/advanced_settings/Languages.php
index 921d495c..dbc0de89 100644
--- a/application/modules/admin/controllers/advanced_settings/Languages.php
+++ b/application/modules/admin/controllers/advanced_settings/Languages.php
@@ -95,11 +95,11 @@ class Languages extends ADMIN_Controller
                 savefile($prevFile, $phpFileInclude);
                 $phpFileInclude = "<?php \n";
             }
             $php_value = str_replace("'", '&#39;', $_POST['php_values'][$i]);
 			$php_value = str_replace('"', '&#34;', $php_value);
-            $phpFileInclude .= '$lang[\'' . htmlentities($_POST['php_keys'][$i]) . '\'] = \'' . $php_value . '\';' . "\n";
+            $phpFileInclude .= '$lang[\'' . htmlentities(addslashes($_POST['php_keys'][$i])) . '\'] = \'' . $php_value . '\';' . "\n";
             $prevFile = $phpFile;
             $i++;
         }
         savefile($phpFile, $phpFileInclude);
 
@@ -111,26 +111,47 @@ class Languages extends ADMIN_Controller
             if ($jsFile != $prevFile && $i > 0) {
                 $jsFileInclude .= "};";
                 savefile($prevFile, $jsFileInclude);
                 $jsFileInclude = "var lang = { \n";
             }
-            $jsFileInclude .= htmlentities($_POST['js_keys'][$i]) . ':' . '"' . htmlentities($_POST['js_values'][$i]) . '",' . "\n";
+            $jsFileInclude .= htmlentities(addslashes($_POST['js_keys'][$i])) . ':' . '"' . htmlentities(addslashes($_POST['js_values'][$i])) . '",' . "\n";
             $prevFile = $jsFile;
             $i++;
         }
         $jsFileInclude .= "};";
         savefile($jsFile, $jsFileInclude);
     }
 
     private function getLangFolderForEdit()
     {
+        if(!ctype_alnum($_GET['editLang'])) {
+            redirect('admin/languages');
+        }
+
+        $dir = 'application' . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR . '' . $_GET['editLang'] . DIRECTORY_SEPARATOR;
+        if(!is_dir(rtrim($dir, DIRECTORY_SEPARATOR))) {
+            redirect('admin/languages');
+        }
+
         $langFiles = array();
-        $files = rreadDir('application' . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR . '' . $_GET['editLang'] . DIRECTORY_SEPARATOR);
+        $files = rreadDir($dir);
         $arrPhpFiles = $arrJsFiles = array();
         foreach ($files as $ext => $filesLang) {
             foreach ($filesLang as $fileLang) {
                 if ($ext == 'php') {
+
+                    $file_content = file_get_contents($fileLang);
+                    $tokens = token_get_all($file_content);
+                    foreach ($tokens as $tokenK => $token) {
+                        if ($token[0] == T_VARIABLE) {
+                            if($token[1] != '$lang') {
+                                throw new \Exception('Invalid variable name in file ' . $fileLang . ' on line ' . $token[2] . '');
+                            }
+                        }
+                        unset($tokens[$tokenK]);
+                    }
+
                     require $fileLang;
                     if (isset($lang)) {
                         $arrPhpFiles[$fileLang] = $lang;
                         unset($lang);
                     }
diff --git a/application/modules/admin/controllers/ecommerce/Publish.php b/application/modules/admin/controllers/ecommerce/Publish.php
index 4b4a6430..cc54840f 100644
--- a/application/modules/admin/controllers/ecommerce/Publish.php
+++ b/application/modules/admin/controllers/ecommerce/Publish.php
@@ -149,15 +149,18 @@ class Publish extends ADMIN_Controller
     }
 
     /*
      * called from ajax
      */
-
-    public function removeSecondaryImage()
-    {
+    public function removeSecondaryImage() {
         if ($this->input->is_ajax_request()) {
-            $img = '.' . DIRECTORY_SEPARATOR . 'attachments' . DIRECTORY_SEPARATOR . 'shop_images' . DIRECTORY_SEPARATOR . '' . $_POST['folder'] . DIRECTORY_SEPARATOR . $_POST['image'];
-            unlink($img);
+            $basePath = realpath('.' . DIRECTORY_SEPARATOR . 'attachments' . DIRECTORY_SEPARATOR . 'shop_images' . DIRECTORY_SEPARATOR);
+    
+            $folder = realpath($basePath . DIRECTORY_SEPARATOR . $_POST['folder']);
+            $image = $_POST['image'];
+    
+            if ($folder !== false && strpos($folder, $basePath) === 0 && is_file($folder . DIRECTORY_SEPARATOR . $image)) {
+                unlink($folder . DIRECTORY_SEPARATOR . $image);
+            }
         }
     }
-
 }
diff --git a/application/modules/admin/models/Orders_model.php b/application/modules/admin/models/Orders_model.php
index a6d48245..9ea84839 100644
--- a/application/modules/admin/models/Orders_model.php
+++ b/application/modules/admin/models/Orders_model.php
@@ -76,18 +76,22 @@ class Orders_model extends CI_Model
         $this->db->where('id', $id);
         $result = $this->db->get('orders');
         $arr = $result->row_array();
         $products = unserialize($arr['products']);
         foreach ($products as $product) {
+                if (!is_numeric($product['product_quantity']) || (int)$product['product_info']['id'] < 1) {
+                    continue;
+                }
+
                 if (isset($operator)) {
-                    if (!$this->db->query('UPDATE products SET quantity=quantity' . $operator . $product['product_quantity'] . ' WHERE id = ' . $product['product_info']['id'])) {
+                    if (!$this->db->query('UPDATE products SET quantity=quantity' . $operator . $product['product_quantity'] . ' WHERE id = ' . (int)$product['product_info']['id'])) {
                         log_message('error', print_r($this->db->error(), true));
                         show_error(lang('database_error'));
                     }
                 }
                 if (isset($operator_pro)) {
-                    if (!$this->db->query('UPDATE products SET procurement=procurement' . $operator_pro . $product['product_quantity'] . ' WHERE id = ' . $product['product_info']['id'])) {
+                    if (!$this->db->query('UPDATE products SET procurement=procurement' . $operator_pro . $product['product_quantity'] . ' WHERE id = ' . (int)$product['product_info']['id'])) {
                         log_message('error', print_r($this->db->error(), true));
                         show_error(lang('database_error'));
                     }
                 } 
         }

Vulnerable code:             $phpFileInclude .= '$lang[\'' . htmlentities($_POST['php_keys'][$i]) . '\'] = \'' . $php_value . '\';' . "\n";
            $jsFileInclude .= htmlentities($_POST['js_keys'][$i]) . ':' . '"' . htmlentities($_POST['js_values'][$i]) . '",' . "\n";
        $files = rreadDir('application' . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR . '' . $_GET['editLang'] . DIRECTORY_SEPARATOR);

    public function removeSecondaryImage()
    {
            $img = '.' . DIRECTORY_SEPARATOR . 'attachments' . DIRECTORY_SEPARATOR . 'shop_images' . DIRECTORY_SEPARATOR . '' . $_POST['folder'] . DIRECTORY_SEPARATOR . $_POST['image'];
            unlink($img);

                    if (!$this->db->query('UPDATE products SET quantity=quantity' . $operator . $product['product_quantity'] . ' WHERE id = ' . $product['product_info']['id'])) {
                    if (!$this->db->query('UPDATE products SET procurement=procurement' . $operator_pro . $product['product_quantity'] . ' WHERE id = ' . $product['product_info']['id'])) {
Fixed code:             $phpFileInclude .= '$lang[\'' . htmlentities(addslashes($_POST['php_keys'][$i])) . '\'] = \'' . $php_value . '\';' . "\n";
            $jsFileInclude .= htmlentities(addslashes($_POST['js_keys'][$i])) . ':' . '"' . htmlentities(addslashes($_POST['js_values'][$i])) . '",' . "\n";
        if(!ctype_alnum($_GET['editLang'])) {
            redirect('admin/languages');
        }

        $dir = 'application' . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR . '' . $_GET['editLang'] . DIRECTORY_SEPARATOR;
        if(!is_dir(rtrim($dir, DIRECTORY_SEPARATOR))) {
            redirect('admin/languages');
        }

        $files = rreadDir($dir);

                    $file_content = file_get_contents($fileLang);
                    $tokens = token_get_all($file_content);
                    foreach ($tokens as $tokenK => $token) {
                        if ($token[0] == T_VARIABLE) {
                            if($token[1] != '$lang') {
                                throw new \Exception('Invalid variable name in file ' . $fileLang . ' on line ' . $token[2] . '');
                            }
                        }
                        unset($tokens[$tokenK]);
                    }

    public function removeSecondaryImage() {
            $basePath = realpath('.' . DIRECTORY_SEPARATOR . 'attachments' . DIRECTORY_SEPARATOR . 'shop_images' . DIRECTORY_SEPARATOR);
    
            $folder = realpath($basePath . DIRECTORY_SEPARATOR . $_POST['folder']);
            $image = $_POST['image'];
    
            if ($folder !== false && strpos($folder, $basePath) === 0 && is_file($folder . DIRECTORY_SEPARATOR . $image)) {
                unlink($folder . DIRECTORY_SEPARATOR . $image);
            }
                if (!is_numeric($product['product_quantity']) || (int)$product['product_info']['id'] < 1) {
                    continue;
                }

                    if (!$this->db->query('UPDATE products SET quantity=quantity' . $operator . $product['product_quantity'] . ' WHERE id = ' . (int)$product['product_info']['id'])) {
                    if (!$this->db->query('UPDATE products SET procurement=procurement' . $operator_pro . $product['product_quantity'] . ' WHERE id = ' . (int)$product['product_info']['id'])) {