전공영역 공부 기록

64비트 쉘코드를 실행하는 한글문서 악성코드

악분 2020. 7. 25. 11:27
반응형

 


1. 요약

1.1 한글문서 악성코드 샌드박스 분석

hybrid-analysis 샌드박스를 이용하여 한글 악성코드를 분석합니다.

1.2 한글문서 악성코드 추출

포스트스크립트 쉘을 이용해서 한글문서에 존재하는 악성코드를 추출합니다.

1.3 API 리졸빙

악성코드가 실행 중에 필요한 API함수 주소를 가져오는 과정을 x32dbg 조건 브레이크포인트를 설정하여 로그로 출력합니다.

1.4 헤븐즈게이트

악성코드를 실행하는 시스템이 64비트인 경우 동작하는 헤븐즈게이트를 살펴봅니다.

1.5 인젝션된 64비트 쉘코드 분석

64비트 프로세스에 인젝션된 쉘코드를 분석합니다.

 


2. 행위분석

프로세스모니터와 샌드박스 보고서를 활용하여 행위분석을 진행합니다.

한글문서를 열자마자 바로 악성코드가 실행됩니다. 악성코드의 목적은 explorer.exe를 대상으로 코드 인젝션을 수행합니다.

그림1 hybrid-analysis 코드 인젝션 로그

 

프로세스모니터에서는 코드 인젝션이 실패하여 오류가 발생합니다.

그림2 프로세스모니터 로그 ​

 

악성코드는 포스트스크립트로서 한글문서 위에 작은 크기로 숨겨져있습니다.

그림3 한글문서에 숨겨진 악성코드

 


2. 악성코드 추출

챕터2에서는 한글파일의 악성코드인 포스트스크립트를 추출합니다.

 

 

hwpscan2도구로 한글파일에 존재하는 포스트스크립트를 추출합니다.

* Root Entry → BinData → BIN0001.ps 오른쪽 마우스를 클릭 후 Save a Hex(Decompress)

그림4 포스트스크립트 추출 ​

 

포스트스크립트는 실행 중에 XOR연산으로 페이로드를 복호화 합니다. 복호화키는 바이트배열입니다.

그림5 포스트스크립트 복호화

복호화 결과를 파일로 추출하기 위해 실행 명령어(exec)를 출력 명령어(print)로 변경합니다.

그림6 파일 추출을 위한 포스트스크립트 수정

고스트스크립트 쉘에서 수정한 포스트스크립트를 실행합니다. 결과물을 복사하여 파일로 저장합니다.

그림7 복호화된 데이터

 


3. 쉘코드 실행

jump2it.exe와 gbb.exe를 사용하여 쉘코드를 실행하는 방법에 대해 살펴봅니다.

복호화된 데이터 중 쉘코드가 존재합니다. 쉘코드를 분석하기 위해 exe파일로 변환해야 하는데 파일 크기가 커서 [2차 미북 정상회담.hwp]예제에서 사용한 방법이 되지 않습니다. shellcode2exe.py는 1kbyte크기인 쉘코드만 exe파일로 변경합니다.

* 2차 미북 정상회담.hwp 분석 보고서: https://www.notion.so/2-hwp-cbc93af950d745c48dc15d9b355ac6f4

 

3.2 jump2it으로 쉘코드 실행

jump2it은 https://github.com/adamkramer/jmp2it/releases/tag/v1.4에서 다운로드 받을 수 있습니다.

 

 

3.2.1 쉘코드 추출

[그림 7]에서 '<>'꺽쇠사이에 있는 데이터를 헥사에디터를 활용하여 저장합니다.

그림8 쉘코드 저장

3.2.2 쉘코드 실행

jump2it로 쉘코드를 실행하고 디버거로 jmp2it.exe프로세스에 Attach하는 방식입니다. 번거로운 점은 Attach하고 몇 개의 명령어를 NOP으로 변경해야 합니다.

그림9 쉘코드 실행

x32dbg로 jmp2it프로세스 attach(File → attach)합니다.

