Vulnerability: admin/vqmods.app/vqmods.inc.php in LiteCart before 2.1.3 allows remote authenticated attackers to upload a malicious file (resulting in remote code execution) by using the text/xml or application/xml Content-Type in a public_html/admin/?app=vqmods&doc=vqmods request.
Vulnerability ID: CVE-2018-12256
CWE: CWE-434
Severity score: 6.4
Project: https://github.com/litecart/litecart
Published: 2018-08-16
File: public_html/admin/vqmods.app/vqmods.inc.php
Commit message: ! Verify that uploads have valid xml and vqmod content
Commit author: timint

Vulnerable version (before fix):
         throw new Exception(language::translate('error_must_select_file_to_upload', 'You must select a file to upload'));       }        if (!in_array($_FILES['vqmod']['type'], array('text/xml', 'application/xml'))) {         throw new Exception(language::translate('error_must_provide_vqmod', 'You must provide a valid vQmod file'));       }        move_uploaded_file($_FILES['vqmod']['tmp_name'], FS_DIR_HTTP_ROOT . WS_DIR_HTTP_HOME .'vqmod/xml/'. $_FILES['vqmod']['name']);        notices::add('success', language::translate('success_changes_saved', 'Changes saved successfully'));       header('Location: '. document::ilink());       notices::add('errors', $e->getMessage());     }   } ?> <h1><?php echo $app_icon; ?> <?php echo language::translate('title_vqmods', 'vQmods'); ?></h1> 

Fixed version (after fix):
         throw new Exception(language::translate('error_must_select_file_to_upload', 'You must select a file to upload'));       }        $dom = new DOMDocument('1.0', 'UTF-8');        $xml = file_get_contents($_FILES['vqmod']['tmp_name']); // DOMDocument::load() does not support Windows paths so we use DOMDocument::loadXML()        if (!@$dom->loadXML($xml)) {         throw new Exception(language::translate('error_invalid_xml_file', 'Invalid XML file'));       }        if (!$dom->getElementsByTagName('modification')) {         throw new Exception(language::translate('error_xml_file_is_not_valid_vqmod', 'XML file is not a valid vQmod file'));       }        $filename = FS_DIR_HTTP_ROOT . WS_DIR_HTTP_HOME .'vqmod/xml/'. pathinfo($_FILES['vqmod']['name'], PATHINFO_FILENAME) .'.xml';        if (is_file($filename)) {         unlink($filename);       }        move_uploaded_file($_FILES['vqmod']['tmp_name'], $filename);        notices::add('success', language::translate('success_changes_saved', 'Changes saved successfully'));       header('Location: '. document::ilink());       notices::add('errors', $e->getMessage());     }   }  ?> <h1><?php echo $app_icon; ?> <?php echo language::translate('title_vqmods', 'vQmods'); ?></h1> 

Patch:
patch: @@ -49,11 +49,25 @@
         throw new Exception(language::translate('error_must_select_file_to_upload', 'You must select a file to upload'));
       }
 
-      if (!in_array($_FILES['vqmod']['type'], array('text/xml', 'application/xml'))) {
-        throw new Exception(language::translate('error_must_provide_vqmod', 'You must provide a valid vQmod file'));
+      $dom = new DOMDocument('1.0', 'UTF-8');
+
+      $xml = file_get_contents($_FILES['vqmod']['tmp_name']); // DOMDocument::load() does not support Windows paths so we use DOMDocument::loadXML()
+
+      if (!@$dom->loadXML($xml)) {
+        throw new Exception(language::translate('error_invalid_xml_file', 'Invalid XML file'));
+      }
+
+      if (!$dom->getElementsByTagName('modification')) {
+        throw new Exception(language::translate('error_xml_file_is_not_valid_vqmod', 'XML file is not a valid vQmod file'));
       }
 
-      move_uploaded_file($_FILES['vqmod']['tmp_name'], FS_DIR_HTTP_ROOT . WS_DIR_HTTP_HOME .'vqmod/xml/'. $_FILES['vqmod']['name']);
+      $filename = FS_DIR_HTTP_ROOT . WS_DIR_HTTP_HOME .'vqmod/xml/'. pathinfo($_FILES['vqmod']['name'], PATHINFO_FILENAME) .'.xml';
+
+      if (is_file($filename)) {
+        unlink($filename);
+      }
+
+      move_uploaded_file($_FILES['vqmod']['tmp_name'], $filename);
 
       notices::add('success', language::translate('success_changes_saved', 'Changes saved successfully'));
       header('Location: '. document::ilink());
@@ -63,6 +77,7 @@
       notices::add('errors', $e->getMessage());
     }
   }
+
 ?>
 <h1><?php echo $app_icon; ?> <?php echo language::translate('title_vqmods', 'vQmods'); ?></h1>
path: public_html/admin/vqmods.app/vqmods.inc.php