요약
사이버 범죄자들은 취약한 합법적인 드라이버를 악용하거나 엔드포인트 탐지 및 대응(EDR) 시스템을 비활성화하고 탐지 또는 예방 기능을 회피하기 위해 맞춤형 드라이버를 사용하는 등 자체 드라이버를 사용하는 경우가 점점 더 많아지고 있습니다.
Elastic Security Labs는 HEARTCRYPT가 포함된로더를 사용하여 금전적 동기를 가진 캠페인이 MEDUSA 랜섬웨어를 배포하는 것을 모니터링했습니다. 이 로더는 중국 공급업체의 해지된 인증서 서명 드라이버와 함께 배포되었으며, 이 드라이버는 피해 시스템에 설치한 다음 다른 EDR 공급업체를 표적으로 삼아 무력화시키는 데 사용됩니다. 이 EDR 킬러 드라이버는 최근 다른 캠페인에서 다른 인증서와 IO 제어 코드를 사용하여 ConnectWise에 의해 보고되었으며, 당시에는 그 기능 중 일부가 논의되었습니다. 2022년 구글 클라우드 맨디언트는 이 악성 드라이버에 대한 최초의 언급으로 추정되는 POORTRY라는 악성 드라이버를 공개했습니다.
이 글에서는 이 드라이버의 다양한 기능과 기술을 살펴보면서 이 드라이버를 자세히 살펴봅니다. 또한 각 리버스 코드 스크린샷 아래에 상대 가상 주소(RVA)를 제공하여 연구와 참조 샘플을 연결하고, 이 멀웨어를 추가로 실험하는 데 사용할 수 있는 작은 클라이언트 예제를 제공합니다.
기술적 분석
PE 헤더
이 바이너리는 smuol.sys
이라는 이름의 64비트 Windows PE 드라이버이며, 합법적인 CrowdStrike Falcon 드라이버를 모방합니다.
분석 당시 VirusTotal에서 2024-08-08 에서 2025-02-24 까지 12개의 샘플을 발견했습니다. 대부분 VMProtect가 적용되었지만 아래 관찰 가능한 표에 언급된 두 개는 보호되지 않았습니다.
모든 샘플은 중국 회사에서 도난당해 해지된 것으로 보이는 인증서를 사용하여 서명합니다. 이러한 인증서는 여러 멀웨어 샘플과 캠페인에서 널리 알려져 있고 공유되지만 이 드라이버에만 국한된 것은 아닙니다. 인증서 지문은 아래에 나열되어 있습니다:
fingerprint | 이름 |
---|---|
51 68 1b 3c 9e 66 5d d0 b2 9e 25 71 46 d5 39 dc | 불산 가오밍 케데유 단열재 유한 공사 |
7f 67 15 0f bb 0d 25 4e 47 42 84 c7 f7 81 9c 4f | 페이 샤오 |
72 88 1f 10 cd 24 8a 33 e6 12 43 a9 e1 50 ec 1d | 푸저우 딩신 무역 유한공사 |
75 e8 e7 b9 04 3b 13 df 60 e7 64 99 66 30 21 c1 | 창사 헝샹 정보 기술 유한공사 |
03 93 47 e6 1d ec 6f 63 98 d4 d4 6b f7 32 65 6c | 신장 이실련 네트워크 기술 유한공사 |
4e fa 7e 7b ba 65 ec 1a b7 74 f2 b3 13 57 d5 99 | 심천 윤디안 기술 유한공사 |
난독화
어비스워커는 불투명한 술어와 기타 파생 함수의 조합에 의존하여 항상 동일한 값을 반환하는 함수를 사용합니다. 예를 들어, 아래의 영 리턴 함수는 하드코딩된 파생값을 기반으로 항상 0
을 반환합니다.
아래는 파생 함수 중 하나입니다:
이러한 상수 반환 함수는 바이너리 전체에서 반복적으로 호출되어 정적 분석을 방해합니다. 그러나 이러한 함수는 세 개뿐이며 술어에 사용되지 않고 단순히 호출됩니다. 쉽게 식별할 수 있으므로 비효율적인 난독화 방식입니다.
초기화
초기화 시 드라이버는 다음 섹션에서 설명할 여러 커널 모듈과 클라이언트 보호 기능에 대한 포인터를 가져오는 것으로 시작합니다.
그런 다음 \\device\\czx9umpTReqbOOKF
경로와 다음과 같은 심볼릭 링크가 있는 장치를 만듭니다. \\??\\fqg0Et4KlNt4s1JT
.
주요 함수에 대한 콜백을 등록하여 초기화를 완료합니다.
디바이스 개봉 시 클라이언트 보호
드라이버 장치가 열리면 IRP_MJ_CREATE
메이저 콜백이 호출됩니다. 이 함수는 보호할 프로세스 목록에 프로세스 ID를 추가하고 실행 중인 프로세스 목록에서 대상 프로세스에 대한 기존 핸들을 모두 제거합니다.
이 함수는 디바이스가 열릴 때 커널 콜백이 클라이언트 프로세스의 컨텍스트에서 실행되므로 현재 커널 스레드에서 프로세스 ID를 검색합니다.
프로세스 ID를 보호 목록에 추가하기 전에 ABYSSWORKER는 실행 중인 다른 프로세스에서 클라이언트 프로세스에 대한 기존 핸들을 검색하여 제거합니다.
이를 위해 멀웨어는 API에 의존하지 않기 위해 프로세스 ID(PID)를 무차별 대입하여 기존 프로세스를 반복합니다. 각 프로세스에 대해 무차별 대입을 사용하여 핸들을 반복하고 기본 객체가 클라이언트 프로세스에 해당하는지 확인합니다. 일치하는 항목이 발견되면 매개 변수로 전달된 값을 사용하여 액세스 권한을 제거합니다(0x8bb
).
마지막으로 보호된 프로세스의 글로벌 목록에 PID를 추가합니다.
앞서 언급했듯이 드라이버는 초기화 단계에서 보호 기능을 설정합니다. 이 보호는 ObRegisterCallback
API를 사용하여 두 개의 pre-operation
콜백을 등록하는 데 의존합니다. 하나는 보호된 프로세스에 대한 핸들 열림을 감지하고 다른 하나는 보호된 프로세스의 스레드에 대한 핸들 열림을 감지하는 것입니다.
두 콜백은 동일한 방식으로 작동하며, 핸들에 대한 원하는 액세스 권한을 0으로 설정하여 핸들 생성을 효과적으로 거부합니다.
DeviceIoControl 핸들러
디바이스 I/O 제어 요청을 받으면 ABYSSWORKER는 I/O 제어 코드에 따라 핸들러에게 요청을 전송합니다. 이러한 핸들러는 파일 조작부터 프로세스 및 드라이버 종료에 이르기까지 광범위한 작업을 다루며, EDR 시스템을 종료하거나 영구적으로 비활성화하는 데 사용할 수 있는 포괄적인 툴셋을 제공합니다.
아래 표에서 다양한 IO 컨트롤에 대해 자세히 설명합니다:
이름 | 코드 |
---|---|
멀웨어 사용 | 0x222080 |
파일 복사 | 0x222184 |
모듈 이름으로 콜백 및 장치 제거 | 0x222400 |
드라이버 주요 기능을 모듈 이름으로 바꾸기 | 0x222404 |
모듈 이름으로 시스템 스레드 종료 | 0x222408 |
미니 필터 장치 분리 | 0x222440 |
파일 삭제 | 0x222180 |
멀웨어 비활성화 | 0x222084 |
API 로드 | 0x2220c0 |
모든 드라이버 참조 카운터 줄이기 | 0x222100 |
모든 디바이스 참조 카운터 줄이기 | 0x222104 |
프로세스 종료 | 0x222144 |
스레드 종료 | 0x222140 |
Ntfs 및 Pnp 드라이버의 주요 기능에서 후크 제거하기 | 0x222444 |
재부팅 | 0x222664 |
악성코드 활성화(0x222080)
이 블로그 게시물에서 설명한 대로 클라이언트는 드라이버에 비밀번호(7N6bCAoECbItsUR5-h4Rp2nkQxybfKb0F-wgbJGHGh20pWUuN1-ZxfXdiOYps6HTp0X
)를 전송하여 드라이버를 활성화해야 하며, 저희의 경우 0x222080
IO 제어를 통해 활성화합니다.
핸들러는 사용자 입력과 하드코딩된 비밀번호를 비교하기만 하면 됩니다. 맞으면 글로벌 플래그를 참(1)으로 설정합니다. 이 플래그는 다른 모든 핸들러에서 실행을 허용하거나 거부하기 위해 체크됩니다.
API 로드 중(0x2220c0)
멀웨어의 대부분의 핸들러는 이 핸들러를 사용하여 로드해야 하는 커널 API에 의존합니다. 이 핸들러는 초기화 중에 이전에 로드된 커널 모듈 포인터를 사용하여 여러 구조체와 함께 이러한 전역 변수를 로드합니다. 로딩이 완료되면 글로벌 플래그가 설정되어 이러한 API를 사용할 수 있음을 알립니다.
이 핸들러에는 전체 모드와 부분 모드의 두 가지 작동 모드가 있습니다. 전체 모드에서는 사용자가 IO 제어에 입력으로 제공한 함수 이름과 RVA의 매핑 구조를 사용하여 API를 로드합니다. 부분 모드에서는 일부 API를 자체적으로 검색하지만 전체 모드에서 로드되는 모든 API를 로드하지는 않으므로 부분 모드라고 합니다. 사용자가 이 매핑 구조를 제공할 수 없어 부분 모드를 선택하면 일부 핸들러가 실행되지 않습니다. 이 장에서는 전체 작동 모드에 대해서만 설명합니다.
아래에서 사용된 구조에 대해 자세히 설명합니다:
#define AM_NAME_LENGTH 256typedef struct _struct_435{uint64_t rva;char name[AM_NAME_LENGTH];} struct_435_t;#define AM_ARRAY_LENGTH 1024typedef struct _struct_433{struct_435_t array[AM_ARRAY_LENGTH];uint32_t length;} struct_433_t;
아래에서 간단한 사용 예시를 제공합니다:
struct_433_t api_mapping = {.length = 25,.array = {[0] = {.rva = 0xcec620, .name = "PspLoadImageNotifyRoutine"},[1] = {.rva = 0xcec220, .name = "PspCreateThreadNotifyRoutine"},[2] = {.rva = 0xcec420, .name = "PspCreateProcessNotifyRoutine"},// (...)[24] = {.rva = 0x250060, .name = "NtfsFsdShutdown"},}};uint32_t malware_load_api(HANDLE device){return send_ioctrl(device, IOCTRL_LOAD_API, &api_mapping, sizeof(struct_433_t), NULL, 0);}
API를 로드하기 위해 함수는 서로 다른 커널 객체 유형에서 세 개의 '콜백 목록'을 로드하는 것으로 시작합니다. 특정 모듈에 속한 등록된 알림 콜백을 제거하는 핸들러에서 사용됩니다.
그런 다음 함수 이름을 검색하고 모듈의 기본 주소에 관련 RVA를 추가하기만 하면 제공된 구조를 사용하여 함수에 대한 포인터를 로드합니다.
이는 다음 25 함수에 대해 수행됩니다:
PspLoadImageNotifyRoutine
PspCreateThreadNotifyRoutine
PspCreateProcessNotifyRoutine
CallbackListHead
PspSetCreateProcessNotifyRoutine
PspTerminateThreadByPointer
PsTerminateProcess
IopInvalidDeviceRequest
ClassGlobalDispatch
NtfsFsdRead
NtfsFsdWrite
NtfsFsdLockControl
NtfsFsdDirectoryControl
NtfsFsdClose
NtfsFsdCleanup
NtfsFsdCreate
NtfsFsdDispatchWait
NtfsFsdDispatchSwitch
NtfsFsdDispatch
NtfsFsdFlushBuffers
NtfsFsdDeviceControl
NtfsFsdFileSystemControl
NtfsFsdSetInformation
NtfsFsdPnp
NtfsFsdShutdown
파일 복사 및 삭제(0x222184, 0x222180)
파일을 복사하거나 삭제하기 위해 ABYSSWORKER는 새롭지는 않지만 여전히 흥미로운 전략을 사용합니다. NtCreateFile
와 같은 일반적인 API를 사용하는 대신 처음부터 IRP(I/O 요청 패킷)를 생성하여 대상 파일이 포함된 해당 드라이브 장치로 직접 전송합니다.
파일 만들기
파일 생성 기능은 이 메커니즘이 어떻게 작동하는지 보여주기 위해 사용됩니다. 이 기능은 파일 경로에서 드라이브 장치를 가져오는 것으로 시작됩니다. 그런 다음 새 파일 개체가 생성되고 대상 드라이브 장치에 연결되어 새 개체가 드라이브에 올바르게 연결되었는지 확인합니다.
그런 다음 새 IRP 개체를 만들고 파일 생성 작업을 수행하는 데 필요한 모든 데이터를 설정합니다. 이 IRP가 대상으로 하는 주요 기능은 MajorFunction
속성에 지정되며, 이 경우 파일 생성 시 예상대로 IRP_MJ_CREATE
으로 설정되어 있습니다.
그런 다음 멀웨어가 IRP를 대상 드라이브 장치로 보냅니다. IoCallDriver
API를 사용할 수도 있었지만, 대신 해당 디바이스의 주요 기능을 호출하여 IRP를 수동으로 전송합니다.
이 시점에서 파일 개체는 나중에 사용할 수 있습니다. 핸들러는 파일 객체의 참조 카운터를 증가시키고 나중에 사용할 수 있도록 출력 매개변수에 할당하는 것으로 작업을 완료합니다.
파일 복사하기
파일을 복사하려면 ABYSSWORKER가 소스 파일과 대상 파일을 모두 연 다음 소스에서 읽기(IRP_MJ_READ
)를 하고 대상에 쓰기(IRP_MJ_WRITE
)를 합니다.
파일 삭제하기
삭제 처리기는 파일 속성을 ATTRIBUTE_NORMAL
로 설정하여 읽기 전용 파일의 보호를 해제하고 파일 처리를 삭제(disposition_info.DeleteFile = 1
)로 설정하여 IRP_MJ_SET_INFORMATION
IRP를 사용하여 파일을 제거합니다.
모듈 이름별 알림 콜백 제거(0x222400)
멀웨어 클라이언트는 이 핸들러를 사용하여 EDR 제품과 해당 제품의 가시성을 숨길 수 있습니다. 등록된 모든 알림 콜백을 검색하여 제거합니다. 대상 콜백은 다음 API에 등록된 콜백입니다:
PsSetCreateProcessNotifyRoutine
PsSetLoadImageNotifyRoutine
PsSetCreateThreadNotifyRoutine
ObRegisterCallbacks
CmRegisterCallback
또한 미니필터 드라이버를 통해 등록된 콜백을 제거하고, 선택적으로 특정 모듈에 속한 장치를 제거합니다.
이러한 알림 콜백을 삭제하기 위해 핸들러는 ObRegisterCallbacks
및 CmRegisterCallback
에 등록된 콜백을 포함하는 로딩 API 핸들러에 이전에 로드된 3개의 글로벌 콜백 목록과 같은 다양한 방법을 사용하여 해당 콜백을 찾습니다. 그런 다음 해당 API(예: ObUnRegisterCallbacks
및 CmUnRegisterCallbacks
.
이러한 방법을 사용하는 블라인드 EDR은 그 자체로 블로그 포스팅을 할 가치가 있습니다. 이 포스팅을 간결하게 유지하기 위해 여기서는 자세한 내용은 제공하지 않겠지만, 이러한 기법을 구현하는 잘 문서화된 두 개의 프로젝트에서 이러한 방법을 살펴보시기 바랍니다:
드라이버 주요 기능을 모듈 이름으로 바꾸기 0x222404
드라이버를 방해하는 또 다른 방법은 이 핸들러를 사용하여 모든 주요 기능을 더미 함수로 대체하여 대상 모듈 이름이 지정된 드라이버와의 모든 상호 작용을 비활성화하는 것입니다.
이를 위해 ABYSSWORKER는 Driver
및 Filesystem
객체 디렉터리에 있는 드라이버 객체를 반복합니다. 각 드라이버 객체에 대해 기본 모듈 이름과 대상 모듈을 비교하고 일치하는 경우 모든 주요 함수를 IopInvalidDeviceRequest
.
미니 필터 장치 분리(0x222440)
이 핸들러는 Driver
및 FileSystem
객체 디렉터리에 있는 모든 드라이버 객체를 반복합니다. 각 드라이버에 대해 장치 트리를 탐색하고 미니 필터 드라이버와 연결된 모든 장치를 분리합니다: FltMgr.sys
.
이 함수는 AttachedDevice
및 NextDevice
포인터를 통해 드라이버의 장치를 반복하고 각 장치의 연결된 드라이버의 모듈 이름을 검색한 다음 매개 변수로 전달된 대상 모듈 이름(”FltMgr.sys”
)과 비교하는 방식으로 작동합니다. 이름이 일치하면 IoDetachDevice
함수를 사용하여 장치 연결을 해제합니다.
모듈 이름으로 시스템 스레드 종료(0x222408)
이 핸들러는 스레드 ID를 무차별 대입하여 스레드를 반복하고 스레드가 시스템 스레드이고 시작 주소가 대상 모듈에 속하는 경우 스레드를 종료합니다.
스레드를 종료하기 위해 멀웨어는 APC(비동기 프로시저 호출)를 대기열에 추가하여 표적 스레드의 컨텍스트에서 코드를 실행합니다. 이 코드가 실행되면 다음 코드를 차례로 호출합니다. PsTerminateSystemThread
.
프로세스 종료 및 스레드 종료(0x222144, 0x222140)
이 두 핸들러를 사용하면 PsTerminateProcess
를 사용하여 프로세스 또는 스레드의 PID 또는 스레드 ID(TID)로 프로세스 또는 스레드를 종료할 수 있습니다. PsTerminateThread
.
Ntfs 및 Pnp 드라이버의 주요 기능에서 후크 제거(0x222444)
일부 EDR은 알림 콜백을 등록하는 것 외에도 NTFS
및 PNP
드라이버의 주요 기능을 연결하기도 합니다. 이러한 후크를 제거하기 위해 멀웨어는 이 드라이버를 호출하여 해당 드라이버의 원래 주요 기능을 복원할 수 있습니다.
어비스워커는 등록된 각 주요 함수를 반복하여 해당 함수가 드라이버 모듈에 속하는지 확인하고, 그렇지 않은 경우 해당 함수가 후킹된 것을 의미하므로 원래 함수로 대체합니다.
재부팅 0x222664
이 핸들러는 머신을 재부팅하기 위해 문서화되지 않은 함수를 사용합니다. HalReturnToFirmware
.
클라이언트 구현 예제
이 블로그 게시물에서는 소규모 클라이언트 구현 예제를 제공합니다. 이 예제는 참조 샘플과 함께 작동하며 디버깅에 사용되었지만 드라이버의 모든 IOCTRL을 구현하지는 않으며 향후 업데이트될 가능성이 높지 않습니다.
그러나 여기에는 이를 활성화하고 API를 로드하는 모든 기능이 포함되어 있으므로 의욕이 있는 독자는 이 문서의 정보를 사용하여 이 멀웨어를 확장하고 추가 실험을 할 수 있기를 바랍니다.
프로젝트의 리포지토리는 여기에서 확인할 수 있습니다.
멀웨어 및 MITRE ATT&CK
Elastic은 위협이 엔터프라이즈 네트워크에 대해 사용하는 일반적인 전술, 기술 및 절차를 문서화하기 위해 MITRE ATT& CK 프레임워크를 사용합니다.
전술
기술
기술은 공격자가 행동을 수행하여 전술적 목표를 달성하는 방법을 나타냅니다.
완화
YARA
Elastic Security는 이 게시물과 관련된 다음과 같은 YARA 규칙을 만들었습니다:
관찰
이 연구에서는 다음과 같은 관찰 가능성에 대해 논의했습니다:
관측 가능합니다. | 유형 | 참조 | 날짜 |
---|---|---|---|
6a2a0f9c56ee9bf7b62e1d4e1929d13046cd78a93d8c607fe4728cc5b1e8d050 | SHA256 | ABYSSWORKER 참조 샘플 | VT 처음 보기: 2025-01-22 |
b7703a59c39a0d2f7ef6422945aaeaaf061431af0533557246397551b8eed505 | SHA256 | ABYSSWORKER 샘플 | VT 처음 보기: 2025-01-27 |
참고 자료
- 구글 클라우드 맨디언트, 맨디언트 인텔리전스. 나는 엄숙히 맹세컨대 내 드라이버가 나쁜 짓을 하고 있지 않습니다: 증명 서명된 멀웨어 찾기. https://cloud.google.com/blog/topics/threat-intelligence/hunting-attestation-signed-malware/
- 유닛42, 제롬 투재그, 다니엘 번스. 암호화된 하트: 하트크립트 서비스형 패커 운영 공개, 12월 13, 2024. https://unit42.paloaltonetworks.com/packer-as-a-service-heartcrypt-malware/
- ConnectWise, 블레이크 이킨. "공격자가 사회 공학 공격을 위해 Microsoft 팀 기본값 및 빠른 지원을 활용하는 방법", 1월 31 2025. https://www.linkedin.com/pulse/attackers-leveraging-microsoft-teams-defaults-quick-assist-p1u5c/
- 웨이브스톤-CDT, 8월 30, 2024. https://github.com/wavestone-cdt/EDRSandblast/tree/master
- myzxcg, 5월 24, 2024. https://github.com/myzxcg/RealBlindingEDR