ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • CVE-2017-11882
    WeekHack/Pwnable 2021. 4. 25. 18:53
    반응형
    SMALL

    안녕하세요, comalmot입니다. 오늘은 CVE-2017-11882를 분석하려고 합니다.

    취약점 소개

    CVE-2017-11882

    CVSS Score : 9.3

     

    영향을 받는 프로그램 : Microsoft Office 제품군 중 CVE-2017-11882 관련 업데이트를 받지 않은 모든 버전 

    (Microsoft Office 365, Office 2016, Office 2013, Office 2010, Office 2007 등)

     

    취약점 타입 : 오버플로우로 인한 메모리 커럽션

    EQNEDT32.EXE

    EQNEDT32.EXE는 구버전 Microsoft Offie가 사용하던 Microsoft Equation 3.0 Object의 호환을 위해 Microsoft가 Office에 남겨놓은 기능으로, 현재 수식편집기와 동일한 기능을 하고 있습니다.

    Word 2016을 기준으로, Equation 3.0은 아래와 같이 접근할 수 있습니다.

     

    [삽입] - [개체] - Microsoft Equation 3.0 - [확인] 으로 생성이 가능합니다.

     

    Word 2016에서의 Equation 3.0

    확인 버튼을 누르면, 아래와 같은 화면이 나오게 됩니다.

     

    구버전 수식편집기의 모습

    우리가 현재 사용하고 있는 수식 편집기와 다를 바가 없습니다. 동일한 기능을 합니다.

     

     

    왜 발생했을까?

    0x41160F 주소에 있는 함수 내에 공격자가 임의로 입력 값을 조작할 수 있는 변수와 strcpy() 함수의 콜라보라고 이해하시면 될 것 같습니다.

     

    취약점으로 인한 피해

    현재도 이 취약점으로 인한 피해는 계속되고 있으며, 북한 등의 국가에서 다양한 변종으로 이 취약점을 활용한 악성 문서 파일이 계속 만들어지고 있습니다.

     

    app.any.run 에서는 코로나바이러스 사태 이후 이 취약점을 사용해 보건기관을 사칭한 문서 파일이 돌아다니는 등 아직까지도 업데이트를 하지 않은 대상들을 노리는 모습을 확인할 수 있었습니다.

     

    사전 지식

    버퍼 오버플로우

    버퍼오버플로우는 대부분 아실 것이라고 믿지만, 혹시 모르니 간단히만 적겠습니다.

     

    버퍼오버플로우 취약점을 가지고 있는 간단한 코드

    간단한 C 코드가 있습니다. 프로그램을 실행할 때 인자를 받고, 출력해주는 프로그램입니다.

     

    그런데 char 형 배열인 arr에 문자열을 6 이상 넣으면 어떻게 될까요? 그렇습니다. 여기서 오버플로우 취약점이 나오게 되는 것 입니다.

     

    이 프로그램의 메모리 구조를 한 번 봅시다.

     

    char arr[6];

    sfp

    ret

    아마 위와 같은 형식으로 되어 있을 겁니다.

     

    그런데 함수가 끝나고 돌아가는 주소가 적혀있는 ret 영역이 다른 임의의 값으로 변경되게 되면? 우리가 원하는 코드의 주소를 삽입할 수 있겠죠?

     

    여기서 나오는 아이디어입니다. 

     

    버퍼오버플로우에 대한 간단한 설명은 마쳤으니, 이제는 MTEF Header와 Font Record에 대해서 말씀드리겠습니다.

     

     

    MTEF Header와 Font Record

    먼저 MTEF Header는 아래와 같이 생겼습니다.

    MTEF Header

    이것은 Equation Object가 파일에 기록될 때 구분을 위한 구조체라고 보시면 되겠습니다.

     

    아래는 Font Record 입니다. 우리가 주목해야할 부분이 바로 여기에 있습니다.

    Font Record

    보시면 Font Name에 우리가 잘 아는 cmd 명령어가 있는 것을 확인할 수 있는데, 바로 여기서 오버플로우로 인해 취약점이 발생하는 것 입니다.

     

    뒤에 있는 0x00430c12는 WinExec()의 주소인데, 어째선지 제 샘플에서는 위 이미지와 같은 Payload가 확인이 불가하였습니다.

     

    그럼 얼마나 취약했길래 이렇게 쉬운 오버플로우에 취약점이 터졌을까?

    Get-PESecurity.ps1 실행 결과 (보안 기법 확인)

    Github에서 Get-PESecurity 파워셸 스크립트를 내려받아 EQNEDT32.EXE에 실행했더니, 

     

    ASLR, DEP, SafeSEH 등의 보안기법이 적용이 안된 모습을 볼 수 있었습니다.

     

    프로그램 버전 확인 결과

    프로그램 버전도 마찬가지로 저작권에 표기되어 있는 모습 (1990-2000), 파일 버전 (2000.11.9.0)이 이 프로그램의 연식을 확인할 수 있는 자료가 되었습니다.

     

    IDA로 열어봅시다

    IDA로 취약함수를 열어본 결과

    진짜 strcpy()가 있음을 확인할 수 있습니다.

     

    여기서 확인하셔야 할 부분은,

    char형 v12 변수와 int형 v13변수의 esp 기반 위치, 그리고 a1이 Font Record가 들어가는 부분이라는 것입니다.

     

    샘플 파일 만들기

    분석을 위해, 샘플 파일을 제작하였습니다.

     

    원래는 실제 악성코드 샘플을 활용하려 하였지만, 악성코드가 원활히 실행되지 않아 github에서 샘플을 만드는 스크립트를 활용하였습니다.

     

    https://github.com/unamer/CVE-2017-11882 

     

    unamer/CVE-2017-11882

    CVE-2017-11882 Exploit accepts over 17k bytes long command/code in maximum. - unamer/CVE-2017-11882

    github.com

    위 링크에서 제작하였습니다. 명령어는 

    python3 CVE-2017-11882.py -c "cmd.exe /c calc.exe" -o test.rtf

    입니다.

     

    샘플 HxD로 열어보기

    본격적인 분석 시작전에 HxD로 샘플 파일을 열어보았습니다.

     

    HxD 화면

    Class Equation - objw380 - obh260 - Object Data 하위에 16진수가 모여있는 것을 확인할 수 있습니다.

     

    16진수 데이터의 내용이 궁금하여 그대로 ASCII로 변환해보았습니다.

     

    ASCII 변환 결과

    놀랍게도 아까 우리가 샘플을 만들 때 입력했던 명령어인 cmd.exe /c calc.exe가 있는 것을 확인할 수 있습니다.

     

    본격적인 분석 시작

    Global Flags

    저는 Global Flags를 분석하는데에 활용했습니다. 원래 특정 프로그램 실행시 바로 인터셉트해서 잡아주려면 레지스트리 변경이 필요한데, 그 과정을 편리하게 해주는 프로그램입니다.

     

    Windows SDK 설치 시에 Debugging Tools for Windows를 선택 후에 설치하면 windbg와 함께 설치가 가능합니다.

     

    Global Flags(x86) 화면

    Global Flags(x86) 화면입니다. 우리가 분석하는 EQNEDT32.EXE는 32비트 기반 프로그램이니 32비트로 디버깅을 해주어야겠죠?

    Image에는 우리가 분석할 프로그램인 EQNEDT32.EXE를 넣어주고,

    Debugger란에는 체크박스에 체크를 해준 뒤 디버거의 경로를 입력해줍니다. 저는 windbg를 활용하려고 했기 때문에, windbg(x86)의 경로를 넣어주었습니다.

    취약 함수의 모습

    sub_0x41160F()

    아까 IDA로 봤던 취약 함수의 모습입니다. 벌써부터 머리가 복잡해지지만, 한 번 분석을 시도해 봅시다.

     

    이 어셈블리에서 가장 의아한 것은 아까 봤던 strcpy() 등의 함수 여러개의 call들이 거의 없다는 것입니다. 하지만 여러번의 분석을 통해 0x0041165F와 0x00411658 위치에 있는 명령어가 해당 동작을 하는 것을 확인하였고, 이를 가지고 분석하였습니다.

     

    공격 전 41160F 함수 스택의 모습

    멀쩡한 스택의 모습

    아까 v12 변수의 esp 기반 위치를 기억하시나요? 이 샘플은 sfp를 덮기 때문에 ebp가 오염되어 esp 기반 주소로 변수를 탐색하였습니다.

     

    보시면 별 이상이 없어보이는 모습을 확인할 수 있습니다. 하지만, 실행이 거듭될 수록 [esp + 0x6c] 에서는 이상한 일이 발생합니다.

     

    NULL 문자가 사라지고 그 자리를 쉘코드가 대체한 모습

    NULL이 사라지고, sfp 와 ret까지 덮어버리는 모습을 확인할 수 있었습니다.

     

    이때의 폰트를 확인해보니,

    Trigger

    Trigger가 되는 Font는 Cascadia Mono SemiBold임을 확인할 수 있었습니다.

     

    아까 봤던 스택의 모습

    아까 보셨던 사진입니다. 쉘코드와 sfp, ret의 구분이 어려우실까봐 색을 입혀 정리해보았습니다.

     

    빨간색 부분이 우리가 변수로서 접근할 수 있는 메모리의 영역이며, 이후 4바이트(초록색)은 sfp, 그 다음 4바이트(보라색)은 ret 영역입니다.

     

    즉, 현재 상태에서 함수가 끝나게 되면 우리는 0x402114 주소로 이동하게 됩니다.

     

    Breakpoint를 걸어보았습니다.

     

    sfp가 덮인 상태로 leave 명령어가 실행되어 ebp가 909010ff로 바뀐 모습

    ebp가 0x909010ff 로 오염된 것을 볼 수 있습니다. 아까 위 스택의 모습에서 리틀엔디언 형식으로 저장되어 있던 909010ff 가 leave 명령어 실행 이후 ebp에 영향을 주었습니다.

     

    이제 ret 명령어를 볼 수 있습니다.

     

    ret 명령어는 아래와 같은 동작을 실행합니다.

    pop eip

    jmp eip

     

    바로 실행흐름을 바꾸는 동작을 하는 것 입니다.

     

    그럼 현재 esp 위치에는 어떤 값이 존재할까요?

    esp 위치에 있는 값

    공교롭게도 아까 esp+0x6c 이미지에 있었던 ret 다음의 값이 0x19eefc 인 것을 알 수 있으며,

     

    0x19eefc로 점프한다는 의미이므로 해당 주소에는 어떤 코드가 있을 지 확인해보겠습니다.

     

    쉘코드의 모습

    아까 우리가 esp+0x6c 캡쳐 화면에서 본 일련의 16진수 값들이 0x19eefc로 복사가 되고 있었다는 것을 알 수 있습니다.

     

    실행하면 알 수 있는 함수들

    실제로 실행을 해보면 첫 번째 call은 WinExec()를 실행하는 구문이고, 두 번째 call은 ExitProcess()를 실행하는 구문임을 확인할 수 있습니다.

     

    WinExec()가 실행되는 모습

    그리고.. 계산기까지 잘 등장하는 모습을 확인할 수 있습니다.

     

    공격 성공!

    여기서 끝내면 다가 아니겠죠. 콜 스택을 뒤져서 인자가 어디있는지 찾도록 하겠습니다.

     

    Args to Child에서 찾을 수 있는 함수의 인자

    처음 실행했을 때는 ~*kv 가 잘 먹혀서 찾을 수 있었는데, 계속 snapshot을 돌려서 그런지 나중엔 잘 안되더군요.. ㅠㅠ

     

    그래서 push ecx 하는 것을 보고 ecx 레지스터가 가리키는 곳을 확인해봤습니다. (함수 실행 전엔 push 해서 인자 주니까요)

    ecx 레지스터가 가리키고 있었던 명령어..

    이렇게 인자까지 확인을 했고, 분석을 마치도록 하겠습니다.

     

     

    후기

    쉘코드가 우리가 일반적으로 생각하는 리눅스에서 사용하기 위해 고안된 그런 28byte 쉘코드 그런게 아니라 쉘코드를 한 번에 알아보기도 힘들었습니다..

     

    오류가 없길 바랍니다...

     

    혹시라도 오류가 있다면 댓글로 남겨주시면 참고해서 더 완벽한 분석으로 찾아뵙도록 하겠습니다.. 감사합니다.

     

     

     

    반응형
    LIST

    댓글

Copyright ⓒ 2019, WeekHack