보안정보
전문화된 보안 관련 자료, 보안 트렌드를 엿볼 수 있는
차세대 통합보안관리 기업 이글루코퍼레이션 보안정보입니다.
악성코드로 알아보는 Reflective DLL Injection
2020.10.06
17,102
01. 개요
악성코드 공격자들의 공격 기법은 날로 진화하고 있다. 보다 안정적이고 정확하게 목표를 공격하기 위해 다채로운 유포 방법들을 이용하고 있고, 보안 장비/소프트웨어의 탐지를 피하기 위해 다양한 기법들을 이용하여 악성코드를 은밀하게 감춘다. 그중 파일리스(Fileless)를 이용한 악성코드 은닉 방법이 점점 더 다양해지고 있다.
올해 초 발견된 매그니베르(Magniber) 랜섬웨어는 인터넷 익스플로러 프로세스에 Injection하여(Fileless) 사용자의 PC에 악성 파일을 남기지 않고 파일들을 암호화하는 행위를 한것이 파악되었다. 또한 지난 5월 전미북한위원회(NCNK)의 ‘북한 코로나19 상황 인터뷰 문서’를 사칭한 DOC 문서형 악성코드가 발견되었는데 이는 윈도우 작업 스케쥴러를 이용하는 파일리스 형태였다.
이처럼 Fileless 기법을 이용하는악성코드들이 심심치않게 등장하고 있으며 앞으로도 사용빈도가 증가할 것으로 보인다. 공격에는 주로 파워 쉘(PowerShell) 스크립트를 난독화하여 이용하거나 Process Hollowing, Reflective DLL Injection 등의 기법을 이용한다.
올 해 6월 22일 국내 유명 커뮤니티에서 시력 보호 프로그램을 사칭한 악성코드가 유포되었다. 해당 악성코드는 실행 시 백그라운드에 그림판(정상 파일)을 실행하는 것 외에는 별다른 수상한 행위가 보이지 않는 파일이었다. 그러나 상세 분석결과 그림판(정상 파일)에 임의의 DLL을 Reflective DLL Injection 시켜 악성 행위를 하는 행위를 발견하였다. 백그라운드에서 임의의 C2로 접속하는 로그는 계속해서 남으나 악성 행위를 하는 파일은 존재하지 않는 Fileless 악성코드였다. 월간보안동향 9월호 Tech Note에서는 실제 악성코드에서 어떻게 Reflective DLL Injection 기법을 사용하는지 알아보고자 한다.
02. DLL Injection과 Reflective DLL Injection
1) DLL Injection
DLL Injection은 실행 중인 다른 프로세스의 공간에 강제로 DLL을 Injection하는 방법을 의미한다.
[그림 1] DLL Injection 과정 (출처 : malwareforensics1.blogspot.com)
비교적 간단한 방법으로 DLL을 Injection 시킬 수 있기 때문에 악성코드에서 많이 사용되었으나 CreateRemoteThread로 대상 프로세스의 Injection 된 DLL을 실행할 때 들어가는 lpStartAddress 인자 때문에 쉽게 탐지된다는 단점을 가진다. lpStartAddress 인자에는 GetProcAddress를 통해 얻어온 LoadLibrary(혹은 GetProcAddress) API의 주소가 들어가게 되는데 이 부분을 탐지하게 되면 DLL Injection을 막을 수 있게 된다.
2) Reflective DLL Injection
Reflective DLL Injection은 기존의 DLL Injection 방법과 달리 현재 실행중인 프로세스의 메모리에 임의의 DLL에 대한 데이터를 삽입한 후 직접 매핑(Mapping) 하여 실행시키는 방법으로 동작한다. 이러한 동작 방법으로 실제 악성 행위를 하는 DLL은 백그라운드에 존재하지 않으며 탐지 또한 어렵다. 이러한 점에서 파일리스(Fileless) 악성코드에서 많이 사용되고 있으며 2017년 이슈가 되었던 SMB취약점 이터널블루(Eternal Blue)와 더블펄서(Double Pulsar)에서도 사용되었다.
[그림 2] Reflective DLL Injection 과정(출처 : giac.org)
3) 차이점
두 가지의 Injection 방법은 DLL을 어떠한 형태로 프로세스에 인젝션 하는가에 따라 달라진다. DLL Injection은 실행 가능한 파일(PE) 그대로를 프로세스에 인젝션하고, Reflective DLL Injection의 경우 인젝션 시 실행 가능한 파일을 현재 사용중인 메모리에 직접 인젝션하고 메모리에서 바로 사용 가능하게 만드는 작업들까지 함께 진행한다는 점이 다르다.
구분 | DLL Injection | Reflective DLL Injection | |
---|---|---|---|
인젝션 | 방법 | 인젝션 하고자 하는 DLL의 경로를 직접 삽입 | 인젝션 하고자 하는 데이터를 메모리에 직접삽입 후 메모리에 매핑(MAPPING) |
실행 | 스레드(Thread) | 스레드(Thread) | |
탐지방법 | · 레지스트리(AppInIt_DLLs) 값 체크 · 스레드 함수 내부 인자 값 체크 |
· 정상 동작에서 벗어나는 메모리 영역의 권한 체크 (메모리에 로드해야 하기 때문에 임의의 메모리 영역에 RWX권한을 부여) |
03. 악성코드로 알아보는 Reflective DLL Injection 동작원리
분석에 사용된 악성코드는 지난 6월 국내 인터넷 커뮤니티 자료실에서 시력보호 프로그램을 사칭하여 유포된 악성코드이다. 인스톨러(Installer) 형태로 되어있으며 실행 시 정상적으로 시력보호 프로그램을 다운로드하지만 백그라운드에서는 그림판(mspaint.exe) 프로세스가 실행되며 C2 주소로 PC 정보를 전송하는 행위를 한다. 그림판의 경우 System32내부에 있는 정상 프로세스를 이용했으며 공격자들은 해당 공격을 위해 Reflective DLL Injection 기법을 이용하였다.
1) 악성코드 전체 구성 – 어디에서 사용된 걸까?
해당 악성코드의 전체 개요도는 [그림 3]과 같다. 실행과 동시에 악성 DLL(wctE64E.tmp)이 드롭 되고 바로 삭제되는 것처럼 보인다. 그러나 백그라운드에서는 그림판(mspaint.exe)이 동작하면서 C&C 서버와 통신하는 기이한 현상이 발생한다. 악성 행위를 하는 것으로 추정되는 DLL 파일이 사라졌는데 악성 행위가 정상 프로세스를 통해서 계속된다? 어떻게 이렇게 될 수 있는 걸까. 이는 모두 악성 DLL에서 이루어 지며 자세한 내용은 다음 챕터에서 알아보자.
구분 | 내용 |
---|---|
파일명 | wctE64E.tmp |
MD5 | 19493F139D74950681354BB881113683 |
파일크기 | 286.50 KB (293,376 byte) |
[그림 3] 악성코드 개요도
2) Reflective DLL Injection – 어떻게 이루어지는 걸까?
Reflective DLL Injection은 기존의 DLL Injection 방법과 달리 현재 실행중인 프로세스의 메모리에 임의의 DLL에 대한 데이터를 삽입한 후 직접 매핑(Mapping) 하여 실행시키는 방법으로 동작한다. 이러한 동작 방법으로 실제 악성 행위를 하는 DLL은 백그라운드에 존재하지 않으며 탐지 또한 어렵다. 이러한 점에서 파일리스(Fileless) 악성코드에서 많이 사용되고 있으며 2017년 이슈가 되었던 SMB취약점 이터널블루(Eternal Blue)와 더블펄서(Double Pulsar)에서도 사용되었다.
해당 악성코드에서는 악성 DLL을 Injection 하는 대상으로 mspaint.exe(그림판)을 이용하였다.
해당 프로세스를 생성한다
[그림 4] mspaint.exe 프로세스 오픈
현재 실행 중인 악성 DLL 파일(wctE64E.tmp)과 동일한 위치에 실행중인 악성 DLL과 동일한 파일을 생성 시도하지만 CreateFileW의 dwShareMode 인자가 0x0으로 설정되어 있어 디버깅 상태에서는 정상적으로 파일 생성을 할 수 없게 설정되어 있다.(안티 디버깅 효과) 해당 부분을 우회하면 정상적으로 파일을 생성하는 부분을 확인할 수 있다.
[그림 5] 현재 실행중인 악성 DLL 파일의 핸들 수집
정상적으로 생성된 파일(현재 실행 중인 악성 DLL)의 크기를 확인 후 크기만큼 힙(Heap)을 할당한다. 정상적으로 힙을 할당한 후 생성된 파일(현재 실행 중인 악성 DLL)의 데이터를 할당된 힙에 복사한다.
[그림 6] 악성 DLL의 데이터를 사용하기 위한 과정(1)
[그림 7] 메모리 로드전(위)과 로드 후(아래)
mspaint.exe 프로세스 내부에 본격적으로 악성 DLL를 Injection 하기위해 생성(CreateProcess) 해두었던 프로세스를 오픈한다.
[그림 8] mspaint.exe 프로세스 오픈
본격적으로 Reflective DLL Injection을 하기 위해 로더함수인 iAppleCloud 함수를 호출한다. 해당 함수는 Import Table에 선언되어 있다. 함수 내부 코드를 보면서 살펴보도록 하자.
[그림 9] Reflective DLL Injection 로더 함수(iAppleCloud) 호출
STEP1 | 로더에서 사용할 데이터 가공하기 |
---|---|
Injection을 위해서는 로더(Loader)의 기능이 중요하다. 해당 로더에서는 현재 실행 중인 악성 DLL이 호출 중인 시스템 DLL(ntdll.dll, kernel32.dll)들의 정보를 필요로 한다. 로더의 기능을 위해 API가 필요하기 때문이다. 해당 로더 함수에서는 Windows API Hash를 이용하여 필요한 시스템 DLL과 API를 찾아 로더에서 사용할 수 있는 형태로 가공한다. |
STEP2 | 이미지 로드 |
---|---|
로드할 PE의 헤더를 가지고 온 후 악성 DLL을 메모리에 로드하기 위한 메모리를 할당한다. 가상 메모리에 로드될 때 실행 가능한 Imagebase에 로딩될 수 있도록 재배치(Relocation) 작업을 진행한다 |
STEP3 | 이미지를 로드할 섹션 확인 |
---|---|
임의의 섹션에 데이터를 로드하기 위해 섹션 영역을 탐색한다. |
STEP4 | Import Table 재작성 |
---|---|
로로드 된 새로운 이미지의 파일을 참조하여 IAT를 재작성한다. |
STEP5 | 프로세스 이미지 재배치 |
---|---|
모든 과정이 끝난 이미지가 충돌없이 메모리에 로드 될 수 있도록 재배치(Relocation)한다. |
OpenProcess로 오픈했던 mspaint.exe의 내부에 0x47AAA(실행 중인 악성 DLL의 파일 크기) 만큼 임의의 공간을 할당한다. (할당되는 공간의 주소는 매 실행 시 달라짐)
[그림 10] mspaint.exe의 내부에 악성 DLL을 로드하기 위한 임의의 공간 할당
[그림 11] mspaint.exe – 임의의 공간이 할당됨
WriteProcessMemory를 이용하여 총 세 번에 걸쳐 mspaint.exe의 내부로 데이터를 삽입한다.
NO | 내용 |
---|---|
1 | Heap 영역에 로드되어있는 현재 실행중인 악성 DLL |
2 | 현재 실행중인 악성 DLL의 절대경로 |
3 | 스레드 실행 시 처음 시작되는 부분 |
[그림 12] WriteProcessMemory를 이용하여 데이터 삽입
[그림 13] 첫 번째 WriteProcessMemory를 통해 삽입되는 내용
[그림 14] 두 번째 WriteProcessMemory를 통해 삽입되는 내용
[그림 15] 세 번째 WriteProcessMemory를 통해 삽입되는 내용
mspaint.exe에 Reflective DLL Injection 된 악성DLL을 CreateRemoteThread로 실행한다.
[그림 16] CreateRemoteThread를 이용하여 Injection된 DLL 데이터가 실행
04. 참고자료
Reflective DLL Injection
- https://0x00sec.org/t/reflective-dll-injection/3080
Fileless 사례
- http://www.dailypop.kr/news/articleView.html?idxno=45150
- https://koya-culture.com/news/article.html?no=123015