0. 목차
1. 악성코드 개요
1) 개요
국내 주요 공공기관과 기업 등 많은 사용자들이 이용하는 HWP문서를 대상으로 한 악성코드가 꾸준히 유포되고 있다. 이번에 분석할 HWP문서는 도널드 트럼프 미국 대통령과 김정은 북한 국무위원장이 2019년 2월 27-28일 베트남 하노이에서 가졌던 2차 북미 정상회담 결과에 대한 특별좌담회 문서파일을 미끼로 사용하였다.
일반 문서로 위장된 악성 HWP
악성 HWP 문서의 상당수가 EPS를 이용하여 악성행위를 수행한다.
EPS란 Encapulated PostScript의 약자로, Adobe에서 만든 PostScript 언어를 이용하여 그래픽 이미지를 표현하는 파일이다. 이를 이용하여 각종 고화질 벡터 이미지를 표현할 수 있어 HWP에서는 EPS 이미지를 포함하거나 볼 수 있는 기능이 존재한다.
EPS에서 사용한 CVE-2017-8291 취약점은 고스트스크립트 인터프리터가 ‘.eqproc’ 함수에서 매개변수 타입 유효성을 검증하지 않아 피연산자 스택의 메모리가 변조된다. 즉, 악의적인 PostScript 파일로 스택을 변조함으로서 임의 코드를 실행할 수 있다.
2017년 초 한글과컴퓨터에서는 EPS 파일 처리 과정에서 발생하는 취약점을 조치하여 최신 업데이트가 적용된 hwp는 EPS를 이용한 악성코드가 동작하지 않는다. 하지만 여전히 예전 버전을 사용하는 사용자들이 많기 때문에 해당 악성코드는 꾸준히 배포되고 있다.
2) 분석 환경 및 대상 정보
Default view
Search
Default view
Search
2. 상세분석
2.1) 행위 분석
한글문서를 실행시키면 쉘코드가 바로 실행된다. Procmon 프로그램의 Process Tree 기능을 이용하여 현재 한글문서 하위에 실행되는 프로세스들을 확인할 수 있다.
그림 1. 한글 문서 실행결과
EPS 파일을 포함한 한글 문서가 이미지를 로드할 때 OLE 구조상 EPS 파일은 임시파일 형태로 BinData 폴더에 생성된다. 한글 프로세스는 생성된 임시 파일을 인터프리터가 전달받아 처리하도록 gbb.exe 프로세스와 gswin32c.exe 프로세스에 임시 파일 경로를 인자로 전달하여 실행한다.
OLE는 Microsoft의 기반 기술로써 일반적으로 복합 문서를 지칭한다. 복합 문서에는 다양한 종류의 정보 객체가 포함될 수 있는데 이러한 정보 객체를 OLE Object라고 한다. OLE Object는 문서, 동영상, 소리, 수식, 표 등과 같이 어떤 작업의 결과물이다
따라서 위 사진과 같이 한글 프로세스 하위에 2개의 gbb.exe, gswin32c.exe 프로세스가 실행되고 있는걸 볼수 있다. 하지만 각 프로세스의 하위에서 iexplore.exe가 injection되어 있다. 이는 사용자의 눈 보이지 않게 동작하며, 실제 악성행위는 해당 iexplore.exe 내부에서 일어날 것으로 유추된다.
2.2) 악성코드 추출(EPS - PostScript)
우선 한글 문서 내부에 들어있는 EPS 파일을 추출해보자. 누리랩에서 개발한 Hwp2Scan 프로그램을 이용하면 한글문서의 취약점을 확인 할 수 있고, EPS 파일을 뽑아 낼 수 있다.
그림2. hwp2scan 결과
취약점 검사 기능을 이용하면 현재 검사하고 있는 한글문서에 존재하는 취약점을 확인할 수 있는데, 현재는 취약점이 발견되지 않는다. 왜냐하면 악성 PostScript 파일은 코드가 암호화가 되어있어 검사로직에 확인되지 않는다.
우선 BinData 폴더안에 있는 BIN003.eps 파일을 추출한다. 참고로 BinData 폴더는 압축된 상태이므로 추출 옵션 중 ' Save a Hex(Decompress) ' 을 이용해야 한다.
그림3. 추출한 PostScript 파일
그림 3이 바로 인코딩된 PostScript 파일을 Sublime Text로 확인한 결과이다. 첫번째 라인의 꺽쇄 다음으로 시작하는 이어지는 문자열이 바로 쉘코드이다. 이 PostScript를 실행시키면 xor 연산을 통해 인코딩된 쉘코드가 복호화가 되고 실행이 된다.
따라서 복호화된 쉘코드를 얻기 위해 12라인의 exec 를 print로 변경하여 헥사값으로 얻어낼 것이다. 이렇게 하면 따로 PostScript의 문법을 몰라도 원한는 복호화 결과는 얻을수 있다.
그림4. 12라인의 exec를 print로 변경
코드를 수정하고 mal.eps이름으로 새로 저장한다.
2.3) PostScript 실행
Postscript는 GhostScript를 이용하여 실행시킬수 있다. 단 주의해야 할점은 작성된 PostScript는 버전에 따라서 문법이 약간 다르므로 위 EPS를 실행하기 위해선
9.6.2 버전의 GhostScript를 설치해야한다.
•
바이너리 위치
1.
C:\Program Files\gs\gs9.26\bin
•
사용법
1.
터미널에서 gswin64c.exe 실행
2.
(EPS 파일 경로) run
주의 : 파일경로는 역슬래쉬가 아닌 슬래쉬여야 한다
그림6. EPS 실행결과
PostScript의 마지막 exec 부분을 print로 변경하여 복호화된 코드가 출력된다. 출력결과를 에디터로 확인해보면 다음과 같다
그림7. EPS 복호화 결과 코드 일부
복호화된 결과를 보면 기존의 코드보다 매우 길어진걸 확인할 수 있다. 그 중 9090.. 으로 시작하는 부분이 존재하는데 이는 쉘코드의 nop 영역인 걸을 유추할 수 있다. 따라서 해당 쉘코드로 추청되는 놈을 실행시켜보자.
2.4) shellcode 분석
아래 사이트는 쉘코드를 exe 파일로 변환시켜주는 사이트이다.
그림8. shellcode → exe convert
submit을 누르면 쉘코드가 exe 파일로 변환되어 저장된다. 이를 Cutter 프로그램을 이용해서 Graph view를 확인해보자.
그림9. Cutter를 이용한 shellcode의 Graph View
중간 block을 확인해보면, 반복해서 al 레지스터의 값을 xor 연산하는 걸 확인할 수 있다. 이 뜻한 해당 shellcode 또한 암호화가 되어있다는 의미이다. 현재 그림1에서 볼수 있었다시피 자식 프로세스로 iexplore.exe를 실행시키기 때문에 createprocess를 시작점으로 하여 분석을 진행해보자.
참고로 기드라를 이용하여 헥스레이를 확인할 수 도 있다.
그림10. CreateProcessA → breakpoint
위 사진은 CreateProcessA 에 break를 걸고 실행했을 때의 결과이다. esp+8이 해당 api의 2번째 인자 위친데, 여기를 보면 iexplore.exe의 경로가 지정되어 있는것을 확인할 수 있다. 현재 위치는 dll 내부의 CreateProessA 이므로 해당 영역을 빠져나와서 다시 쉘코드 위치로 돌아가보자.
그림11. CreateProcessA() 종료 후 생성된 iexplore.exe
call eax 어셈이 바로 CreateProcessA()이다. 현재 호출을 완료했고, Process Explorer 프로그램을 이용해서 확인해보면 프로세스가 생성된 것을 볼 수 있다. 현재는 suspend(일시중지) 상태이다. 예상되는 악성행위로는 일시중지된 iexplore.exe에 코드를 인젝션 할 것으로 보인다. 이 부분이 어딘지를 찾아보자.
그림12. CreateProcessA() 후 user-code
얼마지나지 않아 0x40146C 라인에서 어떤 shellcode.4010DD를 call한다. 해당 함수 내부를 확인해보자.
그림13. API Resolving code pattern
중간에 동일한 shellcode.40107E를 계속 호출하고, 그 결과값을 스택의 배열에 저장한다. 이는 API Resolving 코드 패턴으로, 동적으로 API를 가져오게 된다. VirtualAllocEx으로 메모리를 할당하고, writeProcessMemory로 어떤 값을 쓴다. 마지막으로 해당 값을 CreateRemoteThread로 동작시킨다. 아마 이 부분이 iexplore.exe에 code inject을 수행하는 로직일 것이다.
어떤 값을 쓰는지 writeProcessMemory 부터 자세히 봐보자.
2.4.1 WriteProcessMemory → code inject to iexplore.exe
BOOL WriteProcessMemory(
HANDLE hProcess, // 조작할 대상 프로세스 핸들
LPVOID lpBaseAddress, // 값을 쓸 주소
LPCVOID lpBuffer, // 값
SIZE_T nSize, //메모리 크기
SIZE_T *lpNumberOfBytesWritten
);
C++
복사
WriteProcessMemory의 인자는 다음과 같다. 인자로 들어가는 값을 확인해보자
그림14. WriteProcessMemory 프롤로그
스택을 보면 해당 API의 인자들을 볼 수 있다. 현재 처리할 핸들 값의 위치에 0xAC가 들어가 있고, Handles 에서 해당 값을 찾으면 다음과 같은 결과를 볼 수 있다.
그림 15. PID 0x2FC(764) 의 핸들 값
해당 핸들값은 0x2FC PID 값을 가진 프로세스를 처리한다는걸 알 수 있다.
그림 16. Injection 될 주소
두번째 인자인 값을 쓸 주소는 VirtualAlloc으로 할당받은 주소인 0xc0000이다. RWX 권한으로 전에 할당을 받았기 때문에 WriteProcessMemory가 끝나게 되면 해당 영역으로 쉘코드가 injection 될 것이고 현재는 아무것도 들어있지 않다.
그림 17. Injection 될 코드
마지막 3번째 인자는 Injection 될 코드의 주소인데 0x4014D3가 바로 이 영역이다. 해당 코드가 0xc0000에 채워질 것이다.
그림 18. Injection 된 코드
*중간에 디버거가 꺼져서 주소는 달라졌다. 아까 0xc0000 영역이 0x80000이라고 보면 된다
널바이트로 채워져 있던 영역에 코드가 삽입되었다
2.4.2 CreateRemoteThread
이제 삽입된 쉘코드는 CreateRemoteThread를 통하여 실제 동작이 이뤄진다.
그림19. Inection 되어 실행된 쉘코드
suspend 상태였던 iexplore.exe 프로세스가 CreateRemoteThread 를 통하여 실행된 것을 볼 수 있다. 따라서 실제로 어떠한 악성행위를 하는지를 알아보기 위해 Injection 된 코드를 전과 동일한 방식으로 추출하여 다시 분석을 진행해보자.
2.4.3 악성 행위 분석
그림20. 복호화 루틴
추출한 실제 쉘코드 역시 암호화가 되어있고, xor으로 복호화가 진행되고 jmp로 이동하여 실제 동작이 진행된다. 현재 C&C 서버가 닫혀있으므로 더 이상의 동적 분석은 불가능하다.
이글루 시큐리티의 분석 보고서에 따르면, 이 경우 악성행위를 하는 코드 뿐만 아니라 C&C주소도 함께 복호화 된다. 해당 악성코드는 복호화 된 C&C에서 추가 악성코드를 다운로드 받아온 후 최종 악성행위를 진행한다고 한다.
따라서 Any Run Sandbox를 이용해서 현재 추가적으로 확인할 수 있는 정보를 확인해보자.
그림21. 쉘코드가 요청하는 C&C 서버 주소 확인
쉘코드 내부에서 " http://itoassn.mireene.co.kr/shop/shop/mail/com/mun/down.php " 주소로 어떠한 Request를 보내는 것을 볼 수 있다. 해당 주소는 Any Run에서는 자세히 안나고오 디버거로 확인 가능하다
해당 서버에서 추가적인 악성코드를 쉘코드가 요청하게 되고 이는 VBE라는 파일을 다운로드 받게끔 한다. 해당 파일은 여러번 인코딩된 URL을 포함하고 이를 디코딩하여 난독화된 VBS 코드를 얻을 수 있고, 이를 해제하여 코드 원본을 확인할 수 있다.
자세한 내용은 위 사이트에서 확인 할 수 있다
3. 정리
최종적인 해당 악성코드의 행위를 정리하면 다음과 같다.
1.
C&C 서버로부터 추가 파일을 다운받고 실행
2.
Code Injection을 통해 정상 프로세스에 삽입된다.
이러한 악성코드는 일반 사용자는 확인하기 힘들며, 삽입된 코드는 키로깅, 백도어 등의 작업을 수행한다
참고로 해당 보고서에는 CVE-2017-8291 EPS 취약점 구현에 대한 내용은 추가하지 않았지만 추후에 따로 POC를 구현해볼것이다.