MSMQ QueueJumper(RCE 취약점): 심층 기술 분석

야간 다중 디스플레이 작업 환경

Microsoft가 2023년 4월 11일에 발표한 보안 업데이트는 90개 이상의 개별 취약점을 해결했습니다. 특히 주목할 만한 것은 QueueJumper라는 이름의 CVE-2023-21554 , Microsoft Message Queueing(MSMQ) 서비스에 영향을 미치는 원격 코드 실행 취약점입니다. MSMQ는 애플리케이션에서 로컬 및 원격으로 모두 연결할 수 있는 메시지 큐를 통해 메시지를 교환할 수 있도록 하는 선택적 Windows 구성 요소입니다. 이 분석은 Valentina Palmiotti, Fabius Watson, Aaron Portnoy가 Randori 및 X-Force Adversary Services 팀과 협력하여 수행했습니다.

연구 동기

초기의 관심을 끌었던 CVE-2023-21554 특성은 다음과 같습니다.

  • 타사 애플리케이션마다 MSMQ 대기열을 다양하게 사용하기 때문에 환경 간 또는 환경 전반에 미치는 취약성 영향의 전체 범위를 파악하는 데 어려움이 있습니다.
  • 초기 보고서에서는 MSMQ 서비스가 노출된 인터넷 액세스 가능 호스트가 360,000개에 달한다고 설명했습니다. 당시 Shodan의 상담 건수는 250건에 불과했습니다. 이러한 불일치로 인해 노출 가능 범위가 더욱 불분명해졌습니다.
  • 이 취약점은 인증이 필요하지 않은 원격 코드 실행으로 분류되며 광범위한 Windows 플랫폼에도 영향을 미칩니다.
  • 유일한 명백한 요구 사항은 TCP 포트 1801에서 서비스에 연결할 수 있다는 것입니다.

초기 분류

MSMQ 엔드포인트 식별

MSMQ의 존재를 감지하는 방법을 결정하기 위해 실험실 환경에서 구성 요소로 테스트 시스템을 구성했습니다. 포트 1801에서 MSMQ 엔드포인트에 연결할 때 서버가 데이터로 응답하지 않았습니다. 서버가 합리적인 형식의 데이터를 수신하지 않으면 응답하지 않는다고 가정할 수 있습니다. 엔드포인트와 대화를 수행하는 방법을 이해하려면 기본 코드를 추가로 검사해야 했습니다.

MSMQ 코드 찾기

해당 권고사항에서는 어떤 바이너리가 패치되었는지 즉시 알 수 없습니다. 변경된 코드를 식별하는 첫 번째 단계는 업데이트 파일을 다운로드하는 것이었습니다. Microsoft 업데이트 카탈로그에서 KB5025224를 검색하면 됩니다.

MSMQ 코드 찾기 스크린샷

KB5025224에 대한 Microsoft Update Catalog 검색 결과

구체적으로 누적 업데이트 파일

windows10.0-kb5025224-x64_3522b1b562ed44bc949541dd1c7d08e1e967d925.msu 

Windows 11 x86 기반 시스템용 파일을 확보했습니다.

7-Zip 추출기를 사용하여 MSU 파일과 그 안에 포함된 CAB 파일의 내용을 압축 해제했습니다. 압축 해제된 결과 폴더의 모든 파일에서 “msmq” 문자열을 검색한 결과, 다음 항목을 포함하고 있는 Container Index 파일 

Windows11.0-KB5025239-x64/express.psf.cix.xml을

확인할 수 있었습니다.

<File id="21296" name="amd64_microsoft-windows-msmq-queuemanager-core_31bf3856ad364e35_10.0.22621.1555_none_5f975f8fdb349517\f\mqqm.dll" length="34811" time="133245266510000000" attr="128">

이 항목은 MQQM.dll 을 참조하고 있으며, 이는 추가 분석 대상으로 식별되었습니다.

패치된 코드 식별

