보안정보

전문화된 보안 관련 자료, 보안 트렌드를 엿볼 수 있는
차세대 통합보안관리 기업 이글루코퍼레이션 보안정보입니다.

BlueKeep (CVE-2019-0708)

2019.07.03

16,282

 

 

 

1. 취약점 개요 

 

마이크로소프트(MS)는 지난 5월 정기 패치를 통해 원격 터미널 접속에 사용되는 RDP(Remote Desktop Protocol) 프로토콜에서 발견된 원격코드실행 취약점에 대한 보안 업데이트를 발표하였다. 패치 권고안에 따르면 해당 취약점을 악용할 경우 공격자는 인증 없이도 서버에 코드 실행이 가능하다. 취약점의 심각도를 고려하여 MS는 업데이트 지원이 끝난 윈도우 XP, 2003 등에도 보안 업데이트를 배포하였다.

 

현재 해당 취약점에 대한 실제 공격 코드 및 이를 악용한 대규모 공격 사례는 보고되고 있지 않으나 보안업체 Errata Security의 조사에 따르면 95만 대 가량의 윈도우 시스템이 해당 취약점에 노출되어 있는 것으로 조사되었으며, 지속적으로 취약점에 대한 연구가 진행되고 있으므로 이에 대한 대비가 필요하다.

 

 

구분

버전

Windows XP

SP3 x86

Professional x64 Edition SP2

Embedded SP3 x86

Windows Server 2003

SP2 x86

x64 Edition SP2

Windows 7

32-bit Service Pack 1

64-bit Service Pack 1

Windows Server 2008

 

32-bit Service Pack 2

64-bit Service Pack2

Itanium Service Pack 1

64-bit Service Pack 1

 

[표 1] CVE-2019-0708 취약한 버전 목록 

 

 

2. 취약점 분석

 

1) 패치 분석

 

MS에서 제공된 보안 패치는 다음 명령어를 통해 언패킹이 가능하다.

 

ㆍ패치파일이 .msu 파일인 경우

 > expand -F:* update.msu C:

 > cd

 > expand -F:* update.cab C:

 

 

ㆍ패치파일이 .msp 파일인 경우

 > msix patch.msp /out C: 

 

 

ㆍ패치파일이 .exe 파일인 경우

 > pach.exe /x:C:MS10-005Extracted 

 

 

추출된 패치 파일에는 RDP 서버에서 사용되는 termdd.sys 드라이버 파일이 존재한다. 해당 파일을 BinDiff  도구를 이용하여 패치 전 파일과 비교한 결과는 다음과 같다.

 

 

[그림 1] 패치 전/후 termdd.sys 파일 비교

 

 

BinDiff 결과를 통해 유사도가 가장 낮은 IcaBindVirtualChannels, IcaRebindVirtualChannels 두 함수가 수정된 것을 확인할 수 있다.

 

 

[그림 2] 패치 전 IcaBindVirChannelByName 함수 내용

 

 

[그림 3] 패치 후 IcaFindChannelByName 함수 내용

 

 

수정된 내용은 _IcaBindChannel 함수 호출 전에 “MS_T120”  문자열이 존재할 경우 세번째 인자가 강제로 31로 변경 되게 조치 하였다.

_IcaBindChannel 함수는 채널 번호와 채널 객체를 바인딩 해주는 역할을 수행하는데, 이 때 “MS_T120” 채널이 31번 이외의 번호와 바인딩 되지 않도록 하기 위함이다.

 

 

2) RDP in a Nutshell

 

RDP 프로토콜은 일련의 연결 과정을 거쳐 서비스를 제공하게 되는데 이 과정에서 클라이언트는 서버에 명시적으로 정적 채널(Static Channel)을 요청할 수 있다. 서버는 요청된 채널에 대하여 채널 번호를 할당하고 해당 채널을 통해 메시지 송수신이 가능케 된다.

 

 

[그림 4] RDP 연결 순서 (출처:Microsoft)

 

 

취약점에 사용되는 “MS_T120” 채널의 경우 일반적인 RDP 연결 과정에서 요청되는 채널이 아니며, MS에서 용도를 명시하지 않고 프로그램 내부에서 31번으로 할당되어 사용되는 채널이다.

 

 

[그림 5] 정상 RDP Initial PDU 패킷

 

 

3) Use After Free(UAF) 취약점

 

UAF 취약점은 메모리 버그 중 하나로, 임의의 포인터가 비할당(free)된 객체를 참조하고 있다가 해당 메모리에 접근을 시도할 경우 발생하게 되며, 이를 통해 시스템 오동작을 일으키게 된다.

 

