본문 바로가기
카테고리 없음

CVE-2020–0796 취약점 분석 보고서 내용 및 실습

by pharmerci 2021. 8. 2.
728x90

분석 추진 배경

공유 폴더로 원격에서 파일에 접근해본 적이 있을 것이다. 또한 학교, 사무실에서 여러 PC가 하나의 프린터를 공유해본 적도 있을 것이다. 이 때 사용되는 프로토콜이 SMB이다.

 

SMB 프로토콜은 Server Message Block의 약자로, 윈도우 시스템에서 파일 공유, 프린터 공유, 원격 윈도우 서비스 액세스 등을 목적으로 사용되는 전송 프로토콜이다. 2017년 4월 30만대의 PC를 감염시킨 워너크라이 랜섬웨어가 SMB 프로토콜을 이용해서 다른 PC로 전파되었다. 이때부터 SMB 취약점에 대해서 사람들이 관심을 갖게 되었다.

위 취약점은 이미 패치된 취약점이지만, 내용을 분석하면서 모르는 내용을 공부할 수 있는 기회이기 때문에 조사해보았다. 또한 분석을 통해서 시스템에 어떠한 취약점이 발생할 수 있는지, 어떤 방식으로 악용될 수 있는지 알아볼 수 있겠다.

 

SMB 프로토콜

SMB 프로토콜은 현재까지 SMBv3까지 발표되었다. SMBv1의 경우 SMBv2, v3에 존재하는 보안 기능이 없기 때문에 v1은 논외로 하고 SMBv2를 기준으로 구조를 확인한다.

SMB 프로토콜은 고정된 크기의 헤더 패킷으로 시작되며 패킷 내의 커맨드 필드 값에 따라서 어떤 오퍼레이션을 수행할 지 결정된다. 헤더 패킷이 오고가면 SMB 메시지 패킷이 전송되는데 이 세트를 SMB dialect라고 부른다. SMBv2의 다이얼렉트는 TCP 통신을 지원하고 TCP 통신 패킷은 아래 구조를 갖는다.

 

 

 

 

 

SMB2Message를 서버와 클라이언트 간에 교환해서 SMB 프로토콜이 구성, 구동되게 한다. 이 메시지는 다양한 종류가 있는데 COMPRESSION_TRANSFORM_HEADER 메시지 다이얼렉트를 주의 깊게 봐야한다. SMBGhost가 이 메시지를 처리하는 과정에서 발생하는 취약점이기 때문이다.

지금부터 COMPRESSION_TRANSFORM_HEADER의 구조, 취약점 발생 원리를 알아보자.

 

COMPRESSION_TRANSFORM_HEADER의 구조

COMPRESSION_TRANSFORM_HEADER은 SMB 통신에서 클라이언트나 서버가 압축된 메시지를 전송하게 될 때 사용하는 메시지 다이얼렉트이다. SMB 3.1.1 다이얼렉트에서만 가능하다.

 

 

 

 

 

구조는 다음과 같다. 각 값이 의미하는 바를 조사해보았다.

Protocol ID: 프로토콜의 구분자 역할을 하며 반드시 0x424D53FC로 세팅되어 있어야 한다. 이는 0xFC와 S, M, B를 나타낸다.

OriginalCompressedSegmentSize: 압축되지 않은 데이터 세그먼트의 크기를 나타낸다.

CompressionAlgorithm: SMB2 메시지 압축을 위해 사용한 알고리즘을 반드시 1개 이상 포함해야 한다.

Flags: 0 또는 1의 값으로 반드시 설정되어야 한다. 0은 연결된 compression이 없다는 의미이고, 1은 압축된 메시지가 여러 압축된 페이로드와 연결되어 있음을 의미한다.

Offset/Length: flag가 1이면 길이 값으로 인식되는데 압축된 페이로드 길이를 의미한다. 이외의 경우에는 끝부터 압축된 데이터 세그먼트 시작 부분까지의 오프셋을 나타내는 값이다.

CVE-2020–0796(SMBGhost) 취약점

SMBGhost로 인한 블루스크린 현상이나 권한상승은 COMPRESSION_TRANSFORM_HEADER의 OriginalCompressedSegmentSize 값을 조작해서 발생하는 정수 오버플로우 때문이다. OriginalCompressedSegmentSize에 저장 가능한 값보다 큰 값을 넣는다. 그러면 변수가 의도치 않게 매우 작은 수로 인식하거나 음수로 인식하게 된다. 이 때 프로그램이 원래와는 다른 동작을 하게 되는데 그 예시가 블루스크린이나 권한 상승이다.

PoC를 실행했을 때 발생하는 패킷들을 살펴보자. PoC는 Proof of Concept의 약자로 hunting bugs 단계에서 발견한 버그들이 실제로 유용한 버그인지 증명하기 위해서 작성하는 코드이다.

 

 

 

 

 

이렇게 패킷이 생성되었다. 먼저 헤더 패킷이 request, response로 오간 것을 알 수 있고 클라이언트가 서버에 SMB2 세션에 대해 새로운 권한을 요청하는 패킷도 볼 수 있다. SMB는 Server Message Block의 약어로 도스나 윈도우에서 파일이나 디렉토리 및 주변 장치를 공유하는데 사용되는 메시지 형식이다. 그런데 문제는 세션 요청에 대한 서버의 응답이 에러 메시지라는 것이다. 사진에서 4번째 패킷에 있는 에러 메시지를 볼 수 있다. 마지막 패킷에는 comp가 적혀있는데 저것은 패킷이 압축되어있다는 의미이다.

 

 

 

 

 

 

마지막 패킷의 내부 구조를 살펴보아야 한다. COMPRESSION_TRANSFORM_HEADER 메시지 다이얼렉트이고, 압축 알고리즘은 LZNT1이며, offset은 0xffffffff이다. 디버깅을 통해서 확인해보면 크래시가 발생한 부분은 rsi가 가리키고 있는 곳의 값이 00000000 00000000일때이다. 이전에 RtlDecompressBufferLZNT1함수가 시행됐기 때문에 이를 역추적해야 한다. 그 결과로는 다음 순서로 함수가 호출되었다는 것을 알 수 있다.

 

 

 

 

 

 

(svr2!Srv2DecompressData)->(srvnet!SmbCompressionDecompress)->(nt!RtlDecompressBufferEx2)->(nt!RtlDecompressBufferLZNT1)

srvnet!SmbCompressionDecompress 여기에서 페이지폴트가 발생하였고

svr2!Srv2DecompressData 이 함수에서 위의 함수를 호출했다.

메모리 공간을 잡을 때 원래 OriginalSize에 0xffffffff를 더한 값만큼 지정했는데 이부분이 오버플로우의 원인을 제공하는 부분이다. 이렇게 메모리공간을 지정하면 압축이 해제될 때 오버플로우를 유발하여 데이터들이 잘못된 주소에 접근하게 한다.

 

해결방안

운영체제를 최신 보안 업데이트 된 상태로 유지해야 한다. 또한 백신과 같은 보안 프로그램의 사용도 필요하다. 개발자의 경우에는 시큐어코딩에 집중을 하여 검증하고 확인하는 과정을 거치도록 해야한다.

728x90