MQQM.dll 파일의 패치 전후 변경 사항을 식별하기 위해 Zynamics의 BinDiff 툴을 사용했습니다. 다음 이미지는 유사도 점수가1.00 미만인 일치하는 함수들을 보여줍니다.

패치된 코드 스크린샷

패치된 MQQM.dll과 패치되지 않은 MQQM.dll 간의 BinDiff 결과 

Hex-Rays Decompiler를 사용하여 이러한 함수를 분석한 결과, Microsoft 보안 연구 센터(MSRC) 취약점 식별자를 참조하는 것으로 보이는 자세한 함수 이름이 포함된 패치 버전의 심볼이 발견되었습니다.

Microsoft Security Research Center(MSRC) 참조 스크린샷

MQQM.DLL 내의 기능 플래그 기호

기능 플래그 분석

자세히 살펴보면 MSRC 사례 번호가 포함된 기호는 취약점 수정을 위한 기능 플래그에 해당합니다. 기능 플래그는 다양한 기능과 실험을 토글하는 Windows의 구성 요소입니다. 여기서 발견된 ‘기능’은 실제로는 취약점에 대한 패치입니다. 기능이 활성화되면 패치된 안전한 코드 경로가 실행됩니다. 그렇지 않으면 패치되지 않은 원래 코드 경로가 실행됩니다.

패치되지 않은 원본 코드 경로 실행 스크린샷

취약점 수정을 위한 기능 플래그를 보여주는 디컴파일된 코드 스니펫

사용자 및 커널 구성 요소 모두에서 CVE-2023-21554를 구성하는 각 취약점에 대한 기능 플래그 검사가 있었습니다. 보안 업데이트 패키지에 포함된 나머지 바이너리를 분석한 결과, 2023년 4월 패치 화요일에 수정된 대부분의 취약점 또는 모든 취약점에 대해 기능 플래그가 도입된 것으로 나타났습니다.

근본 원인 분석

이러한 플래그를 교차 참조함으로써 패치된 코드 위치를 신속하게 특정할 수 있었습니다. 특히 MSRC76146_MSMQ_OOBRWFixes 플래그와 관련된 CQmPacket::CQmPacket 내부의 변경 사항이 가장 중요한 부분으로 보였습니다.

이 기능 플래그에 대한 확인은 함수 내에서 8번 이루어집니다. 이러한 검사 중 하나가 아래에 나와 있습니다.

근본 원인 분석 스크린샷

취약점 수정을 보여주는 디컴파일된 코드 스니펫 

위의 디컴파일된 코드 스니펫에서 패치된 코드 경로는 GetNextSectionPtrSafe. 호출을 통해 MSMQ 메시지의 다음 섹션을 가리키는 포인터를 획득합니다. 반면 패치되지 않은 경로에서는 아무런 검증 없이 섹션 크기를 단순히 더해 포인터를 계산합니다. 새로운 GetNextSectionPtrSafe 함수는 계산된 다음 섹션 포인터가 패킷 전체 길이를 초과하지 않는지 검증합니다.

함수 스크린샷

GetNextSectionPtrSafe 함수의 디컴파일 스니펫

이 기능 플래그 및 기타 항목의 모든 발생을 검토한 결과, CVE-2023-21554가 다양한 MSMQ 메시지 섹션 유형의 크기를 불충분하게 확인하는 몇 가지 버그로 구성되어 있는 것으로 확인되었습니다. 이러한 취약점으로 인해 MSMQ 메시지 끝에 대한 포인터가 원래 할당된 버퍼의 경계 외부로 임의의 32비트 오프셋만큼 증가할 수 있습니다.

패킷 처리 이후,  CQmPacket::CQmPacket의 마지막 단계에서는 패킷 버퍼의 끝에 OnDiskExtensionHeader을 추가합니다. 앞서 언급한 취약점으로 인해 메시지 끝을 가리키도록 계산된 포인터가 경계를 벗어날 수 있습니다. 그 결과 OnDiskExtensionHeader를 추가하는 과정에서 여러 차례의 경계 외 쓰기가 발생할 수 있습니다. 아래 디컴파일 코드는 경계 외 쓰기가 발생하기 전에 취약한 메시지 끝 포인터에 대해 추가된 패치 검사를 보여줍니다:

