NOTICE



 “[hwp] 비트코인을 겨냥한 한글 취약점 파일 분석_두 번째” 시간입니다.


 이번에는 취약점이 어디서 어떻게 발생하는지 살펴보겠습니다.


 앞서 “[hwp] 비트코인을 겨냥한 한글 취약점 파일 분석_첫 번째” 시간에 취약점 코드는 gswin32c.exe의 gsdll32.dll 모듈을 오동작하게 만든다고 했던 것을 기억하실 겁니다.

 

[그림 01] 취약점 발생 모듈


 gswin32c.exe는 Ghostscript Interpreter Application입니다. GhostScript나 PostScript 코드를 읽어서 운영체제가 알아들을 수 있게 해석 및 전달해주는 프로세스라고 생각하시면 됩니다. 그리고 gsdll32.dll은 gswin32c.exe의 조수로써 스크립트 코드를 읽고 실행시키는데 핵심 역할을 합니다. 


 그럼 gsdll32.dll는 어떤 과정을 거쳐서 Script 코드를 실행시킬까요?

 먼저 Script 코드를 읽어와야 할 것입니다. 읽어온 데이터는 메모리에 기록됩니다. 메모리에 존재하는 Script 코드는 문자열 데이터이기 때문에 운영체제가 알아들을 수 있게 변환을 합니다. 코드 변환이 완료되면, 변환된 코드를 사용해서 운영체제에게 행위가 발생하도록 요청합니다. 그리고 마지막으로 운영체제에게 “내가 원하는 작업은 다 끝났어.”라고 알리면 모든 과정이 완료됩니다.


 여기에 답이 있습니다. 이 일련의 과정을 크게 “Script Read → Reset  Execute  Close”라고 했을 때, BIN0012.ps는 Close 과정에서 gsdll32.dll이 오작동을 하도록 만듭니다.


 다음은 gsdll32.dll이 Close 과정에서 사용하는 코드의 일부입니다. 여기서 gs_free_object( ) 호출 오작동으로 인해 악성 ShellCode(핵심 악성 데이터가 실행되도록 만들어주는 징검다리)가 실행됩니다.

 

[그림 02] gsdll32.dll - sclose( ) 코드


 오동작이 정확히 어떻게 발생하는지 확인하기 위해서는 gsdll32.dll이 gs_free_object( ) 함수를 호출하는 방식에 대해서 살펴봐야 할 것으로 보입니다.


 gs_free_object( ) 호출 코드입니다. 아래 그림을 보면 뭐가 취약한 건지 잘 모를 겁니다. 간단하게 설명 드리겠습니다. 함수를 호출할 때, “CALL 함수코드 위치 주소” 라는 명령어를 사용합니다. 그런데 여기서는 “CALL EDX”라는 명령어를 사용했네요. EDX는 레지스터라는 임시 저장 공간입니다. 즉, gsdll32.dll는 EDX라는 임시 저장 공간에 ‘gs_free_object( ) 호출 주소 정보’를 담아놓고 사용을 하는 겁니다. 그런데 이 말은 누군가 EDX에 잘못된 주소 정보를 입력해 놓으면 코드 흐름이 바뀔 수 있다는 것과 같습니다.

 

[그림 03] gsdll32.dll에서 확인한 gs_free_object( ) 호출 지점


 본 한글 악성 파일도 동일한 방법을 사용합니다.


 BIN0012.ps 코드부터 차근차근 살펴보겠습니다. 여기서 크게 어려운 부분은 없습니다. Line 11에서 ‘<>’ 안에 있는 쉘코드를 파라미터로 넣고 A4 함수를 호출하는데 그 과정에서 쉘코드가 0xB45CD16C로 XOR 연산됩니다. 그리고 복호화된 쉘코드는 exec Command에 의해 실행됩니다.

 

[그림 04] BIN0012.ps 코드_01


 다음은 exec Command에 의해 실행되는 코드입니다. 이 코드는 조금 기네요. 그런데 대부분이 함수 코드이고 핵심 동작 코드는 몇 줄 안됩니다. (물론 함수 코드가 코드 실행에 중요한 역할을 합니다.)

 