그림10 x32dbg Attach 시도

 

attach가 성공하면 일시정지 상태로 되고 ret명령어가 보입니다.

그림11 attach 결과

 

F9를 누르고 2~3초 뒤에 일시정시상태로 변경합니다.

그림12 시작→일시정시 결과

스페이스를 눌러 jmp명령어를 nop으로 변경합니다.

그림14 명령어 변경 결과

all edi까지 실행한 후 F7을 눌러 진입합니다.

그림15 쉘코드 진입

 

[그림 8]에서 저장한 쉘코드와 진입한 명령어가 일치한 것을 알 수 있습니다.

그림16 쉘코드 진입 성공

 

3.3 gbb.exe으로 쉘코드 실행

행위분석 [그림 2]를 보면 gbb.exe가 실행되었습니다. gbb.exe는 구버전 한글을 설치하면 기본으로 설치되는 포스트스크립트 실행기입니다. gbb.exe를 디버거로 실행해서 [그림 7]에서 추출한 포스트스크립트를 실행할 것입니다.

한글설치 경로에 gbb.exe를 찾아 x32dbg로 실행합니다.

* 설치경로: C:\Program Files (x86)\Hnc\Common80\ImgFilters\GS\gs8.60\bin

그림17 gbb.exe 디버거 실행

 

gbb.exe를 실행할 때 필요한 인자(File → Change CommandLine)를 수정합니다. [그림 7]에서 추출한 파일 경로를 추가합니다.

그림18 커맨드라인 수정

 

ctrl + F2를 눌러 gbb.exe를 다시 시작합니다. VirtualProtect에 브레이크포인트를 설정하고 실행합니다. 브레이크포인트에 멈추면 Alt + F9를 눌러 VirtualProtect를 호출한 곳으로 이동합니다. 이동한 곳은 쉘코드 영역입니다. jmp2it실행 결과(그림 16)와 같습니다.

그림19 쉘코드로 이동

 


4. 쉘코드 분석

4.1 API 리졸빙

쉘코드는 실행 중에 필요한 API함수 주소를 가져온 뒤 API함수를 실행합니다. 이 과정을 API리졸빙이라고 부릅니다. x32dbg의 브레이크포인트 컨디션이라는 기능을 사용하여 쉘코드가 가져올 API함수 목록을 가져올 수 있습니다.

쉘코드 시작점에서 F8번을 한번 누르면 함수를 call하는 명령어를 만납니다. F7을 눌러 함수에 진입합니다. 그리고 [그림 20]와 같이 브레이크포인트를 설정하고 마지막 브레이크포인트에 멈출 때까지 실행합니다.

그림20 API 리졸빙 함수에 진입하기 위한 브레이크포인트 설정

 

F7번을 눌러 함수에 진입합니다. 첫 번째 만나는 함수에서도 F7을 눌러 진입합니다.

그림21 API 리졸빙 함수진입

 

오른쪽 버튼을 눌러 Graph버튼을 클릭합니다. 이제 어셈블리 명령어를 그래프로 볼 수 있습니다.

그림22 그래프 모드 전환

 

스크롤을 내리면 xor eax, eax 명령어를 볼 수 있습니다. 해당 명령어는 eax를 0으로 초기화하는 명령어입니다. API함수 주소를 성공적으로 가져왔다면 eax값을 0으로 초기화하지 않으므로 오른쪽 구간은 API함수 주소를 가져오는 과정이 실패했을때 실행됩니다. 반대로 왼쪽은 API함수 주소를 성공적으로 가져왔을 때 실행되는 곳입니다.

jmp 명령어에 브레이크포인트를 설정합니다.

그림23 API리졸빙 분기

 

이제 브레크포인트 조건을 수정할 겁니다. Breakpoints탭으로 이동하고 [그림 23]에서 설정한 브레이크포인트를 찾아 클릭한 후 Ctrl + E를 누릅니다. Break Condition을 0으로 수정하고 Log Text를 [그림 24]와 같이 설정합니다. 브레이크포인트를 만나도 멈추지 않고 로그를 남기는 설정입니다.