OOB 쓰기가 발생하기 전에 취약한 메시지 종료 포인터에 대한 패치 검사의 스크린샷

메시지 종료를 위한 경계 밖의 메모리 접근 검사

커널 변형

취약점의 익스플로잇 가능성을 평가하는 과정에서 MSMQ 서비스에 대응하는 커널 드라이버 mqac.sys에서 추가적인 커널 취약점이 식별되었습니다. 해당 취약점들은 다시 한 번 기능 플래그 심볼을 통해 식별되었으며, MQQM.dll에서 관찰된 바와 같이 MSRC 사례 76146도 참조하고 있습니다.

기능 스크린샷

mqac.sys 내 기능 플래그 심볼

KernelVariants 기능 플래그를 분석한 결과, 해당 취약점은 사용자 공간 구성 요소에서 발견된 취약점과 구조적으로 유사함이 확인되었습니다. 커널 구성 요소mqac.sys  은 MSMQ 서비스에서 메시지를 배달 실패 로 전달하고, 승인 메시지를 전송하며, MSMQ 패킷 버퍼에 대한 메모리 관리를 수행하는 등 다양한 작업에 관여합니다.

관련 작업을 수행하기 위해 커널 컴포넌트는 MSMQ 패킷 버퍼의 다양한 섹션을 파싱합니다. 이러한 두 가지 사례가 아래에 나와 있습니다.

관련 작업을 수행하기 위해 커널 구성 요소가 MSMQ 패킷 버퍼의 다양한 섹션을 파싱하는 과정을 보여주는 스크린샷

커널 드라이버 mqac.sys의 취약점 수정을 위한 기능 플래그를 보여주는 디컴파일된 코드 스니펫

위에 제시된 디컴파일된 코드 스니펫에서 볼 수 있듯이, 기능 플래그가 활성화된 경우 패킷 버퍼에서 해당 헤더를 가져오기 위해 “안전" 함수 CPacketBuffer::MsgDeadletterHeaderSafe CPacketBuffer::MsgOnDiskExtensionHeaderSafe 이 호출됩니다. 활성화되지 않은 경우에는 섹션 크기에 대해 충분한 검증을 수행하지 않는 “비안전" 함수가 호출됩니다.

취약성 유발

프로토콜 리버스 엔지니어링

프로토콜 파싱과 관련된 대부분의 코드는mqsvc.exe 프로세스에 의해 로드되는 MQQM.dll 라이브러리에 위치합니다. MSRC76146_MSMQ_OOBRWFixes 에서 참조된 코드에 도달하려면 클라이언트로부터 유효한 MSMQ 요청이 전송되어야 합니다. MSMQ 메시지 규격과 프로토콜은 방대하고 복잡합니다. 초기에는 MSMQ 서버를 스캔하는 공개 코드가 GitHub gist에 게시되어 있었으며, 이는 패킷 처리 과정을 보다 심층적으로 분석하는 데 기초 자료로 활용되었습니다. 또한 Microsoft 문서는 MSMQ 메시지 형식을 이해하는 데 유용했습니다.

아래 디버깅 세션에서 볼 수 있듯이 DLL 내의 코드는 WSARecv 함수를 호출하여 포트 1801을 통해 데이터를 수신합니다.

0:020> bp ws2_32!wsarecv ; g

중단점 0 히트

WS2_32!WSARecv:

00007ffd`651115c0 48895c2408      mov     qword ptr [rsp+8],rbx ss:000000aa`f07fef30=0000000000000006

 

0:019> k

# Child-SP          RetAddr               Call Site

00 000000aa`f07fef28 00007ffd`57ba9cb0     WS2_32!WSARecv

01 000000aa`f07fef30 00007ffd`57b9683d    

MQQM!NoReceivePartialBuffer+0x38

