루비 스크립트를 활용한 APT 공격, 국내 기관을 노린다
최근 국내 여러 기관을 대상으로 루비(Ruby) 스크립트를 활용한 APT(Advanced Persistent Threat) 공격 정황이 포착됐다. 이 공격은 기존 악성코드와는 다르게 루비 스크립트를 활용해 감염 과정을 시작하며 해당 공격에 사용된 스크립트는 마이크로소프트 관련 파일로 위장하였다. 공격 과정에서는 여러 데이터 파일을 참조하며, 감염 대상 PC 이름이 특정 이름일 경우에만 동작하도록 구성했다. 최종적으로 실행되는 악성코드는 ‘RokRAT’이라 불리는 악성코드와 매우 유사하다.
이번 글에서는 루비 스크립트로부터 시작되는 APT 공격에 대한 분석 정보를 조명한다.
서두에 언급한대로 이번에 살펴볼 공격은 악성코드 실행을 위해 루비(Ruby) 스크립트를 사용한다. 따라서 해당 스크립트를 실행하기 위해서는 윈도우(Windows)용 루비 프로그램이 설치되어 있어야 한다. 공격에 사용된 루비 프로그램의 위치가 일반적으로 설치되는 디렉토리인 ‘%Program Files%’ 경로가 아닌 ‘%Appdata%’ 경로에 위치하는 것으로 보아 사전에 공격자에 의해 설치되었을 것으로 추정된다. 또한 공격 과정에서 여러 파일을 참조하기 때문에 해당 파일이 존재하지 않으면 감염이 진행되지 않는다.
따라서 본 공격 과정 전에 어떠한 방식으로 루비 프로그램을 설치하고 감염에 필요한 관련 파일들을 드롭하는 행위를 선행했을 것으로 판단된다.
루비 스크립트 활용 공격 분석
감염 PC의 루비 프로그램 폴더 내부에는 다음 그림과 같은 악성 파일 ‘Windows Container Isolation FS Filter Driver.ini’이 있다. 파일 확장자는 ini이지만, 내부 데이터는 루비 스크립트 코드이다.
[그림 1] 루비 폴더 내 악성 파일
파일의 내용은 다음 [그림 2]와 같다. 특정 경로의 파일을 실행하는 명령어이다.
[그림 2] .ini 파일 내용
해당 경로의 ‘history.zh.urls’ 파일 내용 역시 루비 스크립트이며 내용은 다음 [그림 3]과 같다.
[그림 3] history.zh.url 파일 내용
마이크로소프트(Microsoft: MS) 관련 문자열을 주석과 URL 형식의 문자열에 사용해 MS에서 제작한 파일로 위장했다. 본 스크립트가 실행되면 ‘https://update.microsoft.com/driverupdate=’ 뒤의 문자열을 역순으로 배치한 결과를 Base64 디코딩 후 실행한다. 해당 디코딩 과정을 거쳐 실행되는 코드는 다음 [그림 4]와 같다.
[그림 4] 디코딩 결과 스크립트
그림의 코드는 특정 경로의 파일을 읽어 복호화한 값을 rubyw.exe의 프로세스에 할당한 가상 메모리에 복사한다. 이후 별도의 스레드를 생성하여 실행한다. 복호화 값은 x64 쉘코드이며 해당 쉘코드의 행위는 다음과 같다.
쉘코드 1 (Shortcut_26E6.info)
Shortcut_26E6.info 파일을 복호화한 쉘코드는 약 180KB의 크기로 ‘Code+PE 데이터’의 구조를 갖는다. GetTickCount()와 IsDebuggerPresent()를 활용한 분석 방해 코드가 존재한다.
[그림 5] 안티 디버깅 코드
실행 시 코드 뒷부분의 데이터를 ROL과 XOR 연산을 통해 복호화하는데, 복호화 결과는 실행파일(Portable Executable: PE)이며 해당 파일 정보는 [표 1]과 같다.
[그림 6] 복호화 코드
[표 1] 복호화된 PE 정보
이후 복호화된 PE 바이너리를 가상 메모리에 매핑한 후 JMP 명령어를 통해 EP(Entry Point)로 분기하여 실행한다.
[그림 7] 인젝션 PE로의 분기 코드
이로 인해 실행되는 PE 파일의 행위는 다음과 같다.
PE 1: 로더(Loader)
GetModuleFileNameA() 함수를 통해 현재 모듈의 파일 경로를 얻은 후 ‘UBY’ 문자열이 없을 경우 실행 불가능한 코드로 분기하는 행위가 있다. 이는 현재 모듈이 rubyw.exe를 통해서 실행되었는지를 검사하기 위한 행위이다.
[그림 8] 파일 경로 검사 코드
GetComputerNameW() 함수를 통해 PC 이름을 얻어 온 후 MD5 값을 구한다. 이때 NULL 패딩을 추가한 0x40 바이트 크기의 데이터를 연산에 사용한다. 해당 과정에서 얻어진 해시값과 특정 바이트 배열을 XOR한 값을 키로 사용하여 특정 데이터 블록을 AES 복호화 한다. 복호화에 필요한 IV값(‘323112233445566778899AAB0CBDCEDF’)은 별도로 하드코딩 되어있다. 복호화 결과값은 특정 파일의 경로이며, 이후 해당 파일을 참조하게 된다. 따라서 PC 이름이 특정 이름일 경우에만 감염된다. 본 샘플이 감염된 환경에서는 사용자의 이름을 PC 이름으로 사용하였다.
[그림 9] PC 이름 활용 복호화 키 생성 코드
[그림 10] 데이터 블록 복호화 결과
복호화된 경로의 파일을 열고 내부 데이터를 이전 과정과 동일한 알고리즘과 키로 복호화한다. 복호화 결과는 쉘코드이다. 해당 쉘코드를 실행하는 방식에서는 백신 사용 환경에 따라 다른 방법을 사용한다. 윈도우 관리 도구(Windows Management Instrument: WMI) 쿼리를 사용하여 현재 사용 중인 안티바이러스(AV) 제품의 이름을 얻은 다음 특정 백신을 사용 중인지 검사한다. NameSpace ‘root\\SecurityCenter2’에 대한 WMI 쿼리 ‘Select * From AntiVirusProduct’ 조회 결과에서 ‘displayName’ 항목의 어베스트(Avast)와 시만텍(Symantec) 문자열을 검사한다. 해당 결과에 따라 이후 쉘코드 실행 방식이 달라진다.
[그림 11] AV 제품 조회 WMI 쿼리
[그림 12] AV 문자열 비교
문자열 검사 결과에 따라 달라지는 쉘코드 실행 방식은 다음과 같다.
Avast 또는 Symantec AV 제품을 사용 중일 경우:
현재 프로세스에 가상 메모리를 할당한 후 쉘코드를 복사한 후 Call 명령어를 통해 분기한다.
기타 백신을 사용 중인 경우:
System32 하위 다음 프로세스 중 랜덤으로 한 개를 선택하여 실행 후 스레드를 일시 정지시킨다.
[표 2] 실행 대상 프로세스 목록
이후 해당 프로세스에 원격으로 가상 메모리를 할당한 후 쉘코드를 인젝션한 뒤 별도의 스레드를 생성하여 쉘코드를 실행한다.
[그림 13] 특정 AV 사용 여부에 따른 분기 코드
쉘코드 2: WinSDK_38B8.info
두 번째 쉘코드 역시 ‘Code+PE 데이터’의 형식을 갖는다. 여기서 Code 부분은 위에서 언급한 1번 쉘코드와 동일하다. 코드 뒷부분의 PE 데이터를 복호화한 후 JMP 명령을 통해 EP를 실행한다. 이때 실행되는 PE는 정보 탈취 및 다운로더 기능을 한다.
[그림 14] 메모리에 인젝션된 PE
[표 3] 인젝션 PE 정보
PE 2: 인포스틸러(Infostealer) & 다운로더(Downlaoder)
PE 실행 시 컴퓨터 이름으로 연산한 값을 뮤텍스(Mutex)로 사용하여 중복 실행을 방지한다.
[그림 15] Mutex 생성 및 종료 코드
해당 악성코드는 윈도우 생성 후 등록된 윈도우 프로시저(Windows Procedure)에서 수신되는 메시지를 모니터링하며 악성 행위를 수행한다. 첫 실행 시 쉘코드에서와 동일한 방식으로 컴퓨터 이름에 대한 해시값을 값을 키로 특정 데이터를 복호화하는데, 복호화 결과는 특정 디렉토리 경로이다.
[표 4] 복호화된 경로명
해당 디렉토리 하위에 ‘WER+[특정 문자열]’ 폴더를 생성한 뒤 파일을 생성한 후 '읽기 전용'과 '시스템 파일' 옵션을 부여한다.
[그림 16] 폴더 및 파일 생성
해당 파일에 국가, 윈도우 버전, 바이오스(BIOS) 버전, CPU 정보, 디스크/파일시스템 정보, 네트워크 어댑터 정보, 설치된 프로그램 정보 등의 시스템 정보와, 악성 행위에 사용되는 디렉토리 및 파일 경로, C2 통신 시 인증 토큰값 등 악성 행위에 사용되는 전반적인 정보가 기록된다. 해당 파일은 암호화되어 저장되며 선행 과정에서 생성한 키로 복호화가 가능하다.
[그림 17] 파일 저장 내용 (복호화)
그리고, ‘AddClipboardFormatListener()’ 함수를 사용해 클립보드 변경 시 메시지를 발생시킨다. 이 메시지는 윈도우 프로시저에 의해 모니터링되며, 해당 메시지가 발생할 때마다 클립보드 데이터와 최상위 윈도우의 타이틀을 저장한다.
[그림 18] 클립보드 탈취 코드
[그림 19] 저장된 클립보드 내용과 최상위 윈도우 제목
이후 WM_DEVICECHANGE 메시지를 모니터링하며 장치 연결과 해제를 기록한다. 이는 ‘[현재시각].usb’ 파일에 기록되며 그 내용은 다음과 같다.
[그림 20] USB 장치 연결 시 기록 정보
[그림 21] USB 장치 제거 시 기록 정보
WMI 쿼리 결과를 통해 사용 중인 AV 정보를 ‘[현재시각]_vinfo.txt’ 파일에 기록한다. 이는 이전 쉘코드에서 사용한 방식과 동일하다.
[그림 22] AV 조회 WMI 쿼리 코드
[그림 23] 사용 중인 AV 기록 정보
http://ipinfo.io/에 접속해 수신한 내용을 바탕으로 감염 PC의 IP, 위치, 국가, 기관명 등의 정보를 ‘[현재시각]_iinfo.txt’ 파일에 json 형식으로 기록한다.
[그림 24] 감염 PC의 IP 관련 기록 정보
레지스트리를 통해 다음 [표 5]와 같이 루비 스크립트를 자동실행 등록한다. 부팅 시마다 이전 과정을 거치며 악성코드가 동작하게 된다.
[표 5] 레지스트리 자동실행 등록 내용
이어서 CMD 명령어를 통해 ‘Windows Container Isolation FS Filter Driver’ 이름의 작업 스케줄러 항목을 제거한다. 해당 항목은 기본적으로는 존재하지 않는 항목이다. 감염 시작 단계에서 실행되는 루비 스크립트의 경로명과 내부 문자열과 일치하는 것으로 보아, 이전 공격에 대한 흔적을 지우는 행위로 추정된다.
[그림 25] 작업 스케줄러 제거 명령어
이외에도 각종 브라우저 정보를 수집하는 코드가 존재한다. 브라우저의 계정 정보와 쿠키 정보, 설정 정보를 수집하며 대상 브라우저는 인터넷 익스플로러(Internet Explorer: IE), 크롬(Chrome), 엣지(Edge), 파이어폭스(Firefox), 오페라(Opera), 네이버 웨일(Naver Whale)이다.
[그림 26] 정보 탈취 대상 브라우저
[그림 27] 브라우저 정보 탈취 SQL 쿼리
브라우저 외에도 FTP 클라이언트, 메일 클라이언트 등의 정보도 탈취 대상이 된다. 탈취 대상으로는 WinSCP, FileZilla, Outlook, Thunderbird 등이 있다.
[그림 28] Outlook 서명 정보 탈취 코드
[그림 29] FileZilla 서버 정보 탈취 코드
이후, 특정 URL에 접근하여 파일 다운로드를 시도한다. 다만 현재는 연결되지 않는 상태다.
[그림 30] 파일 다운로드 URL
그리고 탈취한 정보를 전송하기 위해 클라우드 서비스를 사용한다. Box, Pcloud, Yandex, Dropbox, Backblazeb2의 API를 사용하는 코드가 존재한다.
[그림 31] 클라우드 API 사용 코드
코드상으로는 5개의 클라우드가 구현되어 있지만 실제 전송에는 Pcloud와 Yandex 두 가지 클라우드가 사용되는 것으로 확인된다. 데이터 전송 시 각 클라우드가 제공하는 API를 활용하며, 특정 토큰 값을 사용해 인증을 수행한다. 사용되는 인증 토큰 정보는 다음 [그림 32]와 같다. 이처럼 OAuth 인증을 활용한 전송 방식은 별도의 로그인 과정 없이 파일 전송이 가능해 AV의 C2 차단을 어렵게 한다.
[그림 32] Pcloud 전송 헤더
[그림 33] Yandex 전송 헤더
요청 헤더의 유저에이전트(UserAgent)는 구글봇(Googlebot)으로 위장했다. 현재는 클라우드 전송 시 모두 인증에 실패하여 행위 발현이 불가능하다.
예방 및 진단 정보
본문에서 설명한 악성코드 감염 과정으로 볼 때, 공격자는 대상을 특정하여 공격 페이로드(Payload)를 구성했다. 감염 시스템 및 사용자에 대한 많은 정보가 유출되기에 추가적인 공격이 가능하다. 추가 파일 다운로드를 시도하는 코드가 존재하나 현재 연결이 불가능하기 때문에 본문에 언급된 내용 외 추가적인 피해가 있었을 것으로 예상된다. 안랩 V3 제품에서는 본 악성코드의 감염 과정에서 사용되는 파일을 아래와 같이 진단 중이다.
파일 진단
Trojan/Script.Inject.S1377
Trojan/Script.Loader
Trojan/BIN.Encoded
관련 IoC
-C2
hxxp://wxx.hanneung.co.kr/admincenter/files/boad/1/p.jpg
hxxps://cloud-api.yandex.net/
(OAuth AQAAAAAzHYxcAAWUROxzKJdWc0DBjRwRIB3dlVE)
hxxps://api.pcloud.com/
(Bearer J0ycZ53OfwT3cURkZSVUDa7ZgrE2Kb72JlJntinTe1eN6LP3d1wy)
-MD5
79c936e6292cf6dad3094c86601dcb84
efd939450ceaca5d399d5e199cadd51e
a2b3de7776ae0b571d49339509f23b86
57f6837d1f338ce2a2b857ce61febb70
e962a9fb77479ad13178efebac1cab33
8ab1c50dfefe48e9f34cf48b0e7891e8a
출처 : AhnLab