RDP 호스트는 _IcaBindChannel 함수를 통해 채널 객체를 특정 채널 번호와 바인딩 시키게 되는데, 이 때 사용자가 명시적으로 MS_T120 채널을 요청할 경우, 임의의 번호와 MS_T120 객체가 바인딩 된다. 그런데 MS_T120 객체의 경우 이미 31번 채널이 할당된 상태이므로, 하나의 객체에 두 개의 채널 번호가 할당되게 된다.

 

 

[그림 6] 악성 RDP Initial PDU 패킷

 

 

[그림 7] 채널 바인딩 상태 

 

 

2번 채널 번호를 통해 MS_T120 채널 객체를 참조하고 있는 CODE1에서 동작 중 해당 객체를 비할당(FREE)한 이후, 31번 번호 통해 해당 객체를 참조하고 있는 CODE2에서 해당 객체를 사용할 경우 UAF 취약점이 발현된다.

 

 

[그림 8] 채널 바인딩 상태 

 

 

3. POC 분석

 

1) Static Channel Message

 

현재까지 공개된 POC 코드를 이용하여 UAF 취약점을 발현하고 시스템을 강제 오동작(Crash) 시키는 행위가 가능하다. 이를 위해서는 일련의 연결 과정을 거쳐 MS_T120 채널을 할당하고, 특수하게 조작된 패킷을 서버에 송신해야 한다. POC에서는 아래와 같은 패킷이 사용되었다.

p =  b"x03x00x00x2ex02xf0x80x64x00x07x03xef"

p += b"x70x14x0cx00x00x00x03x00x00x00x00x00"

p += b"x00x00x02x00x00x00x00x00x00x00x00x00x00x00"​ 

 

위의 패킷을 MS에서 제공하는 RDP 문서(2.2.6-Static Virtual Channels)를 참조하여 분석해보면 아래와 같은 구조를 확인할 수 있다. 

# Static Channel Message Packet

 

# TPKT Header

"x03x00x00“

 

# length 

"x2e" 

 

# X.224

"x02xf0x80" 

 

# sendDataRequest

"x64“

 

# intiator userId

"x00x07“

 

# channelId

"x03xef“

 

# dataPriority

"x70" 

 

# userData length

"x14" 

 

# CHANNEL_PDU_HEADER::length

"x0cx00x00x00" 

 

# CHANNEL_PDU_HEADER::flags

"x03x00x00x00" 

 

#  Channel data

"x00x00x00x00x02x00x00x00x00x00x00x00x00x00x00x00"​ 

 

 

2) 동적분석

 

패킷의 Channel Data 부분에 실제 서버에 전달되는 메시지가 담겨 있으며, ChannelID 부분에 메시지를 처리할 채널을 명시한다. 해당 메시지를 처리하는 과정에서 서버는 채널을 비할당하게 되고, 이를 재사용 할 경우 UAF 취약점이 발현된다.

 

이를 확인하기 위해 Channel Data 부분에 임의의 문자열 “ABCD…”를 넣고 디버깅을 진행하였다. 우선 채널 번호와 채널 객체를 바인딩하는 부분에 중단점을 설정하면 다음과 같은 내용을 확인할 수 있다.

 

 

[그림 9] IcaBindVirtualChannels 함수 中

 

 

MS_T120 채널에 3번이 할당되어 바인딩 되고 있으며, esi, edi 레지스터에 관련 채널 객체 주소가 명시된 것을 확인할 수 있다. 해당 주소에 접근시 중단점을 설정하여 분석을 진행하면 _IcaCopyDataToUserBuffer 함수에서 해당 객체를 사용하는 것을 확인할 수 있다.

 

 

[그림 10] _IcaCopyDataToUserBuffer 함수 中

 

 

해당 함수는 커널 영역 데이터를 유저영역 메모리에 저장해 주는 역할을 하며, memcpy의 인자를 확인해 보면 channel data 패킷에 전달된 내용을 확인할 수 있다.  

 

 

[그림 11] 유저 메모리로 전달되는 데이터

 

 

유저영역에 전달된 데이터는 rdpwsx.dll 모듈의 MCSPortData 함수에서 사용된다. HGFE 문자열이 eax 값에 저장이 되는데, 이를 이용하여 채널을 비할당 시킬 수가 있다.  

 

 

[그림 12] MCSPortData 함수 동작 中 메모리 정보

 

 

[그림 13] MCSPortData 함수 동작 과정

 

 

위의 동작 과정을 서술하면 다음과 같다

① eax 값이 0인지 확인하여 0이 아닐 경우 ②로 분기한다.

② eax 값이 2인지 확인하여 2일 경우 ③으로 분기한다.

③ _MCSChannelClose 함수가 호출되며 해당 채널 객체를 비할당한다.

 

