Comprendre les Exit Programs

 SÉCURITÉ IBM i

Comprendre les Exit Programs



(Une bouteille de Champomy pour qui comprendra le lien entre cette photo et l'article...)

1. Introduction et positionnement conceptuel

1.1 De quoi parle-t-on ?

Un point de sortie (exit point) est un emplacement défini par l'OS, dans le cheminement d'une fonction système, où l’IBM i accepte d'appeler un programme fourni par le client :  le programme d'exit (exit program). Ce programme reçoit des informations sur la requête en cours (utilisateur, fonction demandée, objet visé, adresse IP…) et renvoie une décision : autoriser ou refuser. Le registre de ces associations se consulte et se gère via la commande WRKREGINF.

Les exit points sont donc un mécanisme d'interception réseau : ils permettent de filtrer finement les accès qui transitent par les serveurs hôtes (ODBC, FTP, DDM, remote command, partages de fichiers, etc.) là où l'autorité objet native, elle, ne distingue pas le protocole utilisé.

1.2 Le modèle mental à ancrer avant tout

C'est le message le plus important de ce document, celui qui conditionne la lecture de toutes les faiblesses qui suivent : un programme d'exit est un contrôle compensatoire, pas la sécurité primaire.

La sécurité primaire d'IBM i, c'est le modèle d'autorité au niveau objet (qui a le droit de lire/modifier quel objet), adossé au durcissement système (valeurs système, profils, adopted authority maîtrisée). Les exit points viennent par-dessus, en défense en profondeur, pour filtrer et tracer des chemins d'accès spécifiques. Ils ne créent pas de sécurité là où l'autorité objet est absente ; ils ajoutent une couche là où elle existe déjà.

L'image à retenir

Un périmètre dur autour d'un intérieur mou reste mou.

Si la donnée est en *PUBLIC *CHANGE et l'utilisateur *ALLOBJ, le meilleur exit program du monde ne fera que journaliser proprement un accès qu'il ne peut pas empêcher par ailleurs.

1.3 Comment lire ce document

Le catalogue des faiblesses est organisé en cinq familles : (A) les défauts de conception du programme lui-même, (B) les trous de couverture du périmètre, (C) les angles morts structurels que les exit points ne voient jamais, (D) les faiblesses opérationnelles et de gouvernance, et (E) ce que les exit points ne remplacent pas. Chaque faiblesse est présentée selon le même triptyque : Mécanisme (le pourquoi), Scénario (un cas concret), Parade (la bonne pratique).

2. Rappel du fonctionnement : pour comprendre les faiblesses

On ne comprend une faiblesse qu'en comprenant le mécanisme qui la produit. Trois notions suffisent.

Point de sortie → format → programme
Le flux d'un appel
Le code retour est le seul verrou

Un point de sortie n'est pas monolithique. Il expose un ou plusieurs formats (des structures de paramètres versionnées : par exemple les formats de requête SQL du serveur base de données). Un même point de sortie peut évoluer et gagner de nouveaux formats au fil des releases de l’OS. On enregistre un programme d'exit pour un couple (point de sortie, format) donné, d'où un premier risque : ne traiter qu'un format et en ignorer un autre.

  • Le client ouvre une session serveur (ex. un job QZDASOINIT pour ODBC/JDBC).

  • À chaque requête concernée, l'OS appelle le programme d'exit enregistré en lui passant la structure du format.

  • Le programme analyse, décide, et positionne un code retour (typiquement '1' = autoriser, '0' = refuser, selon le format).

  • L'OS applique la décision. Si le programme ne répond pas correctement, le comportement par défaut s'applique, et c'est là que tout se joue.

Toute la sécurité repose sur un octet renvoyé correctement, dans tous les chemins d'exécution du programme, y compris les chemins d'erreur. Retenez cette phrase : la robustesse d'un exit program se mesure à son comportement quand il échoue, pas quand tout va bien.

3. Catalogue des faiblesses

A. Défauts de conception du programme lui-même

A.1 : Le fail-open (ouverture par défaut)

Mécanisme : C'est le défaut le plus grave et le plus répandu. Pour la plupart des points de sortie, si le programme d'exit plante, boucle, tombe en MSGW ou ne positionne pas explicitement son code retour, le comportement par défaut de l'OS est de laisser passer la requête. Un programme mal blindé qui échoue n'est pas un programme qui bloque : c'est un programme qui autorise.

Scénario : Un MONMSG oublié sur un CHAIN vers un fichier de règles inaccessible provoque une exception. Le programme se termine anormalement, le code retour n'est jamais mis à '0', et l'accès ODBC est accordé. Pire : le jour où le fichier de règles est en cours de réorganisation, tout le trafic passe en grand.

Parade : Concevoir en fail-closed : initialiser le code retour à « refuser » dès l'entrée, ne le passer à « autoriser » qu'au terme d'un chemin nominal validé, et intercepter toutes les exceptions (MONMSG de portée, gestion ILE) pour refuser explicitement en cas de doute. La question de conception n'est pas « quand est-ce que je bloque ? » mais « qu'est-ce qui se passe si mon code ne va pas jusqu'au bout ? ».

A.2 : Gestion d'exceptions incomplète

Mécanisme : Corollaire du précédent. Un exit program touche des ressources externes (fichiers de règles, data areas, appels d'API, parfois requêtes réseau). Chacune est un point de défaillance. Une gestion d'erreur partielle laisse des chemins où le code retour reste indéterminé.

Scénario : Le programme lit sa table de règles par SQL. En cas de deadlock ou de timeout DB, l'exception SQL n'est pas captée pour ce chemin précis : alors qu'elle l'est pour la lecture nominale. Résultat : sous charge, le contrôle saute silencieusement.

Parade : Traiter l'exit program comme un composant critique : gestion d'exception exhaustive, chemin de repli déterministe (toujours vers le refus), et journalisation de l'incident pour investigation.

A.3 : Liste noire au lieu de liste blanche

Mécanisme : Un programme construit en « j'autorise tout, sauf ce que j'interdis explicitement » (blocklist) est structurellement fragile : tout cas non prévu passe. Le modèle robuste est l'inverse : « je refuse tout, sauf ce que j'autorise explicitement » (allowlist / deny-by-default).

Scénario : Les règles bloquent DELETE et DROP sur une bibliothèque. Un nouveau verbe ou une nouvelle voie d'accès (un CALL de procédure stockée qui fait le DELETE en interne) n'est pas dans la liste noire : il passe.

Parade : Par défaut refuser, puis ouvrir nommément les opérations, utilisateurs et origines légitimes. C'est plus contraignant à établir, mais c'est le seul modèle qui vieillit bien : un cas oublié échoue du bon côté.

A.4 : Décider sur la requête, pas sur la donnée

Mécanisme : Beaucoup de formats ne présentent au programme d'exit que la requête (nom du serveur, fonction, parfois le texte SQL), pas le contenu effectivement lu ni les colonnes renvoyées. Le programme filtre une intention exprimée, pas un résultat.

Scénario : On autorise un SELECT sur une vue « métier » réputée sans données sensibles. Mais la vue joint, en arrière-plan, une table contenant des IBAN. L'exit program n'a vu qu'un SELECT anodin ; il n'a aucune visibilité sur les colonnes remontées.

Parade : Ne jamais compter sur l'exit point pour du contrôle au niveau colonne/ligne : cela relève de la sécurité objet, des vues autorisées, et surtout de Row and Column Access Control (RCAC). L'exit point filtre le canal, pas la confidentialité fine de la donnée.

A.5 : Le coût en performance (et le DoS involontaire)

Mécanisme : Le programme s'exécute à chaque requête concernée. Il est donc sur le chemin critique de toutes les transactions du protocole. Un accès disque non optimisé, un appel synchrone lent, une journalisation bloquante, et l'exit program devient le goulot d'étranglement : voire un déni de service que l'on s'inflige à soi-même.

Scénario : Chaque requête ODBC déclenche une lecture full-table de la table de règles sans index adapté. À dix connexions, invisible. À trois cents, le serveur base de données s'effondre et l'exploitation « débranche » l'exit program en urgence : supprimant du même coup toute la sécurité.

Parade : Optimiser comme un composant de production temps réel : accès indexés, mise en cache maîtrisée des règles, pas d'I/O synchrone évitable, mesure de la latence ajoutée. Une sécurité que l'exploitation est tentée de désactiver n'est pas une sécurité.

A.6 : État partagé, réentrance, multithread

Mécanisme : Les jobs serveurs sont réutilisés et certains contextes sont multi-thread. Un exit program qui s'appuie sur un état persistant mal maîtrisé (variables statiques, data area partagée, activation group mal choisi) peut mélanger les décisions entre requêtes ou entre utilisateurs.

Scénario : Le programme met en cache « utilisateur autorisé » dans une variable de module persistante pour gagner en performance. Le job serveur est réutilisé pour un autre utilisateur ; le cache n'est pas réinitialisé ; le second utilisateur hérite de la décision du premier.

Parade : Concevoir sans état implicite : ré-évaluer chaque requête à partir de ses seuls paramètres, choisir l'activation group avec soin, et se méfier de tout cache dont la clé n'inclut pas l'identité effective de la requête.

A.7 : Fenêtre TOCTOU (time-of-check / time-of-use)

Mécanisme : La décision est prise à l'instant de l'appel, sur la base d'informations qui peuvent changer entre le contrôle et l'usage réel. L'écart, même bref, est exploitable.

Scénario : Le programme autorise sur la foi d'une adresse IP ou d'un nom d'objet, mais la ressource visée est modifiée (renommage, redirection) après la décision et avant l'accès effectif.

Parade : Réduire au minimum l'écart entre décision et application, s'appuyer sur des attributs stables, et ne pas déporter dans l'exit program des contrôles que l'autorité objet applique, elle, au moment exact de l'accès.

B. Trous de couverture du périmètre

B.1 : Points de sortie non couverts

Mécanisme : Chaque protocole a son propre point de sortie. Couvrir FTP et ODBC ne protège que FTP et ODBC. La faiblesse n'est pas dans le programme mais dans la carte des points enregistrés : il suffit d'un protocole oublié donnant accès à la même donnée pour que tout le reste devienne cosmétique.

Scénario : L'ODBC est verrouillé avec soin. Mais DDM/DRDA reste ouvert, ou le remote command (QZRCSRVS), ou un partage NetServer : le même fichier est atteint par une porte que personne ne surveille.

Les oublis classiques, à recouper systématiquement (voir la table de référence en annexe) :

  • Base de données : accès ODBC / JDBC / DB2 CLI et requêtes SQL (serveur QZDASOINIT).

  • DDM / DRDA : accès distant aux données et à la base, granularité de filtrage historiquement plus limitée qu'en ODBC : à vérifier précisément selon la version.

  • Remote command / appel de programme distant (QZRCSRVS) : l'un des vecteurs les plus sous-estimés.

  • Partages de fichiers et IFS : NetServer et serveur de fichiers hôte.

  • FTP : les deux points, logon ET requête. Filtrer l'un sans l'autre laisse un trou béant.

  • Telnet (init/term de device), Signon server, REXEC : souvent négligés.

  • Filtrage bas niveau optionnel des connexions socket via QIBM_QSO_ACCEPT.

Parade : Cartographier tous les chemins d'accès à chaque donnée sensible, protocole par protocole, puis vérifier la couverture par WRKREGINF. Raisonner par la donnée (« comment peut-on atteindre ce fichier ? ») et non par le protocole (« ai-je sécurisé ODBC ? »).

B.2 : Formats multiples au sein d'un même point

Mécanisme : Un point de sortie peut exposer plusieurs formats. Enregistrer un programme sur un format et ignorer les autres laisse passer, sans alerte, les requêtes qui empruntent le format non traité.

Scénario : Le serveur base de données distingue plusieurs formats (initialisation, requête native, requête SQL, récupération d'informations objet). On traite le format SQL, on ignore le format d'accès natif : un ordre qui n'emprunte pas le canal SQL passe sous le radar.

Parade : Traiter l'ensemble des formats pertinents d'un point de sortie, et ne jamais coder « en dur » l'hypothèse qu'il n'existe qu'un seul format.

B.3 : Chemins alternatifs vers la même donnée

Mécanisme : Généralisation de B.1 : la même donnée est souvent atteignable par plusieurs voies fonctionnellement équivalentes. Sécuriser une voie déplace simplement l'attaquant (ou l'utilisateur négligent) vers la suivante.

Scénario : Extraction interdite par ODBC ? On passe par un download FTP du membre, ou par un partage de fichier, ou par un transfert via remote command. La donnée sort quand même.

Parade : Penser en surface d'attaque complète et non en canaux isolés. Un contrôle n'est réel que s'il couvre toutes les voies équivalentes ; sinon il ne fait que déplacer le problème.

B.4 : Nouveaux points de sortie à chaque release

Mécanisme : IBM ajoute des points de sortie (et parfois des formats) au fil des versions et des Technology Refreshes. Une couverture correcte à un instant T se dégrade mécaniquement si personne ne réévalue le périmètre après montée de version.

Scénario : Une couverture jugée complète en 7.4 laisse un nouveau vecteur non filtré après passage en 7.5, faute d'avoir rejoué l'analyse WRKREGINF post-migration.

Parade : Intégrer la revue des points de sortie au processus de montée de version et de TR. La couverture est un état à re-vérifier, jamais un acquis définitif.

C. Angles morts structurels : ce que les exit points ne voient jamais

Les familles A et B concernent des trous que l'on peut boucher. La famille C, elle, décrit les limites intrinsèques du mécanisme : aucun exit program, si parfait soit-il, ne les couvre. C'est le cœur du message de ce document.

C.1 : L'accès natif 5250 et la ligne de commande

Mécanisme : Les points de sortie réseau interceptent des fonctions serveur réseau. Une session 5250 native ne passe pas par ces serveurs : ce qu'un utilisateur fait à un écran de commande échappe totalement au filtrage exit point.

Scénario : On verrouille l'ODBC pour empêcher la lecture d'un fichier RH. Un utilisateur avec un accès 5250 et une ligne de commande fait un simple DSPPFM ou RUNQRY sur le même fichier. L'exit program n'a rien vu passer, et pour cause.

Parade : Contrôler l'accès natif par d'autres leviers : LMTCPB(*YES) sur les profils, menus contraints, retrait de la ligne de commande, et surtout autorité objet. L'exit point ne compense pas un accès natif trop permissif.

C.2 : Batch, SBMJOB, appels de programme directs

Mécanisme : Un travail batch, un SBMJOB, un CALL direct ne franchissent aucun point de sortie réseau. Toute la logique exécutée localement est hors champ.

Scénario : Un programme soumis en batch lit et exporte des données vers l'IFS. Aucun exit point réseau n'est concerné ; le contrôle est totalement absent sur ce chemin.

Parade : La maîtrise du batch relève de l'autorité objet, du contrôle des files de travaux et des profils qui les alimentent : pas des exit points.

C.3 : L'autorité objet et le fléau *ALLOBJ

Mécanisme : Un exit program peut refuser un accès réseau, mais il ne modifie pas l'autorité de l'utilisateur sur l'objet. Si le profil est *ALLOBJ, il a de toute façon tous les droits par toutes les voies non filtrées. Et si l'objet est en *PUBLIC *CHANGE, l'exit point est la seule barrière : une barrière percée par tout canal non couvert.

Scénario : L'exit program journalise consciencieusement les accès ODBC d'un compte *ALLOBJ pendant que ce compte fait ce qu'il veut en 5250, en batch et en DDM. La trace est belle ; la sécurité, illusoire.

Parade : Réduire drastiquement les *ALLOBJ, appliquer le moindre privilège au niveau objet, remonter les *PUBLIC vers *EXCLUDE avec autorisation nommée. L'exit point ne se substitue jamais à ce travail de fond ; il le complète.

C.4 : Adopted authority et profile swap

Mécanisme : L'autorité empruntée (adopted authority) et l'échange de profil (QSYGETPH/QWTSETP) modifient l'autorité effective en cours d'exécution. Un contrôle exit point fondé sur l'identité initiale peut être court-circuité par du code qui, une fois passé le contrôle, opère sous une autre autorité.

Scénario : Une procédure autorisée par l'exit program adopte l'autorité d'un profil applicatif puissant et réalise, sous ce couvert, des opérations que l'utilisateur d'origine n'aurait jamais pu faire directement.

Parade : Auditer les programmes qui adoptent l'autorité et les usages de profile swap, indépendamment des exit points. Ne pas présumer que l'identité vue à l'entrée est l'autorité réellement en jeu à l'usage.

C.5 : Le filtrage par adresse IP est peu fiable

Mécanisme : Beaucoup de règles s'appuient sur l'adresse IP source. Or une IP n'est pas une identité : elle peut être usurpée, translatée (NAT), mutualisée (postes derrière une même passerelle), dynamique (DHCP) ou masquée (VPN, rebond). Une règle « autoriser 10.0.0.0/24 » autorise potentiellement quiconque atteint ce sous-réseau.

Scénario : On autorise le range du réseau interne. Un poste compromis, ou un rebond via VPN, présente une IP « de confiance » et passe le contrôle sans difficulté.

Parade : Traiter l'IP comme un signal d'appoint, jamais comme une authentification. La confiance doit reposer sur l'identité authentifiée et l'autorité, pas sur la topologie réseau.

C.6 : Identité de la requête vs profil effectif

Mécanisme : Le profil présenté au point de sortie n'est pas toujours celui sous lequel s'exécutera réellement l'action (cf. C.4), et certains contextes (connexions applicatives mutualisées, pools de connexions) présentent un profil technique unique pour de multiples utilisateurs finaux.

Scénario : Un middleware se connecte en base sous un compte de service unique pour cent utilisateurs finaux. L'exit program ne voit que le compte de service : impossible de distinguer, refuser ou tracer l'utilisateur réel.

Parade : Là où l'identité finale compte, l'imposer au niveau applicatif (propagation d'identité, SET SESSION AUTHORIZATION, etc.) et ne pas attendre de l'exit point qu'il désambiguïse (néologisme achille-talonien assumé) ce qu'on ne lui donne pas.

D. Faiblesses opérationnelles et de gouvernance

D.1 : Le programme désactivé ou absent, sans alerte

Mécanisme : Un point de sortie dont le programme est supprimé, renommé, mis en *DISABLED, ou dont la bibliothèque n'est plus dans le chemin, se retrouve de facto en fail-open : le plus souvent silencieusement. La sécurité disparaît sans que rien ne le signale.

Scénario : Lors d'une restauration partielle, la bibliothèque de l'exit program n'est pas remontée. Les points de sortie pointent dans le vide ; tout le trafic passe ; aucune alarme ne se déclenche.

Parade : Superviser activement l'existence et l'état des enregistrements (contrôle périodique de WRKREGINF, vérification que les programmes existent et sont actifs) et alerter sur toute dérive.

D.2 : La maintenance dans la durée

Mécanisme : Les règles vieillissent : utilisateurs partis encore autorisés, IP obsolètes, exceptions temporaires devenues permanentes. Un jeu de règles non entretenu diverge lentement de la réalité et se remplit de trous « pour dépanner ».

Scénario : Une règle « autoriser exceptionnellement » posée pour une migration trois ans plus tôt est toujours là, oubliée, et constitue désormais un bypass permanent.

Parade : Revue périodique documentée des règles, dates d'expiration sur les exceptions, et rattachement des autorisations à un propriétaire fonctionnel.

D.3 : Journalisation : trous et articulation avec QAUDJRN

Mécanisme : Deux écueils. D'abord, un exit program qui décide sans journaliser (ou qui journalise dans un fichier applicatif fragile) prive d'analyse forensique. Ensuite, croire que la trace exit point remplace le journal d'audit système : elle ne voit que ce qui passe par les points couverts, donc pas les angles morts de la famille C.

Scénario : Après incident, on cherche l'origine d'une fuite. La trace exit point ne montre rien : l'extraction s'est faite en 5250 natif, invisible pour elle. Le QAUDJRN, lui, l'aurait vue.

Parade : Journaliser chaque décision de manière fiable ET s'appuyer sur QAUDJRN comme source d'audit de référence. Les deux sont complémentaires ; aucun ne couvre le champ de l'autre.

D.4 : Personne ne surveille le superviseur

Mécanisme : L'exit program devient un composant de sécurité central mais souvent non supervisé lui-même : pas de contrôle d'intégrité de son code, pas d'alerte sur la modification de ses règles, autorité de modification trop large.

Scénario : Un opérateur disposant du droit de modifier la table de règles s'y ajoute une exception à son nom. Rien ne le détecte, car la table n'est ni protégée ni auditée à part.

Parade : Protéger le programme et ses règles par une autorité objet stricte, auditer leurs modifications dans QAUDJRN, et séparer les rôles (qui exploite ≠ qui définit les règles).

D.5 : La testabilité

Mécanisme : Un exit program a de nombreux chemins (formats, protocoles, cas d'erreur, cas limites). Les tester tous est difficile ; les chemins non testés sont précisément ceux où se cachent les fail-open et les décisions erronées.

Scénario : Le chemin nominal est validé, mais le comportement en cas d'indisponibilité de la table de règles n'a jamais été testé: et se révèle être un fail-open le jour où la table est verrouillée.

Parade : Constituer un jeu de tests couvrant explicitement les chemins d'erreur et les cas limites, et vérifier le comportement en échec (doit refuser), pas seulement le comportement nominal.

D.6 : La dépendance à une solution éditeur (effet boîte noire)

Mécanisme : Les solutions du marché (Fortra/PowerTech, Raz-Lee, etc.) sont robustes et font gagner un temps considérable : mais elles n'exonèrent pas de comprendre le périmètre. Faire confiance sans configurer ni vérifier reproduit toutes les faiblesses ci-dessus derrière une interface rassurante.

Scénario : L'outil est installé mais laissé en mode « journalisation seule », ou avec des règles par défaut trop permissives. Le tableau de bord est vert ; le filtrage réel est quasi nul.

Parade : Un outil éditeur est un accélérateur, pas une dispense d'analyse. Vérifier ce qui est réellement couvert, en quel mode (audit vs blocage), avec quelles règles: exactement comme pour un développement maison.

E. Ce que les exit points ne remplacent pas

E.1 : Le chiffrement du flux

Mécanisme : Les exit points filtrent le qui/quoi ; ils n'assurent aucune confidentialité du transport. La donnée autorisée transite en clair si TLS/SSL n'est pas configuré par ailleurs, exposée à l'écoute réseau.

Parade : Chiffrer les flux (TLS sur les serveurs hôtes, FTPS/SFTP, etc.) est un sujet distinct et complémentaire. Un exit program ne protège rien contre un sniffer.

E.2 : Le modèle d'autorité objet

Mécanisme : Répété ici car c'est le point cardinal : les exit points ne créent pas d'autorité, ils filtrent des canaux. La sécurité réelle d'un objet est son autorité (propriétaire, autorisations privées et publiques, listes d'autorisation).

Parade : Construire d'abord un modèle d'autorité propre (moindre privilège, *PUBLIC restreint), puis ajouter les exit points en défense en profondeur : jamais l'inverse.

E.3 : Le durcissement système global

Mécanisme : Valeurs système de sécurité (QSECURITY à 40/50, QCRTAUT, contrôle des profils, mots de passe), gestion des profils puissants, sécurité de l'IFS : autant de fondations qu'aucun exit program ne remplace.

Parade : Traiter les exit points comme une couche parmi d'autres d'une posture de sécurité globale, cohérente et documentée.

4. Synthèse : la checklist de l'exit program robuste

Un programme d'exit n'apporte de la sécurité que si toutes les cases ci-dessous sont cochées. Un seul manquement suffit souvent à annuler l'ensemble.

☐  Fail-closed : Le programme refuse par défaut et n'autorise qu'au terme d'un chemin nominal validé ; toutes les exceptions mènent au refus.

☐  Couverture complète : Tous les protocoles et tous les formats donnant accès à une même donnée sont enregistrés et traités (vérifié par WRKREGINF).

☐  Deny-by-default : Modèle liste blanche : on ouvre nommément, on ne ferme pas au cas par cas.

☐  Complément, pas substitut : L'autorité objet est propre (moindre privilège, *PUBLIC restreint, *ALLOBJ réduits) ; l'exit point vient par-dessus.

☐  Performance maîtrisée : Latence mesurée, accès indexés, pas d'I/O synchrone évitable : l'exploitation n'est jamais tentée de le désactiver.

☐  Sans état implicite : Chaque requête est ré-évaluée sur ses seuls paramètres ; aucun cache indexé sur autre chose que l'identité effective.

☐  Supervisé : Existence, état et intégrité du programme et de ses règles sont surveillés ; toute dérive alerte.

☐  Journalisé + QAUDJRN : Chaque décision est tracée de façon fiable, en complément du journal d'audit système de référence.

☐  Testé en échec : Les chemins d'erreur et cas limites sont explicitement testés, pas seulement le nominal.

☐  Gouverné : Règles entretenues, exceptions datées, rôles séparés, modifications auditées.

☐  Chiffrement traité à part : TLS/SSL assure la confidentialité du flux, indépendamment du filtrage.


La phrase à retenir de tout ceci : 


Les exit points ne valent que si  : 

(a) ils échouent en mode fermé, 

(b) tous les chemins vers une même donnée sont couverts, et 

(c) ils viennent en complément d'un modèle d'autorité objet propre : jamais à sa place.


Le mantra à répéter tous les matins en se levant (et tous les soirs en se couchant) : 


Un périmètre dur autour d'un intérieur mou reste mou.

5. Dangers concrets par point de sortie

Cette section répond à une question simple : à quoi s'expose-t-on, concrètement, si tel point de sortie est laissé ouvert (ou en simple journalisation) ? Les points sont regroupés par niveau de gravité : du plus critique (exécution de code) au plus indirect (reconnaissance, portes d'entrée). 

Le fil rouge : un seul chemin non filtré annule le filtrage de tous les autres qui mènent à la même donnée.

Niveau 1 : Exécution de commandes à distance (le plus grave)

Ces trois points ouvrent, à des degrés divers, un canal d'exécution de commandes CL ou d'appel de programme depuis le réseau. C'est l'équivalent d'un shell distant : compromission complète possible si le profil est puissant.

QIBM_QZRC_RMT : Le plus dangereux de la liste. Exécution de commandes CL et appel de programmes à distance depuis un PC (serveur QZRCSRVS). Ouvert : commandes destructrices (CLRPFM, DLTF…), appel de n'importe quel programme, abus de privilège et mouvement latéral. Vecteur premier de compromission.

QIBM_QTMF_SERVER_REQ : La requête FTP réelle (GET, PUT, DELETE…). Exfiltration et upload en masse de membres et de fichiers IFS, suppression : et surtout le sous-ordre QUOTE RCMD / SITE qui exécute des commandes CL. FTP non filtré = exfiltration ET exécution de commandes. À coupler impérativement au logon.

QIBM_QTMX_SERVER_REQ : REXEC : exécution de commandes distantes, sans détour. Si le serveur REXEC tourne et que ce point est ouvert, c'est un canal RCE direct. Piège classique : personne ne se souvient que REXEC est actif, donc personne ne le filtre.

Niveau 2 : Ransomware et compromission de l'IFS

QIBM_QPWFS_FILE_SERV : Accès IFS via serveur de fichiers hôte. Non filtré : lecture/écriture libre sur l'IFS depuis un poste. Téléchargement de ce qui traîne (certificats, clés TLS, save files, exports, relevés), dépôt de code malveillant, et cible directe de ransomware chiffrant l'arborescence. L'IFS concentre souvent le pire à exposer.

NetServer : Partages SMB vers l'IFS (et QSYS.LIB). Non maîtrisé : lecteur réseau mappé depuis Windows → exfiltration, dépôt de malware, et surtout ransomware (un poste Windows compromis avec un lecteur IBM i mappé chiffre le partage). Un accès invité mal configuré ouvre les partages en anonyme.

Niveau 3 : Exfiltration et modification massives de données

QIBM_QZDA_SQL1 / SQL2 : Le vecteur d'exfiltration et de modification de masse. Ces formats voient le SQL réel : SELECT * sur les salaires ou les IBAN tiré dans Excel, UPDATE / DELETE / DROP si l'autorité le permet, appel de procédures stockées : hors de toute logique applicative. Cauchemar RGPD type. Les deux formats sont à couvrir ensemble.

QIBM_QZDA_NDB1 : Accès natif record-level (et transfert de données Client Access). La porte dérobée de SQL : si l'on filtre le SQL mais pas le natif, on lit et on écrit les fichiers directement. Danger double : download natif (extraction) et upload natif (injection / corruption des fichiers de production).

DDM / DRDA : Serveur distinct (QRWTSRVR) : accès distant aux données (DDM) et SQL distant (DRDA). Danger majeur : le contournement. On blinde l'ODBC côté QZDA, on atteint la même donnée par DDM, un nommage à trois parties ou une entrée de répertoire RDB. Granularité de filtrage historiquement plus limitée qu'en ODBC : à vérifier sur la version cible. C'est la porte de derrière vers les mêmes données.

Niveau 4 : Confidentialité et reconnaissance

QIBM_QNPSERVR : Serveur d'impression réseau : accès aux fichiers spoule. Les spools contiennent régulièrement du très sensible : bulletins de paie, factures, relevés, états nominatifs. Ouvert : récupération à distance de sorties que l'on ne devrait jamais voir. Fuite de confidentialité par un canal qu'on oublie de regarder.

QIBM_QZDA_ROI1 : Retrieve Object Information : le format de reconnaissance. Renvoie le catalogue : bibliothèques, fichiers, champs, formats. Pas de vol direct, mais il livre le plan du bâtiment, et les noms d'objets fuient déjà de l'info métier. Première étape de toute attaque, trop souvent négligée.

QIBM_QZHQ_DATA_QUEUE : Accès distant aux data queues (messages inter-jobs, parfois données transactionnelles). Trois dangers : écoute (lire les échanges métier), injection (empoisonner une file qui pilote un traitement → fausses transactions), effacement (vider une file pour casser un flux → DoS interne). Atteinte à l'intégrité et à la disponibilité des rouages applicatifs.

Niveau 5 : Portes d'authentification et d'entrée

Ces points ne donnent pas directement accès à la donnée, mais commandent qui peut entrer et d'où. Les laisser ouverts, c'est offrir la surface d'attaque (brute force, spraying) et perdre le contrôle d'accès par identité et par origine.

QIBM_QZDA_INIT : Le portier du dialogue serveur base de données. Non filtré, tout profil valide peut ouvrir une session DB depuis n'importe quel poste (Excel, DBeaver, Python, Power BI…). C'est ici : et seulement ici : que l'on décide qui a le droit d'établir une session DB et depuis où.

QIBM_QZSO_SIGNONSRV : Serveur de signon (authentification et changement de mot de passe des clients). Façade d'attaque des mots de passe : brute force et password spraying depuis le réseau, avec au choix compromission ou DoS par verrouillage (QMAXSIGN). Porte d'entrée des serveurs hôtes.

QIBM_QTMF_SVR_LOGON : Le logon FTP : qui s'authentifie en FTP et depuis quelle IP. Ouvert : surface de brute force FTP et accès non maîtrisé. Filtrer le logon sans la requête (niveau 1) laisse un authentifié tout faire une fois entré.

QIBM_QTG_DEVINIT : Initialisation de device Telnet (émulation 5250). Non filtré : n'importe quelle IP ouvre un écran vert, sans restriction par device / IP / utilisateur. Et une fois dans une session 5250, on bascule dans le monde natif que les autres exit points ne voient plus : d'où l'importance doublée de verrouiller l'entrée.

Cas particulier : le filet de rattrapage

QIBM_QSO_ACCEPT : Exit socket accept, bas niveau. Ici le risque de « ne pas le faire » est différent : c'est un filet de rattrapage, pas un contrôle primaire. Son absence prive de toute maille pour ce qui n'a pas de point de sortie dédié, et d'un contrôle de connexion par IP au niveau socket. À manier avec parcimonie (coûteux, grossier), mais c'est la seule couche « attrape-tout ».


Hiérarchie de gravité : à poser au tableau

1. Exécution de commandes (QZRC_RMT, FTP via RCMD, REXEC) : RCE, le plus grave.

2. Ransomware / IFS (QPWFS_FILE_SERV, NetServer).

3. Exfiltration et modification de données (QZDA_SQL1/2, QZDA_NDB1, DDM/DRDA).

4. Confidentialité et reconnaissance (QNPSERVR, QZDA_ROI1, QZHQ_DATA_QUEUE).

5. Portes d'authentification et d'entrée (QZDA_INIT, QZSO_SIGNONSRV, QTMF_SVR_LOGON, QTG_DEVINIT).

6. Feuille de route de remédiation

Un audit qui ne livre que la liste des maux n'est fait qu'à moitié : la valeur est dans l'ordonnance, pas dans le diagnostic. 

Le message à passer d'emblée à un comité inquiet est simple : tout ceci se répare, et dans un ordre précis qui évite de casser la production en route.

Le principe : réparer dans l'ordre, sans rupture

Deux réflexes structurent toute la démarche. D'abord, le meilleur programme d'exit est celui qu'on n'a pas à écrire : on réduit la surface avant de filtrer. Ensuite, on observe avant de bloquer : aucun blocage n'est activé sans avoir mesuré le trafic réel au préalable.

Étape 0 : L'état des lieux factuel

Avant de toucher à quoi que ce soit : QSYS2.EXIT_POINT_INFO et EXIT_PROGRAM_INFO pour la couverture réelle, et surtout la cartographie donnée sensible → chemins d'accès. On ne sécurise pas des protocoles, on sécurise des données. En parallèle, le baseline qui recadre le débat : combien de profils *ALLOBJ, quels fichiers sensibles en *PUBLIC *CHANGE.

Étape 1 : Réduire la surface avant de filtrer (quick win)

La première victoire, rapide et sans code. Avant d'écrire un exit program pour bloquer REXEC, la vraie question est : REXEC tourne-t-il, et pour qui ? Dans la grande majorité des cas, personne ne s'en sert : on l'éteint (ENDTCPSVR + autostart *NO) et le danger disparaît. Idem pour DDM si inutilisé, pour FTP si SFTP l'a remplacé. Un serveur éteint est un serveur qu'on n'a pas à surveiller.

Étape 2 : Réparer les fondations (le chantier de fond)

Rappel du message cardinal : les exit points sont compensatoires. Tant que la donnée sensible est en *PUBLIC *CHANGE et que les *ALLOBJ pullulent, filtrer l'ODBC ne fait que déplacer le problème. En parallèle des étapes réseau, donc : réduction des *ALLOBJ, remontée des *PUBLIC sensibles vers *EXCLUDE avec autorisation nommée. C'est le travail qui compte vraiment, et le plus long.

Étape 3 : Observer avant de bloquer (quick win)

Le geste opérationnel qui évite la catastrophe. On déploie les exit programs en journalisation seule pendant quelques semaines. On récolte le trafic réel : qui se connecte, d'où, pour quoi faire. Double bénéfice : zéro rupture de production, et une liste blanche construite sur des faits observés, pas sur des suppositions. On arrive en réunion avec « voici ce qui se passe réellement chez vous », pas avec des hypothèses.

Étape 4 : Basculer au blocage, progressivement

Deny-by-default, une porte à la fois, en commençant par les vecteurs de niveau 1 (exécution de commandes : QZRC_RMT, FTP via RCMD, REXEC). Conception fail-closed, plan de rollback à chaque étape. On ne bascule jamais un blocage exit point en big bang.

Étape 5 : Superviser et gouverner dans la durée

Surveiller le superviseur (existence et intégrité des programmes et des règles), articuler avec QAUDJRN, dater les exceptions, séparer les rôles, et rejouer la revue de couverture à chaque Technology Refresh et montée de version. La sécurité par exit points est un état à entretenir, jamais un acquis.


Synthèse : le plan d'action priorisé

Étape

Action clé

Bénéfice

Effort / risque

0

État des lieux : EXIT_POINT_INFO, cartographie donnée→accès, comptage *ALLOBJ / *PUBLIC

Base factuelle, chiffres qui recadrent

Nul

1

Éteindre les serveurs inutiles (REXEC, DDM, FTP…)

Danger supprimé sans une ligne de code

Faible : quick win

2

Réparer l'autorité objet (*ALLOBJ, *PUBLIC → *EXCLUDE nommé)

Sécurité primaire réelle

Élevé : fond

3

Exit programs en journalisation seule

Liste blanche fondée sur le trafic réel, zéro rupture

Faible : quick win

4

Bascule au blocage, deny-by-default, une porte à la fois

Filtrage effectif, réversible

Moyen : progressif

5

Supervision + gouvernance (QAUDJRN, revues, TR)

Tenue dans la durée

Continu


La décision structurante : construire ou acheter

C'est la question honnête qu'un auditeur doit poser. Quand on aligne tout ce qu'exige un exit program correct : fail-closed, tous les formats, tous les protocoles, journalisation fiable, supervision, tests des chemins d'erreur, maintenance à chaque release : la conclusion, pour la majorité des sites, est : acheter.

Un gestionnaire du marché (Fortra/Powertech, Raz-Lee iSecurity, Kisco, SEA, Halcyon) apporte le moteur de règles, le mode simulation : exactement l'étape 3  : , le blocage, le reporting audit-ready et le suivi des nouveaux points de sortie. Le développement maison ne se justifie que pour un besoin étroit, bien cerné, avec les compétences pour le maintenir sur dix ans. Le dire clairement évite au client de sous-estimer un projet: et positionne l'auditeur en conseil, pas en marchand de peur.


Pour la restitution : priorité et quick wins d'abord

Éteindre l'inutile (étape 1) et passer en observation (étape 3) sont faisables en quelques jours, sans risque : du mouvement immédiat, qui débloque psychologiquement un comité inquiet.

Pendant ce temps, le chantier de fond : l'autorité objet (étape 2) : avance en arrière-plan.

Message à retenir : Pas de “big-bang” sur un blocage ; on observe, on ouvre nommément, on bascule porte par porte, rollback prêt.

7. Annexe : points de sortie à recouper (référence)

Liste de travail des principaux vecteurs à vérifier en audit. Les noms exacts de points de sortie et de formats doivent être confirmés sur la version cible via WRKREGINF : IBM en ajoute au fil des releases, et cette table est un point de départ, non une vérité figée.

Point de sortie

Domaine

Ce qui transite / à vérifier

QIBM_QZDA_INIT

Base de données (init)

Ouverture de session serveur BDD (ODBC/JDBC/CLI)

QIBM_QZDA_SQL1 / SQL2

Base de données (SQL)

Requêtes SQL : plusieurs formats à couvrir

QIBM_QZDA_NDB1

Base de données (natif)

Accès base de données natif

QIBM_QZDA_ROI1

Base de données (objets)

Récupération d'informations sur les objets

QIBM_QZRC_RMT

Remote command / prog.

Commande et appel de programme distants (QZRCSRVS)

QIBM_QPWFS_FILE_SERV

Fichiers / IFS

Serveur de fichiers hôte (accès IFS)

QIBM_QZHQ_DATA_QUEUE

Data queue

Accès aux files de données

QIBM_QNPSERVR

Impression réseau

Serveur d'impression réseau

QIBM_QZSO_SIGNONSRV

Signon

Serveur d'authentification (signon)

QIBM_QTMF_SVR_LOGON

FTP (logon)

Authentification FTP entrante

QIBM_QTMF_SERVER_REQ

FTP (requête)

Validation des requêtes FTP : à coupler au logon

QIBM_QTMX_SERVER_REQ

REXEC

Exécution de commandes distantes REXEC

QIBM_QTG_DEVINIT

Telnet

Initialisation de device Telnet

QIBM_QSO_ACCEPT

Socket (bas niveau)

Filtrage optionnel des connexions entrantes

DDM / DRDA

Accès distant BDD

À vérifier : granularité de filtrage plus limitée

NetServer

Partages SMB

Partages de fichiers Windows : vecteur souvent oublié


Méthode d'audit recommandée : raisonner par la donnée sensible, pas par le protocole. Pour chaque fichier/objet critique, lister toutes les voies d'accès (réseau ET natives), vérifier lesquelles sont couvertes par un exit point en mode blocage (et non simple journalisation), et confirmer que les voies non couvrables par exit point (5250, batch, autorité objet) sont traitées par les leviers appropriés.

Correspondance : libellé API Finder ↔ point d'exit ↔ format

Table de traduction entre les libellés descriptifs affichés dans « All Exit Programs » de l'API Finder et les noms d'enregistrement QIBM_* utilisés par WRKREGINF. À noter : la seule entrée « Database server » regroupe les cinq points d'exit QZDA, et plusieurs points possèdent plus d'un format (à traiter tous).

Libellé (API Finder V7R5)

Point d'exit (QIBM_*)

Format(s)

Database server

QIBM_QZDA_INIT

ZDAI0100

Database server

QIBM_QZDA_NDB1

ZDAD0100 / ZDAD0200

Database server

QIBM_QZDA_ROI1

ZDAR0100 / ZDAR0200

Database server

QIBM_QZDA_SQL1

ZDAQ0100

Database server

QIBM_QZDA_SQL2

ZDAQ0200

Remote command and distributed program call server

QIBM_QZRC_RMT

CZRC0100

File Server

QIBM_QPWFS_FILE_SERV

PWFS0100

Data queue server

QIBM_QZHQ_DATA_QUEUE

ZHQ00100

Network print server

QIBM_QNPS_ENTRY

ENTR0100

Signon server

QIBM_QZSO_SIGNONSRV

ZSOY0100

FTP Server Logon

QIBM_QTMF_SVR_LOGON

TCPL0100 (+0200/0300)

FTP Server Request Validation

QIBM_QTMF_SERVER_REQ

VLRQ0100

FTP Client Request Validation

QIBM_QTMF_CLIENT_REQ

VLRQ0100

REXEC Server Command Processing Selection

QIBM_QTMX_SERVER_REQ

VLRQ0100

REXEC Server Logon

QIBM_QTMX_SVR_LOGON

TCPL0100

Telnet Device Initialization

QIBM_QTG_DEVINIT

INIT0100

Telnet Device Termination

QIBM_QTG_DEVTERM

TERM0100

Exit Program for Sockets accept() API

QIBM_QSO_ACCEPT

SOAC0100


Deux exceptions notables : elles n'apparaissent pas dans cette liste car ce ne sont pas des points d'exit de la Registration Facility. DDM / DRDA se contrôle par le paramètre DDMACC de la commande CHGNETA (attribut réseau). NetServer (partages SMB) n'a pas de point d'exit de requête : l'accès fichier retombe sur QIBM_QPWFS_FILE_SERV pour la couche IFS, le reste relevant de la configuration NetServer et de l'autorité objet.

Rappel de méthode : cette table est un point de départ ; la liste réelle et à jour de la machine cible s'obtient par SQL

Donc, voici du SQL : 

-- Tous les points de sortie et le nombre de programmes enregistrés

SELECT p.EXIT_POINT_NAME,

       p.EXIT_POINT_FORMAT,

       p.MAXIMUM_EXIT_PROGRAMS,

       p.REGISTERED_EXIT_PROGRAMS

  FROM QSYS2.EXIT_POINT_INFO p

 ORDER BY p.EXIT_POINT_NAME;


-- Détail : quels programmes sont réellement branchés

SELECT ep.EXIT_POINT_NAME, ep.EXIT_POINT_FORMAT,

       pr.EXIT_PROGRAM_NUMBER, pr.EXIT_PROGRAM_LIBRARY, pr.EXIT_PROGRAM

  FROM QSYS2.EXIT_POINT_INFO ep

  LEFT JOIN QSYS2.EXIT_PROGRAM_INFO pr

    ON ep.EXIT_POINT_NAME = pr.EXIT_POINT_NAME

   AND ep.EXIT_POINT_FORMAT = pr.EXIT_POINT_FORMAT

 ORDER BY ep.EXIT_POINT_NAME, pr.EXIT_PROGRAM_NUMBER;



Commentaires

Articles les plus consultés