CVE-2024-21515: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: This affects versions of the package opencart/opencart from 4.0.0.0. A reflected XSS issue was identified in the filename parameter of the admin tool/log route. An attacker could obtain a user's token by tricking the user to click on a maliciously crafted URL. The user is then prompted to login and redirected again upon authentication with the payload automatically executing. If the attacked user has admin privileges, this vulnerability could be used as the start of a chain of exploits like Zip Slip or arbitrary file write vulnerabilities in the admin functionality.**Notes:**1) This is only exploitable if the attacker knows the name or path of the admin directory. The name of the directory is "admin" by default but there is a pop-up in the dashboard warning users to rename it.2) The fix for this vulnerability is incomplete. The redirect is removed so that it is not possible for an attacker to control the redirect post admin login anymore, but it is still possible to exploit this issue in admin if the user is authenticated as an admin already.
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: 4.7
Published: 2024-06-22T05:15Z
Repository: https://github.com/opencart/opencart
Language: PHP
Files changed: upload/admin/controller/common/login.php, upload/admin/view/template/common/login.twig
Commit date: 2024-05-21 10:52:43 +0800
Commit message: removed a xss vunribility if the attack knows the admin path

Diff: diff --git a/upload/admin/controller/common/login.php b/upload/admin/controller/common/login.php
index dd532219c4..e003714e06 100644
--- a/upload/admin/controller/common/login.php
+++ b/upload/admin/controller/common/login.php
@@ -49,27 +49,10 @@ class Login extends \Opencart\System\Engine\Controller {
 			$data['forgotten'] = $this->url->link('common/forgotten');
 		} else {
 			$data['forgotten'] = '';
 		}
 
-		if (isset($this->request->get['route']) && $this->request->get['route'] != 'common/login') {
-			$args = $this->request->get;
-
-			$route = $args['route'];
-
-			unset($args['route']);
-			unset($args['user_token']);
-
-			$url = '';
-
-			$url .= http_build_query($args);
-
-			$data['redirect'] = $this->url->link($route, $url);
-		} else {
-			$data['redirect'] = '';
-		}
-
 		$data['header'] = $this->load->controller('common/header');
 		$data['footer'] = $this->load->controller('common/footer');
 
 		$this->response->setOutput($this->load->view('common/login', $data));
 	}
@@ -124,15 +107,11 @@ class Login extends \Opencart\System\Engine\Controller {
 
 			$this->load->model('user/user');
 
 			$this->model_user_user->addLogin($this->user->getId(), $login_data);
 
-			if ($this->request->post['redirect'] && str_starts_with(html_entity_decode($this->request->post['redirect'], ENT_QUOTES, 'UTF-8'), HTTP_SERVER)) {
-				$json['redirect'] = html_entity_decode($this->request->post['redirect'], ENT_QUOTES, 'UTF-8') . '&user_token=' . $this->session->data['user_token'];
-			} else {
-				$json['redirect'] = $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'], true);
-			}
+			$json['redirect'] = $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'], true);
 		}
 
 		$this->response->addHeader('Content-Type: application/json');
 		$this->response->setOutput(json_encode($json));
 	}
diff --git a/upload/admin/view/template/common/login.twig b/upload/admin/view/template/common/login.twig
index a373bb8700..65fe5e3d9b 100644
--- a/upload/admin/view/template/common/login.twig
+++ b/upload/admin/view/template/common/login.twig
@@ -33,13 +33,10 @@
                 {% endif %}
               </div>
               <div class="text-end">
                 <button type="submit" class="btn btn-primary"><i class="fa-solid fa-key"></i> {{ button_login }}</button>
               </div>
-              {% if redirect %}
-                <input type="hidden" name="redirect" value="{{ redirect }}"/>
-              {% endif %}
             </form>
           </div>
         </div>
       </div>
     </div>

Vulnerable code: 		if (isset($this->request->get['route']) && $this->request->get['route'] != 'common/login') {
			$args = $this->request->get;

			$route = $args['route'];

			unset($args['route']);
			unset($args['user_token']);

			$url = '';

			$url .= http_build_query($args);

			$data['redirect'] = $this->url->link($route, $url);
		} else {
			$data['redirect'] = '';
		}

			if ($this->request->post['redirect'] && str_starts_with(html_entity_decode($this->request->post['redirect'], ENT_QUOTES, 'UTF-8'), HTTP_SERVER)) {
				$json['redirect'] = html_entity_decode($this->request->post['redirect'], ENT_QUOTES, 'UTF-8') . '&user_token=' . $this->session->data['user_token'];
			} else {
				$json['redirect'] = $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'], true);
			}
              {% if redirect %}
                <input type="hidden" name="redirect" value="{{ redirect }}"/>
              {% endif %}
Fixed code: 			$json['redirect'] = $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'], true);