따라서 eax값을 0x00000002로 만들 수 있다면 해당 메시지를 처리하는 과정에서 MS_T120객체를 비할당 할 수 있으며, 이를 통해 UAF 취약점을 발현시킬 수 있다.

앞서 살펴본 바와 같이 eax 값에는 HGFE 문자열이 입력되므로, 메시지의 해당 위치에 02000000을 넣으면 취약점이 발현된다.

 

# POC Channel data

"x00x00x00x00x02x00x00x00x00x00x00x00x00x00x00“

 

# TEST Channel data

"x41x42x43x44x45x46x47x48x49x4ax4bx4cx4dx4ex4f"​

 

POC에서는 시스템 오류를 일으키기 위해 MS_T120 객체를 비할당 한 후 Disconnect 패킷을 서버에 전송한다. 서버는 해당 요청을 수신하면 생성된 모든 객체들을 비할당 하는데, 이 때 MS_T120 객체는 이미 비할당 된 후이므로 에러가 발생하게 된다

 

#Disconnect Request Packet

 

#TPKT Header

"x03x00x00x09“

 

# PER encoded PDU

"x02xf0x80“

 

# shutdownRequestPduData 

"x21x80"​ 

 

Disconnect 요청과 동시에 아래와 같이 메모리 오류가 발생하여 블루스크린과 함께 시스템이 재시작하게 된다.

 

 

[그림 14] 시스템 오동작

 

 

4. 해결방안

 

1) 보안 패치 적용

 

해당 취약점은 MS 자체 위험도 Critical(고위험)로 분류되어 패치가 배포된 상태임으로 패치를 반드시 적용해야 한다.

 

 

 - Windows 2003, XP 패치 링크

   https://www.catalog.update.microsoft.com/Search.aspx?q=KB4500331

 

 - Windows 2008, 7 패치 링크

   https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-0708

 

 

2) MS_T120 요청 탐지

 

해당 취약점을 발현하기 위해서는 RDP 연결 과정 중 “MS_T120“ 채널을 명시적으로 요청해야 하므로, 해당 요청에 대한 탐지 규칙을 추가하여 공격을 막을 수 있다.

 

 

탐지정책

alert tcp any any -> $HOME_NET 3389 (msg:"IGRSS.1.03013 MS, Windows, CVE-2019-0708, Attempted Administrator Privilege Gain"; flow:to_server,establishedfast_pattern:only

alert tcp any any -> any 3389 (msg:"IGRSS.13.03034 MS, Windows, CVE-2019-0708, Potentially Bad Traffic"; flow:to_server,establishedby_src, count 2, seconds 600; sid:1303034;)

 

[표 2] MS_T120 채널 요청 탐지 Snort Rule

 

 

3) NLA(Network Level Authentication) 적용

 

RDP 호스트에서 NLA를 활성화 할 경우 연결 요청 시 인증이 이루어지기 전에는 세션이 수립되지 않으므로 비인가자의 공격을 방어할 수 있다.

 

NLA는 다음과 같은 방법으로 설정이 가능하다.

- 시작 → 실행 → gpedit.msc → 컴퓨터 구성 → 관리 템플릿 → Windows 구성 요소 → 터미널 서비스 → 원격 데스크톱 → 세션 호스트 → 보안 → 네트워크 수준 인증을 사용하여 원격 연결에 대한 사용자 인증 필요 → 사용

 

 

[그림 15] NLA 설정 화면

 

* 최근 NLA와 관련하여 세션 잠금화면 우회 취약점(CVE-2019-9510)이 발견됨에 따라 관련 내용에 대한 인지 및 대비가 필요하다.

 

 

5. 결론

 

현재까지 대중에 공개된 POC 코드는 UAF 취약점을 악용하여 시스템 오동작을 일으키는 DoS공격만 가능한 상태이지만, 해당 취약점이 지속적으로 연구되고 있으므로 원격코드실행 기능이 추가된 공격 또한 나타날 확률이 높다. MS 측에서도 해당 취약점을 악용하여 자가증식 가능한 악성코드의 출현을 우려하고 있으므로 이에 대한 대비가 필요하다. RDP를 운용하고 있는 조직은 업데이트 실시 및 권고된 조치 방안 적용을 통해 공격을 방어해야하며, 불필요한 RDP를 운용하고 있는 경우 위험을 막기 위해 서비스 비활성화, 포트 변경 등의 조치를 취해야 한다.

 

 

[참고자료]

[1] https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/

[2] https://github.com/wanglf/CVE-2019-0708

[3] https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-0708

[4] https://dl.packetstormsecurity.net/papers/general/debugging-CVE-2019-0708.pdf

[5 https://securingtomorrow.mcafee.com/other-blogs/mcafee-labs/rdp-stands-for-really-do-patch-understanding-the-wormable-rdp-vulnerability-cve-2019-0708/