02 000000aa`f07fefb0 00007ffd`57b2078e     MQQM!CWinsockConnection::ReceivePartialBuffer+0x7d

03 000000aa`f07ff010 00007ffd`57b25b28    

MQQM!CSockTransport::BeginReceive+0xe6

04 000000aa`f07ff060 00007ffd`57b2d40b    

MQQM!CSockTransport::NewSession+0x194

05 000000aa`f07ff3f0 00007ffd`57b2d367     MQQM!CSessionMgr::AcceptSockSession+0x6f

06 000000aa`f07ff430 00007ffd`645e26bd     MQQM!AcceptIPThread+0x6a7

07 000000aa`f07ff7d0 00007ffd`6650a9f8    

KERNEL32!BaseThreadInitThunk+0x1d

08 000000aa`f07ff800 00000000`00000000     ntdll!RtlUserThreadStart+0x28

 

0:019> r @$t0=@rdx

0:019> pt

WS2_32!WSARecv+0x19f:

00007ffd`6511175f c3              ret

0:019> dc poi(@$t0+8) LC

000001b5`880ff490  62f06110 524f494c 00000070 5a5a5a5a  .a.bLIORp…ZZZZ

000001b5`880ff4a0  0073006e 00610074 0063006e 00200065  n.s.t.a.n.c.e. .

000001b5`880ff4b0  00440049 00000000 00000000 00000000  I.D………….

 

0:019> ba r1 poi(@$t0+8) ; g

중단점 1 히트

MQQM!CBaseHeader::SectionIsValid+0x154:

00007ffd`57b53450 7462            je     

MQQM!CBaseHeader::SectionIsValid+0x1b8 (00007ffd`57b534b4) [br=1]
 

CBaseHeader::SectionIsValid 함수는 새로운 메시지의 시작 부분을 파싱하는 역할을 하며, 메시지는 다음과 같은 형식의 BaseHeader 구조로 시작합니다.

BaseHeader 구조 스크린샷

BaseHeader 객체 구조

서버가 응답을 전송하기 전에 수신된 메시지 필드는 SectionIsValid에 의해 검증됩니다.

메시지 필드 스크린샷

MQQM.dll 내 SectionIsValid 디스어셈블리 코드 

초기 유효성 검증 이후, 프로토콜 파싱의 대부분은CQmPacket:: CQmPacket 생성자 함수 내에서 수행됩니다. CVE-2023-21554 취약점을 트리거하기 위해, 잘못 처리되는 비정상적인 섹션 헤더를 포함한 MSMQ 메시지를 전송할 수 있습니다. 다음 예시는 Eod(exactly-once-delivery) 섹션에 대해 EodHeader 을 사용하여 취약점을 트리거하는 과정을 상세히 설명합니다.

EodHeader를 사용하여 취약점을 트리거하는 장면 스크린샷

EodHeader 처리 과정의 취약점을 보여주는 디컴파일 결과

위 디컴파일 결과에서 패치된 경로는CEodHeader::GetNextSectionSafe. T 이라는 함수를 호출합니다. 반면 패치되지 않은 경로는 헤더 내 값을 사용하여 단순 포인터 덧셈으로 다음 섹션의 시작 위치를 계산합니다.

EodHeader  의 구조는 문서화되어 있지 않으며,UserHeader 내에EodHeader 의 존재를 나타내는 플래그 비트는 Microsoft 문서에서 “예약됨”으로 지정되어 있고, 전송 시 설정되어서는 안 된다고 명시되어 있습니다. 디스어셈블리 코드를 분석하면 헤더 구조에 대한 단서를 얻을 수 있습니다.

헤더 구조 스크린샷

EodHeader 섹션의 총 크기를 계산하는 디스어셈블리

