메모리 내 악성 프로그램 위협 탐지
현대의 위협은 파일 시스템 아티팩트를 만들지 않고 작동하므로 메모리 분석은 사용자 공간과 커널 공간 모두에서 정교한 멀웨어를 식별하는 데 중요한 역할을 한다.
이러한 정교한 악성 프로그램 구성 요소를 탐지하는 가장 효과적인 방법은 OS 메모리에서 손상 징후를 지속적으로 모니터링하는 에이전트를 보호된 운영 체제에 설치하는 것이다. 그러나 이 접근법에는 여러 가지 단점이 있다. 첫째, 에이전트는 에이전트 프로세스에서 사용되는 리소스(예: CPU, 메모리)와 관련 이벤트(예: API 후킹)를 캡처하는 데 사용되는 계측기로 인해 모니터링되는 OS에 지속적인 오버헤드를 준다. 둘째, 멀웨어 샘플은 에이전트의 존재를 탐지하고 에이전트를 비활성화하거나 탐지를 회피할 수 있다. 셋째, 배포 방식에 따라 에이전트는 사용자 공간 및 커널 공간 메모리의 특정 부분에 액세스할 수 없으며 결과적으로 타협에 대한 중요한 증거를 놓칠 수 있다. 마지막으로, 특히 서로 다른 운영 체제와 아키텍처의 여러 버전이 공존하는 이기종 배포에서는 모든 엔드포인트에 에이전트를 배포, 유지 및 업데이트하는 것이 어려울 수 있다.
이러한 정교한 위협 탐지에 대한 보완적 접근 방식은 특정 시점의 휘발성 메모리 컨텐츠의 스냅샷인 엔드포인트의 메모리 덤프의 오프라인 분석에 의존한다. 대부분의 경우 이러한 유형의 법의학적 분석은 특정 증거를 수집하고 보존해야 할 때 보안 관리자가 수동으로 시작합니다. 이러한 메모리 덤프를 분석하는 프로세스를 메모리 포렌식이라고 한다. 메모리 포렌식은 메모리 덤프에 포함된 비구조적 바이트 스트림에서 의미 있는 데이터를 추출하는 데 초점을 맞춘다. 이는 종종 “시맨틱 갭을 좁히는(closing the semantic gap)” 프로세스라고 한다.
메모리 포렌식은 여러 가지 이유로 오랫동안 어려운 과정으로 여겨져 왔다. 한편으로, 메모리 덤프를 수집하는 간단한 프로세스는 (예를 들어 임베디드 시스템에서) 자기성찰 메커니즘의 부족으로 인해 방해될 수 있다. 한편, 메모리 관리 시스템의 동적 특성은 일관성 없는 메모리 덤프(또는 memory smearing)를 초래하는 레이스 조건을 생성할 수 있습니다.
과거에 많은 애드혹 메모리 포렌식 기술이 제안되었으며, 최근에서야 학술 연구자들이 다양한 기법의 이점과 비용을 강조하는 메모리 포렌식 접근 방식에 대한 체계적인 평가를 제공하였다[1].
기존 메모리 포렌식 기술은 동적 접근법과 정적 접근법의 두 가지 클래스로 대략 나눌 수 있다. 동적 접근 방식은 기본 운영 체제가 실행되는 동안 체내에서 메모리를 분석한다. 이러한 기술은 보안 문제를 적시에 식별할 수 있는 이점을 제공한다. 그러나 성능 비용, 이동 대상 분석의 복잡성 및 불안정성 도입의 위험으로 인해 이러한 기술을 미션 크리티컬 시스템에 적용할 수 없는 경우가 많다.
정적 접근 방식은 특정 시점에 수행되는 시스템의 정적 메모리 덤프에서 작동한다. 이러한 접근 방식은 덤프가 기록되는 간격을 제외하고 시스템의 런타임 작동을 방해하지 않는다. 그러나 덤프가 수집될 때 위협의 증거가 메모리에 있어야 한다. 또한 일련의 이벤트와 관련된 악의적인 행동은 탐지할 수 없을 수 있다 [2].
메모리 포렌식 및 가상화
메모리 획득은 메모리 포렌식 프로세스에서 가장 중요한 단계 중 하나이며, 실행 중인 시스템의 메모리를 획득할 수 있다는 전제를 기반으로 한다. 메모리 수집은 여러 운영 환경에서 어려울 수 있지만 하이퍼바이저가 여러 게스트 운영 체제의 가상 메모리를 추적하고 관리하는 가상화 환경에서는 원활하게 이루어진다.
실제로 대부분의 하이퍼바이저는 게스트 시스템을 나중에 복원할 수 있도록 게스트 상태를 디스크에 저장해야 하는 기능인 게스트 시스템을 일시 중단 및 재시작하기 위한 프로그래밍 방식의 인터페이스를 제공한다.
머신 상태를 디스크에 저장하는 기능은 가상화와 메모리 포렌식 간에 자연스러운 시너지를 창출한다. 경우에 따라 실행을 중단하지 않고도 실행 중인 가상 시스템의 메모리 덤프를 수집할 수도 있다.
예를 들어 VMware의 ESX는 시스템의 전체 상태(예: 해당 가상 디스크, 가상 네트워크 인터페이스 및 가상 메모리)를 포함하는 시스템 스냅샷을 생성하기 위한 메커니즘을 제공한다. 게스트 시스템의 구성은 확장명이 “.vmss”인 파일에 저장되고 게스트 시스템의 메모리는 확장명이 “.vmem”인 별도의 파일에 저장된다.
스냅샷 생성 시 가장 큰 비용은 게스트 시스템의 메모리를 디스크에 쓰는 데 필요한 시간으로, 메모리 설치 공간이 큰 가상 시스템의 경우 상당히 큰 비용이 들 수 있다. VMware 가상화 인프라는 느린(lazy) 스냅샷 메커니즘을 제공하여 게스트 시스템이 상태를 저장하는 동안 실행을 계속할 수 있도록 지원한다. 느린 스냅샷에서는 추적 플래그가 게스트 메모리의 각 페이지에 추가된다. 게스트 시스템을 실행하는 동안 플래그가 있는 페이지에서 쓰기 작업이 수행되면 게스트 시스템이 해당 페이지를 수정하기 전에 해당 페이지가 디스크에 저장된다. 페이지가 디스크에 저장되면 쓰기 추적 플래그가 페이지에서 제거되고 게스트가 페이지를 수정하여 실행을 계속할 수 있다. 이 메커니즘은 메모리 설치 공간이 큰 게스트 시스템의 다운타임을 크게 줄인다.
메모리 아티팩트 분석
가상화된 호스트의 가상 메모리 스냅샷이 수집되면 다음 단계는 메모리 스냅샷을 분석하고 실행 중인 프로세스 목록, 열린 네트워크 연결, 커널에 현재 로드된 드라이버 등 메모리 덤프에 포함된 바이트의 원시 스트림에서 유용한 아티팩트를 추출하는 것이다.
이 “재구성(reconstruction)”은 메모리 분석 도구의 도움을 받아 수행된다. 가장 일반적으로 사용되는 도구 중 하나는 윈도우즈, 리눅스 및 MacOS 운영 체제의 메모리 스냅샷 분석을 지원하는 Volatility Framework [3]다. Volatility3 Framework는 메모리 스냅샷 프로세스 중에 VMware ESX에서 생성된 .vmem 파일을 로드할 수 있으며 메모리 분석을 위해 시스템의 메모리 이미지를 재구성할 수 있다.
Volatility3 Framework는 다음 세 가지 주요 구성 요소를 통해 메모리 포렌식을 지원한다.
- 메모리 계층: 메모리 계층을 사용하면 데이터 저장 방법과 무관한 방식으로 메모리 덤프에서 데이터에 액세스할 수 있다. 메모리 계층은 다양한 테이블 검색 및 데이터 변환을 수행하는 과정에서 메모리 주소를 메모리 덤프의 실제 데이터로 변환하는 다양한 메모리 매핑 알고리즘을 구현한다.
- 템플릿 및 개체: 메모리 포렌식 분석을 수행하려면 운영 체제의 데이터 구조에 액세스해야 한다. 이러한 데이터 구조의 인스턴스를 개체라고 한다. 템플릿에는 데이터에 의해 채워지지 않고 개체 구조에 필요한 모든 정보가 들어 있다. 메모리 분석 시 Template는 특정 오프셋의 메모리 계층에 매핑되어 객체를 구성하며, 이 객체를 메모리의 구조 분석에 사용한다.
- 기호 표: 컴파일 시 컴파일러는 프로그램에 의해 사용되는 데이터 구조와 변수에 대한 메타 정보를 포함할 수 있다(예: Windows의 PDB 파일 또는 Linux의 DWARF 파일 사용). Volatility는 프로그램에서 사용하는 데이터 구조의 템플릿과 특정 데이터 구조의 주소를 모두 포함하는 기호 테이블을 통해 이러한 정보에 대한 통합 액세스를 제공한다.
간단히 말해서 기호 테이블은 템플릿을 생성하는 데 도움이 됩니다. 템플릿은 특정 오프셋의 메모리 계층에 매핑되어 개체를 구성합니다. 메모리 분석 프레임워크는 이러한 객체를 사용하여 메모리에 대한 구조 분석을 수행합니다. 그림 1은 Volatility3 Framework의 메모리 재구성 및 포렌식 분석 프로세스를 보여줍니다.
멀웨어 탐지
OS 데이터 구조와 개체를 식별하면 여러 가지 방법을 사용하여 멀웨어 위협을 탐지할 수 있다. 가장 직접적인 방법은 메모리의 코드나 문자열의 특정 부분과 같은 특정한 Indicators of Compromise(IoC)를 정의하는 서명을 사용하는 것이다. 이러한 서명을 지정하기 위해 가장 많이 사용되는 형식은 YARA 언어[4]다.
YARA 서명은 메모리 덤프에서 식별된 프로세스와 관련된 데이터와 코드 모두에 쉽게 적용할 수 있으며, 보안 커뮤니티는 수년간 광범위한 위협을 위한 방대한 서명 라이브러리를 개발해왔다. YARA를 메모리 포렌식(memory forensics)의 맥락에서 사용하는 주요 이점은 (해당 실행 파일에 코드가 패킹되어 있을 때와 비교하여) 메모리에 있을 때 포장이 풀리고 쉽게 인식된다는 것이다.
보완적 접근 방식은 메모리의 구조적 분석에 기초한다. 이 경우 특정 메모리 구조의 “상태(health)”를 결정하기 위해 몇 가지 휴리스틱이 사용된다. 예를 들어, 일부 루트킷은 존재를 숨기고 탐지를 피하기 위해 다양한 기술을 사용합니다. 루트킷은 커널 모듈의 레지스트리에서 자신을 제거하거나 모니터링 프로세스에서 사용되는 다양한 API에 후크를 추가할 수 있다. OS 개체에 직접 액세스하여 “unaccounted” 구성 요소 또는 프로세스의 기능 주소에 대한 의심스러운 수정을 식별함으로써 메모리 분석을 사용하여 이러한 회피 위협을 식별할 수 있다.
세 번째 접근법은 유사한 메모리 이미지의 비교 분석에 기초한다. 이 경우 동일한 가상화된 운영 체제의 많은 복사본(예: VDI 배포에서 실행되는 복사본)이 동일한 원본 이미지에서 모두 “복제(cloned)”되기 때문에 내부 구조가 매우 비슷하다고 가정한다. 따라서 인스턴스를 비교하고 고유하고 비정상적인 메모리 구조를 가진 “검은 양(black sheep)” 인스턴스를 식별함으로써 손상된 호스트를 식별할 수 있다 [5]. 그러나 이 접근 방식은 단일 시스템을 가정하고 메모리 내 데이터 구조를 비교하기 위해 길고 다소 복잡한 설정이 필요하므로 여기서 더 이상 논의되지 않을 것이다.
예
메모리 내 파일-리스(file-less) 공격은 대부분의 보안 솔루션에 의한 탐지를 회피하고 파일 시스템 아티팩트의 분석을 기반으로 한 포렌식 분석 노력을 좌절시키는 일종의 스텔스 공격이다.
예를 들어 Netwalker 파일리스 랜섬웨어 [6]은 “반사 DLL 로딩(reflective DLL loading)”이라고도 하는 동적 링크 라이브러리(DLL) 주입 기법을 사용한다. 이 기술을 사용하면 디스크가 아닌 메모리에서 DLL을 주입할 수 있다. 이 기술은 실제 DLL 파일이 디스크에 필요하지 않은 것 외에도 윈도우즈 로더를 호출하지 않기 때문에 일반 DLL 주입보다 은밀하다. 이렇게 하면 프로세스의 로드 모듈로 DLL을 등록할 필요가 없어지고 DLL 로드 모니터링 도구가 사라진다.
다음에서는 해시 f4656a9af30e98ed2103194f798fa00fd1686618e3e62fba6b15c9959135b7be를 사용한 특정 샘플의 분석을 제시한다. 샘플의 실행은 PowerShell 스크립트로 시작한다. 이 스크립트는 여러 암호화, 난독화 및 인코딩 계층 아래에 랜섬웨어 DLL을 숨긴다. 이 스크립트는 DLL을 추출하고 합법적인 explorer.exe 인스턴스의 메모리에 DLL을 주입한다.
이 경우 Netwalker 감염 후 ESX를 사용하여 가상 시스템 스냅샷을 수집했다. Volatility3에는 악성 프로그램 분석에 유용한 플러그인이 많이 있다. MalFind라고 불리는 플러그인 중 하나는 모든 프로세스를 검색하고 잠재적으로 주입된 코드를 포함하는 읽기, 쓰기 및 실행 권한으로 모든 메모리 범위를 나열합니다. 그림 2는 감염된 메모리 스냅샷에 적용될 때의 MalFind 플러그인의 출력을 보여준다. 출력에는 잠재적으로 주입된 코드가 포함된 모든 메모리 범위와 관련된 프로세스 이름 및 ID가 나열됩니다.
MalFind 플러그인의 덤프 옵션을 사용하여 나열된 모든 잠재적 주입 코드를 별도의 파일로 덤프했습니다. 그런 다음 YARA 서명 일치를 수행하여 덤프된 파일에 PE 파일이 있는지 확인했습니다. 그 결과 탐색기.exe 덤프 파일에서 PE 파일이 탐지되었습니다. 읽기, 쓰기 및 실행 권한이 있는 메모리 섹션의 PE 파일은 매우 의심스러우며 더 많은 조사가 필요합니다. 위협을 추가로 식별하기 위해 YARA 서명 일치가 전체 explayer.exe 프로세스 메모리에 적용됩니다. YARA 서명은 그림 3과 같이 프로세스 주소 공간에서 발견된 문자열을 기반으로 주입된 코드를 Netwalker 랜섬웨어 모듈의 인스턴스로 성공적으로 식별한다.
메모리 분석은 패턴 일치를 통한 위협 식별에만 국한되지 않는다. 예를 들어, 탐지 회피에 적극적으로 사용되는 기술인 API 후크를 사용하는 위협을 생각해 보자. API 후크는 OS 환경을 모니터링하는 데 사용되는 기능의 호출을 가로채고 API가 반환하는 데이터를 변경할 수 있다. 멀웨어 위협은 Process Explorer (procexp), ProcessHacker, Windows Task Manager 등 널리 사용되는 모니터링 응용 프로그램을 방지하기 위해 API 후킹을 사용하는 경우가 많아 멀웨어 구성 요소의 존재를 표시하지 않는다.
예를 들어, Thanos 랜섬웨어 [7]에서는 ProcessHide라는 도구를 사용해서 감염된 컴퓨터에서 해당 존재를 숨긴다. ProcessHide는 모니터링 응용 프로그램 프로세스의 프로세스 ID와 숨길 프로세스 이름을 매개 변수로 사용한다. ProcessHide는 NtQuerySystemInformation API 호출을 후크하여 모니터링 응용 프로그램에 의해 나열되지 않도록 프로세스를 숨긴다.
메모리 포렌식 분석을 사용하여 이 위협을 감지하고 식별하는 방법을 시연하기 위해 ESXi 호스팅된 가상 시스템에서 해시 58bfb9fa888950d13fff42473956dc2a7ec4f3abb18fd3faeaaaa38089d513c171f를 사용하여 Thanos 랜섬웨어 샘플을 실행했다. 그림 4와 같이 프로세스해커는 악성 프로그램 프로세스 “58bfb9fa88895.exe”를 쉽게 나열할 수 있다.
그런 다음 악성 프로그램이 프로세스로부터 도구 존재 여부를 숨기기 위한 도구 ProcessHide를 사용합니다. 성공적으로 ProcessHide가 실행되어, 멀웨어 프로세스를 숨기면 그림 5와 같이 멀웨어가 더 이상 프로세스에 표시되지 않는다.
그런 다음 프로세스가 숨겨져 있는 감염된 가상 시스템이 스냅샷이 생성되고 메모리 분석을 위해 Volatility3에 메모리 파일이 로드된다. Volatility3은 메모리 이미지를 재구성하고 기호 테이블 및 템플릿을 사용하여 OS 개체를 생성한다. 특히 Volatility3는 시스템에서 실행되는 모든 프로세스를 나열할 수 있는 PsList라는 플러그인을 제공한다. 플러그인은 먼저 커널 메모리 이미지에서 PsActiveProcess를 찾는다. 이 포인터를 EPROCESS 구조 목록을 가리킨다. EPROCESS 구조는 프로세스 객체의 커널 표현이다. EPROCESS 구조에는 LIST_ENTRY 구조가 포함되어 실행 중인 모든 프로세스의 링크된 목록을 작성한다. 플러그인은 링크된 목록을 통과하고 시스템에서 실행 중인 모든 프로세스를 나열한다.
플러그인은 OS 포인터와 커널 개체에 직접 액세스하여 프로세스 목록을 생성하므로 그림 6과 같이 숨겨진 멀웨어 프로세스 “58bfb9fa88895.exe”가 나열됩니다.
API 훅을 감지하기 위해 Volatility3용 간단한 플러그인을 개발했다. 이 플러그인은 가져오기(import) 테이블을 분석하여 프로세스의 후크 함수를 탐지할 수 있다. 플러그인은 먼저 프로세스에 의해 로드된 모든 DLL을 나열하고 기본 주소와 각 DLL의 크기를 기록한다. 그런 다음 플러그인은 프로세스 이진 이미지의 가져오기 테이블을 분석한다. 각 가져오기 테이블 항목과 Import Address Table (IAT) 항목이 확인된다. IAT에는 DLL의 가져온 함수의 주소가 포함되어 있다. IAT의 유효한 함수 주소는 가져온 DLL 메모리 범위 내의 메모리 위치를 가리켜야 한다. 플러그인이 DLL의 메모리 범위를 벗어나는 메모리 위치를 가리키는 함수 주소를 찾으면 해당 함수 주소가 후크 포인터로 표시된다. 플러그인은 후크 코드의 처음 몇 바이트를 추출하여 추가 분석을 위해 분해한다. 그림 7은 ProcessHacker.exe 프로세스에 적용될 때의 플러그인의 출력을 보여준다. 플러그인은 가져온 모든 기능과 IAT에 저장된 해당 주소를 나열합니다. NtQuerySystemInformation의 주소가 ntdll.dll 메모리 범위를 벗어나는 위치(0x191664a0000)를 가리키므로 플러그인은 NtQuerySystemInformation의 후크를 감지한다.
그림 8과 같이 플러그인은 추가 분석을 위해 전체 후크 모듈을 추출할 수도 있다. 후크 모듈은 프록시 역할을 하며 응용 프로그램을 대신하여 NtQuerySystemInformation 함수를 호출한다. NtQuerySystemInformation을 실행한 후 컨트롤이 후크 모듈로 돌아갑니다. 후크 모듈은 NtQuerySystemInformation에서 반환한 프로세스 목록에서 숨기도록 요청된 프로세스를 제거합니다. 숨길 프로세스 이름은 후크 모듈의 끝에 저장됩니다. 플러그인은 그림 8과 같이 숨겨진 프로세스 이름인 “58bfb9fa88895.exe”도 추출한다.
맺음말
정교한 악성 프로그램 위협에는 효율적인 탐지를 위해 서로 다른 접근 방식의 보완적 세트가 필요하다. 맬웨어 분석가의 작업대에서 핵심 도구는 메모리 포렌식을 사용하는 것이다. 데이터 센터 구축이 가상화를 점점 더 많이 활용함에 따라 하이퍼바이저에서 제공하는 메모리 스냅샷 기능과 보안 커뮤니티에서 개발한 고급 메모리 분석 툴을 결합하여 정교한 악성 프로그램 위협을 탐지하고 분석할 수 있는 고유한 기회가 있다.