* 꼭 스냅샷을 찍고 진행하세요.

 

그림24 브레이크포인트 조건 수정

 

F9를 눌러 실행하고 Log탭으로 이동합니다. 쉘코드가 실행 중에 가져온 API주소를 볼 수 있습니다. 오류가 발생할 때까지 F9를 눌러 실행하여 모든 API이름을 출력합니다.

그림25 API리졸빙 로그

API이름을 보고 악성행위를 추측할 수 있습니다.

※ 프로세스 인젝션

  ▶ WriteProcessMemory

  ▶ RtlCreateUserThread

※ 프로세스 정보 탐색

  ▶ CreateToolhelp32Snapshot

  ▶ Process32First

  ▶ Process32Next

※ 실행환경 검사

  ▶ 32비트인지 64비트인지 확인: IsWow64Process

  ▶ 파일이름검사: GetModuleFileName

※ 권한상승

  ▶ ZwAdjustPrivilegesToken

  ▶ GetCurrentProcess

4.2 프로세스 인젝션

[그림 1]에서 분석한 것처럼 쉘코드는 explorer.exe에 쉘코드를 인젝션합니다. API리졸빙 로그를 통해 프로세스인젝션 함수를 알았으므로 해당 함수에 브레이크포인트를 설정해서 분석해봅시다.

4.2.1 데이터 쓰기: WriteProcessMemroy

스냅샷으로 돌아가 WriteProcessMemroy에 브레이크포인트를 설정합니다. 실행한 후에 스택창을 확인하면 어떤 프로세스에 무슨 데이터를 쓰는지 알 수 있습니다.

※ 2번째 인자: 프로세스 핸들

※ 3번째 인자: 데이터를 쓸 메모리 주소

※ 4번째 인자: 인젝션 데이터

그림26 WriteProcessMemroy 인자 확인

프로세스 핸들은 x32dbg Handles탭에서 확인할 수 있습니다. Process Hacker와 같이 확인하면 explorer.exe입니다.

그림27 인젝션 대상 확인

 

[그림 25]을 스택창을 확인하면 explorer.exe 0x2F60000에 데이터를 쓰려는 것을 알 수 있습니다. Process Hacker의 Memory탭을 확인하면 해당 주소는 현재 비어있고 쓰기(R), 읽기(W), 실행(X) 속성이 있습니다.

그림28 인젝션 할 메모리 주소

 

F9를 눌러 WriteProecessMemory를 실행하면 0x2f60000주소에 데이터가 써집니다.

그림29 인젝션 데이터 확인

 

4.2.2 인젝션 데이터 실행: RtlCreateUserThread

인젝션한 데이터는 RtlCreateUserThread함수에 의해 실행됩니다. 하지만 분석하는 환경이 64비트인 경우에 브레이크포인트를 설정해도 멈추지 않습니다. 64비트용 RtlCreateUserThread함수를 호출하기 때문입니다. 이 문서에서는 분석환경이 64비트라는 전제로 인젝션 코드 실행은 4.3섹션에서 다룹니다.

4.3 64비트 API함수 호출: 헤븐즈게이트

쉘코드는 IsWow64Process함수를 사용해서 실행환경이 32비트인지 64비트인지 검사합니다. 64비트이면 64비트용 RtlCreateUserThread를 실행하여 인젝션한 데이터를 실행합니다.

IsWow64Process에 브레이크포인트를 설정합니다. 브레이크포인트에 멈추면 Alt + F9를 눌러 IsWow64Process를 호출한 곳으로 이동합니다. IsWow64Process결과는 esi레지스터에 저장합니다. 32비트이면 esi레지스터는 0, 64비트이면 esi레지스터가 1이 됩니다.

그림30 IsWow64Process결과 저장

 

저는 분석환경이 64비트이므로 ESI레지스터가 1로 설정됩니다. F8번을 눌러 한줄한줄 명령어를 실행합니다. call eax를 만나면 F7을 누릅니다.