위 디스어셈블리에서는  EodHeader의 시작 주소를 가리키는 포인터가  rdx  레지스터에 로드됩니다. 헤더의 첫 번째 및 두 번째 필드는 정수 크기 값(예: 헤더 크기 및 데이터 크기 등)을 나타내는 것으로 추정됩니다. 이 두 크기 값과 0xF를 합하면 Eod 섹션의 전체 바이트 크기를 나타냅니다. 관련 크기 필드를 큰 값으로 설정한  EodHeader을 포함한 메시지를 전송하면 경계 외 쓰기가 발생합니다. 이로 인해 프로그램이 메시지의 끝이라고 판단한 위치에 OnDiskExtensionHeader를 기록할 때 접근 위반이 발생합니다.

확장 헤더 스크린샷

잘못된 형식의 MSMQ 메시지 끝에 쓸 때 액세스 위반을 표시하는 WinDbg 세션

악용 가능성

메모리 관리 및 조작

취약점에서 얻은 경계 밖 쓰기의 강도를 평가하기 위해, 우리는 먼저 기본 메모리의 할당과 관리를 조사했습니다.

MSMQ 메시지 패킷이 처리되기 전에, 그 내용은 함수 QmAcAllocatePacket에서 할당된 버퍼로 복사됩니다. 이 함수는 mqac.sys 커널 드라이버를 다음 경로를 통해 호출합니다.NtDeviceIoControl.

mqac.sys 함수 호출 스크린샷

패킷 버퍼 할당 함수의 디컴파일

커널 구성 요소는 디스크 파일의 매핑된 뷰에서 분할된 버퍼를 반환하며, 해당 파일은C:\Windows\System32\msmq\storage 디렉터리에.mq  확장자로 저장됩니다. 각 파일은 최대 4MB까지 저장할 수 있으며, 여러 의 메시지를 포함할 수 있습니다.

커널 구성 요소 스크린샷

패킷 버퍼 메모리가 파일 매핑임을 보여주는 MQSVC 프로세스의 ProcessHacker 메모리 레이아웃

패킷 버퍼 주소는 무작위 패킷 핸들과 함께 IOCTL을 통한 할당 요청 후 사용자 공간으로 반환됩니다. 드라이버는 사용자 공간의 요청을 처리할 때 핸들을 사용하여 패킷 버퍼 주소를 계산합니다.

힙 정리

취약한 버퍼의 할당 메모리 영역은 프로세스 힙이 아닌 매핑된 파일 영역에 존재합니다. 또한 해당 메모리 영역에는 객체가 저장되어 있지 않습니다. 파일 매핑에는 MSMQ 메시지의 내용과 함께 저장된 메타데이터만 포함되어 있습니다. OnDiskExtension.

또한 메모리 레이아웃에 대한 사전 지식이 없으면 객체 포인터를 덮어쓰기 위해 프로세스 힙에 매핑되는 파일의 상대적 위치를 알 수 없습니다. 따라서 원격 코드 실행을 실현하기 위해서는 메모리를 예측 가능한 위치로 형성하는 메서드가 필요합니다.

대상 시스템에 정상적인 MSMQ 메시지를 전송하는 실험을 진행한 결과, 다수의 메시지를 반복적으로 대량 전송함으로써 .mq 파일 매핑 인접 영역에 새로운 힙 할당을 강제로 유도할 수 있음이 확인되었습니다. 메시지는 수신 시 메모리에 순차적으로 기록되며, MSMQ 메시지의 TimeToBeReceived 속성을 활용하면 특정 메시지의 해제 시점을 정밀하게 제어할 수 있습니다.

커널 구성 요소 스크린샷

MQ 파일 매핑 인접 영역에 새로운 힙이 할당된 모습을 보여주는 MQSVC 프로세스 메모리 레이아웃

그러나 이를 위해서는 공격자가 대상에 있는 하나 이상의 대기열에 메시지를 보낼 수 있는 액세스 권한이 있어야 합니다. 그렇지 않으면 메시지가 삭제되고 덮어쓰기되므로 패킷 메모리를 지속적으로 차지하지 않습니다.