[그림 05] BIN0012.ps 코드_02


 이 중에서 핵심이 되는 마지막 코드만 간단하게 살펴보겠습니다. 공격자는 gsdll32.dll을 리버싱하면서 gs_free_object( ) 함수가 호출되는 과정을 철저히 분석하고 흐름에 맞춰 취약점 발생 코드를 작성했습니다. 

 

[그림 06] BIN0012.ps 코드_취약점 발생 핵심 부분


 아래 [그림 07]과 비교에서 보면 더욱 정확하게 파악할 수 있습니다. 0x10068442 주소에서 ESP 기준으로 + 0xC 주소에 존재하는 4 바이트 값을 EDI로 옮기는 코드가 보이죠. 여기가 취약점 발생 시작 지점입니다. 그럼 공격자는 스택 포인터의 시작 주소를 알아낸 다음 + 0xC 주소에 원하는 값을 미리 넣어놓으면 될 겁니다. [그림 06]에서 Line 391 코드가 여기에 해당됩니다. 이런 식으로 Line 392부터 404까지는 메모리 공간에 계산된 주소 정보를 입력해 넣는 코드이고, 0x10068440 주소부터 0x10068489까지는 [그림 07]에서 입력된 값을 읽고 호출하는 등의 동작을 하는 코드입니다. [그림 06]은 Execute 단계에서 실행될 것이고, Execute가 완료되면 Close 단계에 돌입하면서 [그림 07] 코드가 동작하게 될 것입니다.

 

[그림 07] gsdll32.dll에서 확인한 sclose( ) 코드


 그럼 악성 쉘코드를 찾을 때까지 같이 따라가 봅시다. 여기서 악성 ShellCode는 핵심 악성 데이터가 실행되도록 만들어주는 징검다리로써 [그림 05]의 ‘/shellcode <>’ 안에 있는 16진수 숫자 값입니다.


 먼저 gs_free_object( ) 호출 부분입니다. EDX에 저장되어 있는 주소 값이 0x10017082인 것이 보이죠? 

 

[그림 08] 취약점 발생 당시 gs_free_object( ) 호출 지점


 실제 0x10017082 주소로 이동해보면 ‘XCHG  EAX, ESP’(OpCode: 0x94)와 ‘RETN’ (OpCode: 0xC3) 코드를 확인할 수 있습니다. 여기로 온 이유는 스택 포인터를 변경하기 위함입니다. 어셈블리 코드는 동작 과정에서 스택에 기록되어 있는 값들을 많이 가져다 씁니다. 그렇기 때문에 스택 포인터를 공격자가 원하는 주소로 변경해 놓으면 동작을 더 수월하게 만들 수 있습니다. 0x10017082 주소는 어떻게 알았냐고요? [그림 06]의 Line379와 380에서 0x94C3 값을 가지고 있는 위치 정보를 찾고, Line 395에서 위치 정보를 메모리에 기록하네요.

 

 [그림 09] ROP Chain 시작 지점


 이런 식으로 ROP Chain 코드가 동작하고 끝나면 VirtualProtect( )를 호출해서 악성 쉘코드 영역을 실행 가능하게 만듭니다.

 

[그림 10] 악성 쉘코드 영역에 실행 가능 권한 부여


 그리고 모든 동작이 완료되면 실제 악성 쉘코드를 만날 수 있습니다.

 

[그림 11] 악성 쉘코드 시작 지점


 최대한 쉽고 간결하게 많은 내용을 담고 싶었는데 아직 많이 부족한 것 같습니다. 그래서 직접 공부해보시라고 파일을 첨부했습니다. (PW: infected)


Sample.zip


 다음 포스팅은 추석이 끝나고 난 뒤가 되지 않을까 싶네요. 추석 연휴 잘 보내시기 바랍니다.


 이상으로 “[hwp] 비트코인을 겨냥한 한글 취약점 파일 분석_두 번째”를 마치겠습니다.