그림31 다른 쉘코드 실행

 

ret far명령어로 64비트 API함수를 실행합니다. ret far을 실행하면 디버거가 꺼집니다.

* 꼭 스냅샷을 찍고 진행하세요.

그림32 64비트 API함수 호출

 


5. 64비트 쉘코드 분석

64비트 API함수 분석은 64비트 디버거를 사용해야하므로 x64dbg를 사용합니다.

5.1 64비트 쉘코드 Attach

x64dbg를 실행하고 explorer.exe에 Attach(File→Attach)합니다.

* explorer.exe를 디버깅 하면 작업 표시줄 등 시스템이 제대로 동작하지 않습니다.

그림33 64비트 explorer.exe attach

 

[그림 28]에서 확인한 주소에 브레이크포인트를 설정합니다. 그리고 x32dbg에서 ret far(그림 32)를 실행합니다.

그림33 코드 인젝션 한 메모리 주소에 브레이크포인트 설정

 

explorer.exe는 바로 브레이크포인트에 멈추지 않습니다. explorer.exe는 쓰레드가 많으므로 브레이크포인트에 멈출 때까지 F9를 눌러 실행합니다.

그림33 브레이크포인트에 멈춤

 

5.2 API 리졸빙

64비트 쉘코드 첫 번째 동작은 [그림 20] ~ [그림 25]처럼 필요한 API함수를 주소를 가져오고 실행합니다.

5.2 API 리졸빙

64비트 쉘코드 첫 번째 동작은 [그림 20] ~ [그림 25]처럼 필요한 API함수를 주소를 가져오고 실행합니다.

* 꼭 스냅샷을 찍고 진행하세요.

 

그림34 API 리졸빙 분기

 

그림35 브레이크포인트 조건 설정

 

Log탭에서 확인하시면 네트워크 연결에 관련된 API함수 주소를 가져오는 것을 알 수 있습니다.

그림36 API리졸빙 목록

 

5.3 네트워크 활동 분석

쉘코드는 InternetConnectA, HttpOpenRequestA를 사용해서 http프로토콜 통신을 합니다. 해당 함수에 브레이크포인트를 설정하면 누구와 통신하고자 하는지 대상을 알 수 있습니다. 현재 대상은 존재하지 않아 대상확인만 가능하고 통신 목적은 확인하지 못합니다.

* 기업 분석 보고서에 의하면 추가 악성코드를 다운로드 받는 목적이라고 합니다.

5.3.1 연결대상 확인: InternetConnectA

IntetnectConnect함수에 브레이크포인트를 설정하고 실행합니다. InetnectConnectA함수 2번째 인자는 연결대상 정보를 저장합니다. 현재 64비트 프로세스이기 때문에 RDX레지스터가 2번째 인자를 저장합니다.

그림37 연결대상 확인

 

5.3.2 연결주소 확인: HttpOpenRequestA

http 프로토콜이므로 [그림 37]에서 확인한 연결대상의 어떤 주소에 연결하려고하는지 확인해봅시다. HttpOpenReuqestA에 브레이크포인트를 설정하고 실행합니다. 3번째 인자가 연결주소를 저장합니다. 64비트이므로 R8레지스터가 3번째 인자 값을 저장합니다.

그림38 연결주소 확인

 


6. 참고자료

※ ghostscript 다운로드 링크: https://github.com/ArtifexSoftware/ghostpdl-downloads/releases

※ 분석보고서(중국어): https://norfolkinfosec.com/how-to-analyzing-a-malicious-hangul-word-processor-document-from-a-dprk-threat-actor-group/

※ 이글루시큐리티 월간보안동향 2월 보고서: http://www.igloosec.co.kr/pdf/igloosec_security_report_202002.pdf

※ x64dbg log format: https://help.x64dbg.com/en/latest/introduction/Formatting.html

※ 64bit calling convetion: https://docs.microsoft.com/ko-kr/cpp/build/x64-calling-convention?view=vs-2019

반응형