수행된 연구 실험에서 권한이 없는 사용자는 기본적으로 누구에게나 원격으로 메시지를 보낼 수 있는 대기열을 만들 수 있다는 것이 발견되었습니다. 대기열은 시스템에서 무기한 지속됩니다. 대부분의 최신 MSMQ 용도는 선택적 구성 요소 및 어댑터로 사용되고 있지만 Oracle, Veritas 및 Xerox와 같은 공급업체는 MSMQ를 핵심 종속성으로 사용하는 엔터프라이즈 소프트웨어를 제공합니다. 따라서 공격 시나리오는 비현실적이지 않습니다.

프리미티브 악용

경계 외 메모리 접근 취약점은 공격에 활용 가능한 기본 동작을 제공하며, 이를 통해 악의적인 클라이언트가 패킷에 할당된 메모리 경계를 넘어OnDiskExtensionHeader 을 기록할 수 있게 됩니다.

오프셋에 값을 쓸 수 있는 취약점을 평가할 때는 다음과 같은 몇 가지 속성을
고려해야 합니다.

  • 오프셋을 제어할 수 있나요?
  • 기록된 값을 제어할 수 있나요?

QueueJumper 취약점의 경우 공격자가 제어하는 데이터를 사용하여 계산되기 때문에 OOB 쓰기에 할당된 버퍼의 오프셋을 제어할 수 있습니다. 그러나 OOB 쓰기의 내용은 제한적으로 제어할 수 있습니다.

여기서AddressOnDiskExtension 헤더가 기록될 패킷 메시지의 끝을 가리키는 손상된 포인터를 의미합니다. 발생하는 일련의 동작은 다음과 같습니다.

  • 0x000000000000000C 이 기록됩니다.Address
  • 0x00000000Address+0x2 에 기록됩니다.
  • 0x0000000000000000Address+0x12 에 기록됩니다.
  • 0x0000000000000000 Address+0x1A 에 기록됩니다.
  • 0x00000094 Address+0xE 에 기록됩니다.
  • 0x0000 이 기록됩니다.Address+0x22
  • 0x0000 Address+0x62 에 기록됩니다.
  • memcpy(Address+0xA6, Source, Source->AddressLength+0x08)

위에서memcpy 호출에 사용된SourceTA_ADDRESS 객체를 의미합니다. TA_ADDRESS 구조체는 특정 유형(예: NetBIOS)의 단일 전송 주소를 정의합니다. 정의는 다음과 같습니다.

typedef struct _TA_ADDRESS {

    USHORT AddressLength;;

    USHORT AddressType; Info;

    UCHAR Address[1];;

} TA_ADDRESS, *PTA_ADDRESS;

AddressLength

지정된 AddressType의 주소에 있는 바이트 수를 지정합니다.

AddressType

전송 주소의 유형을 지정합니다.

Address

전송 주소가 포함된 가변 크기 배열을 지정합니다.

아래 디버깅 세션에서TA_ADDRESS 에는 IP 주소 형태의 공격자 영향 데이터가 포함되어 있습니다.

rax=0000014e1d110180 rbx=0000014e1d110180 rcx=0000014e1d110184

rdx=0000014e1ce86b10 rsi=0000014e1d110001 rdi=0000000545d7fa50

rip=00007ff843208074 rsp=0000000545d7f940 rbp=0000000545d7f980

r8=000000000000000c  r9=0000000000000002 r10=0000000000000000

r11=0000000545d7f938 r12=0000000000000002 r13=0000000000001000

r14=0000014e1ce86b10 r15=0000000000000000

iopl=0         nv up ei pl nz na po nc

cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206

MQQM!CQmPacket::CQmPacket+0x89c:

00007ff8`43208074 e8a5780a00      call    MQQM!memcpy (00007ff8`432af91e)

0:017> dc rcx

0000014e`1d110184  00010004 00000000 8620a8c0 00000000  ………. …..
 

위에서TA_ADDRESS 객체는 길이 4 , 유형1 , 값 0x8620a8c0 을 가집니다. 각 바이트를 IPv4 옥텟으로 변환하면 192.168.32.134 주소가 되며, 이는 클라이언트의 IPv4 소스 주소입니다.

이 시나리오를 사용하면 소스 주소를 통해 공격자가 제어하는 데이터를 메모리의 패킷 할당의 제어된 오프셋에 쓸 수 있습니다. 매우 제한적이고 비실용적일 수 있지만 이론적으로는 패킷 오프셋을 줄이면서 다양한 소스 주소에서 여러 요청을 수행하여 메모리에 기록되는 값을 정확하게 제어하는 데 사용할 수 있습니다.

대체 공격

블라인드 원격 코드 실행을 달성하는 데 발생하는 많은 제한 사항으로 인해 정보 유출과 같은 대체 공격 시나리오가 조사되었습니다.

고려된 한 가지 공격은 특정 메시지 섹션에 대한 포인터가 범위를 벗어난 메모리를 가리키도록 손상시킨 다음 나중에 메시지를 검색하여 인접한 메모리를 읽는 것이었습니다.

그러나 각 섹션 구문 분석의 시작 부분에서는 현재 섹션의 위치를 확인하므로 구문 분석 로직을 속여 범위를 벗어난 데이터 섹션을 구문 분석하도록 할 수는 없습니다.

또 다른 가능한 공격 시나리오는 다른 메시지의 OnDiskExtensionHeader를 덮어써 메시지 수신자를 속여 수신된 메시지의 출처를 찾는 것입니다. 마찬가지로 공격자가 액세스할 수 없는 대기열용 메시지의 내용을 덮어쓸 수 있습니다. 메시지의 특정 내용을 덮어쓰려면 공격자가 메시지 크기와 같은 메시지에 대한 정보를 가지고 있어야 합니다.

다음과 같은 형식으로 범위를 벗어난 데이터 액세스에 취약한 Soapheader라는 이름의 선택적 섹션이 있습니다.

Soapheader 의 스크린샷

Soapheader 패킷 형식

버퍼가 해제될 때 MSMQ 패킷 데이터를 저장하는 데 사용되는 메모리가 제대로 지워지지 않는 현상이 관찰되었습니다. 결과적으로 이전 MSMQ 패킷보다 작은 크기의 MSMQ 패킷을 전송하면 메모리 레이아웃에 현재 패킷의 데이터와 이전에 처리된 MSMQ 패킷의 데이터가 포함된 메모리 레이아웃이 생성됩니다.

 SoapHeader을 악용하면 이 특성을 이용해 이전에 처리된 패킷이나 인접하게 저장된 메시지로부터 데이터를 노출시킬 수 있다는 사실이 밝혀졌습니다. 공격자는 BodyDataLength을 임의로 정의하고 본문 섹션을 완전히 제외할 수 있습니다. 그 결과, 이전에 처리된 MSMQ 패킷에 포함된 잠재적으로 민감한 데이터가 공격자의 SoapHeaderBody로 포함된 MSMQ 메시지가 생성됩니다. 패치된 코드 경로는 Body 데이터가 MSMQ 패킷 데이터의 경계 내에 있는지 검증함으로써 이러한 악용 사례를 방지합니다.

제어되지 않는 추가 쓰기가 인접 메모리를 손상시키는 쓰기 콘텐츠에 대한 제한된 제어와 메시지 레이아웃에 대한 제한된 지식은 악용에 큰 장애물이었습니다.

커널을 통한 공격

분석 시점에는 MSMQ 메시지 패킷의 초기 처리 과정에서 발생하는 사용자 공간 취약점에 대해서만 익스플로잇 가능성을 평가했습니다. 커널 변종 취약점을 추가로 분석하면 새로운 익스플로잇 경로가 드러날 수 있습니다. 예를 들어, 손상된 헤더를 포함시킴으로써 .mq 파일의 커널 메모리 매핑 영역에서 쓰기 원시 동작을 획득할 가능성이 있습니다. 일부 경우에는 사용자 공간 처리 단계의 검사가 커널에서 특정 후속 처리 작업을 수행하지 못하도록 막습니다.

또한, 커널 변형의 경우 공격자가 메시지 내용을 직접 제어할 수 없으며, 사용자 공간과 동일한 파일 매핑을 사용하며, 커널 풀(힙)에서 동작하지 않습니다. KASLR과 같은 완화 조치도 원격 악용에 있어 극복하기 어려운 장애물입니다.

취약한 서버 탐지

패치된 코드 구현 방식으로 인해 원격 클라이언트는 시스템에 업데이트가 적용되었는지 안전하게 확인할 수 있습니다. 취약점을 트리거하되 실제로 경계 외 접근을 발생시키지 않는 MSMQ 메시지를 전송함으로써 서비스 프로세스를 크래시시키지 않고 이를 확인할 수 있습니다. 메시지의 UserHeader에 HTTP 플래그가 설정되어 있으면 SRMPEnvelopeHeader가 존재해야 합니다. 패치에서는 DataLength 필드를 2배 한 값에 대해 정수 오버플로 검사를 수행합니다. 해당 길이 값을 조작하면 곱셈 결과가 실제 데이터 크기와 동일한 작은 값으로 오버플로되도록 설정할 수 있습니다.

SRMPEnvelopeHeader DataLength에 대한 정수 오버플로 검사를 보여주는 디컴파일된 코드 스니펫

SRMPEnvelopeHeader DataLength에 대한 정수 오버플로 검사를 보여주는 디컴파일된 코드 스니펫

대상에 패치가 적용되면 취약성으로 인해 예외가 발생하고 서버가 메시지 처리를 중단하므로 클라이언트로 응답이 다시 전송되지 않습니다. 패치가 적용되지 않은 경우 서버는 정상적으로 메시지를 처리하고 응답을 보냅니다.

결론

취약한 버퍼가 할당된 메모리 영역의 위치 특성상, 대상 시스템의 임의 큐로 메시지를 전송할 수 있는 공격자에게는 원격 코드 실행이 보다 현실적인 공격 시나리오로 보입니다. 이 시나리오에서는 힙 그루밍을 통해 인접한 힙 영역이 할당되도록 유도할 수 있습니다. 쓰기 내용에 대한 제어가 극히 제한적이기 때문에 원격 익스플로잇에는 상당한 제약이 따릅니다. ASLR과 같은 완화 기법이 적용되어 있으므로, 추가적으로 정보 유출 취약점도 확보해야 합니다. 공격 원시 동작을 통해 획득한 상수(0xC, 0x0)를 객체에 단 한 번 쓰는 것만으로도 이를 달성할 가능성은 있습니다. 그러나 해당 객체는 인접 필드가 다른 쓰기로 인해 손상되더라도 견딜 수 있는 유의미한 필드를 포함하고 있어야 합니다. 또한 해당 객체는 공격자가 예측 가능하게 할당할 수 있어야 하며, 객체의 수명은 익스플로잇이 진행되는 전체 기간 동안 유지되어야 하고, 객체의 특정 동작은 공격자에 의해 트리거될 수 있어야 합니다. 본 연구 과정에서는 이러한 조건을 충족하는 적절한 객체는 발견되지 않았습니다.

궁극적으로 우리는 QueueJumper를 원격으로 악용하는 것이 불가능하지는 않지만 앞서 언급한 요구 사항으로 인해 이를 달성하기 어렵다는 결론을 내렸습니다. 이 블로그 게시물은 매우 복잡한 메시지 사양, 서비스 및 프로토콜의 표면적인 부분만 다루고 있습니다. 사용자 공간과 커널 구성 요소 작업 모두에 대한 추가 연구가 필요합니다.

Mixture of Experts | 12월 12일, 에피소드 85

AI 디코딩: 주간 뉴스 요약

세계적인 수준의 엔지니어, 연구원, 제품 리더 등으로 구성된 패널과 함께 불필요한 AI 잡음을 차단하고 실질적인 AI 최신 소식과 인사이트를 확인해 보세요.