Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
EDRSandblast — 취약한 서명된 드라이버를 무기화하여 EDR 커널 콜백, 오브젝트 콜백, ETW TI 공급자 및 사용자 공간 훅을 우회하고 LSASS 메모리 덤프 및 자격 증명 추출을 수행합니다. | Kitploit
도구/GitHubGitHub/wavestone-cdt/edrsandblast
Defensive ToolsPrivilege EscalationExploitationPenetration TestingRed Teaming
GitHubwavestone-cdt/edrsandblast

EDRSandblast

취약한 서명된 드라이버를 무기화하여 EDR 커널 콜백, 오브젝트 콜백, ETW TI 공급자 및 사용자 공간 훅을 우회하고 LSASS 메모리 덤프 및 자격 증명 추출을 수행합니다.

저장소 보기
1.8k3202년 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

EDRSandBlast

EDRSandBlast는 서명된 취약한 드라이버를 무기화하여 EDR 탐지(Notify Routine 콜백, Object Callbacks 및 ETW TI 공급자) 및 LSASS 보호를 우회하기 위해 C로 작성된 도구입니다. 여러 사용자 모드 언후킹 기술도 구현되어 사용자 모드 모니터링을 회피합니다.

이번 릴리즈 기준으로, 사용자 모드(--usermode)와 커널 모드(--kernelmode) 기술의 조합을 사용하여 EDR 감시 하에 LSASS 메모리를 덤프했으며, 제품(클라우드) 콘솔에서 차단되거나 "OS 자격 증명 덤핑" 관련 이벤트가 생성되지 않았습니다. 테스트는 3개의 서로 다른 EDR 제품에서 수행되었으며 각 경우에 성공했습니다.

설명

커널 Notify Routines 제거를 통한 EDR 우회

EDR 제품은 Windows에서 커널 "Notify Routines" 콜백을 사용하여 프로세스 및 스레드 생성, 이미지(exe/DLL) 로딩과 같은 시스템 활동을 커널로부터 통지받습니다.

이러한 커널 콜백은 일반적으로 콜백을 구현하는 드라이버가 커널 영역에서 문서화된 API(nt!PsSetCreateProcessNotifyRoutine, nt!PsSetCreateThreadNotifyRoutine 등)를 사용하여 정의됩니다. 이러한 API는 드라이버가 제공하는 콜백 루틴을 커널 공간의 문서화되지 않은 루틴 배열에 추가합니다:

  • 프로세스 생성을 위한 PspCreateProcessNotifyRoutine
  • 스레드 생성을 위한 PspCreateThreadNotifyRoutine
  • 이미지 로딩을 위한 PspLoadImageNotifyRoutine

EDRSandBlast는 이러한 배열에 정의된 루틴을 열거하고 미리 정의된 EDR 드라이버 목록(1000개 이상의 보안 제품 드라이버 지원, EDR 드라이버 탐지 섹션 참조)에 연결된 모든 콜백 루틴을 제거합니다. 열거 및 제거는 취약한 드라이버의 악용( 취약한 드라이버 섹션 참조)을 통해 제공되는 임의의 커널 메모리 읽기/쓰기 프리미티브를 통해 가능해집니다.

앞서 언급한 배열의 오프셋은 여러 기술을 사용하여 복구됩니다. 자세한 내용은 오프셋 섹션을 참조하세요.

Object Callbacks 제거를 통한 EDR 우회

EDR(및 EPP) 제품은 종종 nt!ObRegisterCallbacks 커널 API를 사용하여 "Object callbacks"를 등록합니다. 이러한 콜백을 통해 보안 제품은 특정 객체 유형(프로세스, 스레드 및 데스크톱 관련 객체 콜백이 현재 Windows에서 지원됨)에 대한 핸들이 생성될 때마다 통지를 받을 수 있습니다. 핸들 생성은 객체 열기(OpenProcess, OpenThread 호출 등) 및 핸들 복제(DuplicateHandle 호출 등) 시 발생할 수 있습니다.

커널이 이러한 각 작업을 통지함으로써 보안 제품은 핸들 생성의 정당성을 분석하고(예: 알 수 없는 프로세스가 LSASS를 열려고 함) 위협이 감지되면 차단할 수도 있습니다.

ObRegisterCallbacks를 사용하여 콜백을 등록할 때마다 콜백의 영향을 받는 객체 유형(프로세스, 스레드 또는 데스크톱)을 설명하는 _OBJECT_TYPE 객체에 존재하는 이중 연결 리스트 CallbackList에 새 항목이 추가됩니다. 불행히도 이러한 항목은 Microsoft에서 문서화하거나 기호 파일에 게시하지 않은 구조체로 설명됩니다. 그러나 여러 ntoskrnl.exe 버전에서 연구한 결과, 이 구조체는 (최소) Windows 10 빌드 10240과 22000(2015년부터 2022년까지) 사이에서 변경되지 않은 것으로 보입니다.

언급된 객체 콜백 등록을 나타내는 구조체는 다음과 같습니다:```C typedef struct OB_CALLBACK_ENTRY_t { LIST_ENTRY CallbackList; // linked element tied to _OBJECT_TYPE.CallbackList OB_OPERATION Operations; // bitfield : 1 for Creations, 2 for Duplications BOOL Enabled; // self-explanatory OB_CALLBACK* Entry; // points to the structure in which it is included POBJECT_TYPE ObjectType; // points to the object type affected by the callback POB_PRE_OPERATION_CALLBACK PreOperation; // callback function called before each handle operation POB_POST_OPERATION_CALLBACK PostOperation; // callback function called after each handle operation KSPIN_LOCK Lock; // lock object used for synchronization } OB_CALLBACK_ENTRY;

root@kitploit:~
위에서 언급한 `OB_CALLBACK` 구조체는 문서화되지 않았으며, 다음과 같이 정의됩니다:```C
typedef struct OB_CALLBACK_t {
    USHORT Version;                           // usually 0x100
    USHORT OperationRegistrationCount;        // number of registered callbacks
    PVOID RegistrationContext;                // arbitrary data passed at registration time
    UNICODE_STRING AltitudeString;            // used to determine callbacks order
    struct OB_CALLBACK_ENTRY_t EntryItems[1]; // array of OperationRegistrationCount items
    WCHAR AltitudeBuffer[1];                  // is AltitudeString.MaximumLength bytes long, and pointed by AltitudeString.Buffer
} OB_CALLBACK;

In order to disable EDR-registered object callbacks, three techniques are implemented in EDRSandblast; however only one is enabled for the moment.

Using the Enabled field of OB_CALLBACK_ENTRY

This is the default technique enabled in EDRSandblast. In order to detect and disable EDR-related object callbacks, the CallbackList list located in the _OBJECT_TYPE objects tied to the Process and Thread types is browsed. Both _OBJECT_TYPEs are pointed by public global symbols in the kernel, PsProcessType and PsThreadType.

Each item of the list is assumed to fit the OB_CALLBACK_ENTRY structure described above (assumption that seems to hold at least in all Windows 10 builds at the time of writing). Functions defined in PreOperation and PostOperation fields are located to checks if they belong to an EDR driver, and if so, callbacks are simply disabled toggling the Enabled flag.

While being a pretty safe technique, it has the inconvenient of relying on an undocumented structure; to reduce the risk of unsafe manipulation of this structure, basic checks are performed to validate that some fields have the expected values :

  • Enabled is either TRUE or FALSE (don't laugh, a BOOL is an int, so it could be anything other than 1 or 0);
  • Operations is OB_OPERATION_HANDLE_CREATE, OB_OPERATION_HANDLE_DUPLICATE or both;
  • ObjectType points on PsProcessType or PsThreadType.

Unlinking the CallbackList of threads and process

Another strategy that do not rely on an undocumented structure (and is thus theoretically more robust against NT kernel changes) is the unlinking of the whole CallbackList for both processes and threads. The _OBJECT_TYPE object is the following:```C struct _OBJECT_TYPE { LIST_ENTRY TypeList; UNICODE_STRING Name; [...] _OBJECT_TYPE_INITIALIZER TypeInfo; [...] LIST_ENTRY CallbackList; }

root@kitploit:~
`Flink` 및 `Blink` 포인터가 `CallbackList`의 `LIST_ENTRY`가 `LIST_ENTRY` 자체를 가리키도록 만들면 리스트가 사실상 비어 있게 됩니다. `_OBJECT_TYPE` 구조체는 커널 심볼에 공개되어 있으므로 이 기법은 하드코딩된 오프셋/구조체에 의존하지 않습니다. 그러나 몇 가지 단점이 있습니다.

첫째, EDR의 콜백만 비활성화할 수 있는 것이 아니라, "정상적인" 소프트웨어에 의해 등록되었을 수 있는 모든 객체 콜백에 영향을 미친다는 점입니다. 그럼에도 불구하고 Windows 10에서는 (현재 작성 시점 기준) 객체 콜백이 사전 설치된 어떤 구성 요소에서도 사용되지 않으므로, 이를 비활성화해도 시스템 안정성에 영향을 미치지 않아야 합니다(일시적으로만 비활성화하는 경우 더욱 그렇습니다).

두 번째 단점은 프로세스 또는 스레드 핸들 작업이 OS의 정상적인 기능에서 매우 빈번하다는 점(거의 지속적)입니다. 따라서 사용된 커널 쓰기 기본 연산이 "원자적으로" `QWORD` 쓰기를 수행할 수 없는 경우, `_OBJECT_TYPE.CallbackList.Flink` 포인터가 덮어쓰기 도중에 커널에 의해 접근될 가능성이 높습니다. 예를 들어, MSI 취약 드라이버 `RTCore64.sys`는 한 번에 `DWORD` 쓰기만 수행할 수 있으므로 포인터를 덮어쓰기 위해 두 개의 개별 IOCTL이 필요하며, 그 사이에 커널이 이를 사용할 확률이 높습니다(결과적으로 충돌). 반면, 취약한 DELL 드라이버 `DBUtil_2_3.sys`는 하나의 IOCTL에서 임의 크기의 쓰기를 수행할 수 있으므로 이 방법을 사용해도 충돌 위험이 없습니다.

#### 객체 콜백 완전 비활성화
우리가 발견한 마지막 기법 중 하나는 스레드 및 프로세스에 대한 객체 콜백 지원을 완전히 비활성화하는 것입니다. 프로세스 및 스레드 유형에 해당하는 `_OBJECT_TYPE` 구조체 내부에는 문서화된 `_OBJECT_TYPE_INITIALIZER` 구조체를 따르는 `TypeInfo` 필드가 있습니다. 후자에는 `ObjectTypeFlags` 비트 필드가 포함되어 있으며, 그 중 `SupportsObjectCallbacks` 플래그는 설명된 객체 유형(Process, Thread, Desktop, Token, File 등)이 객체 콜백 등록을 지원하는지 여부를 결정합니다. 앞서 언급했듯이, 현재 작성 시점의 Windows 설치에서는 Process, Thread 및 Desktop 객체 유형만 이러한 콜백을 지원합니다.

`SupportsObjectCallbacks` 비트는 `ObpCreateHandle` 또는 `ObDuplicateObject`가 `CallbackList`를 읽기 전(물론 콜백을 실행하기 전)에 검사하므로, 커널 런타임에 해당 비트를 플립하면 모든 객체 콜백 실행이 사실상 비활성화됩니다.

이 방법의 주요 단점은 *KPP*("*PatchGuard*")가 일부(전부?) `_OBJECT_TYPE` 구조체의 무결성을 모니터링하고, 매개변수 4가 `0x8`인 [`0x109 Bug Check`](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/bug-check-0x109---critical-structure-corruption)를 트리거한다는 것입니다. 이는 객체 유형 구조체가 변경되었음을 의미합니다.

그러나 비활성화/재활성화(및 그 사이의 "악의적인" 작업)를 충분히 빠르게 수행하면 *PatchGuard*를 "추월"할 수 있어야 합니다(주기적 검사가 잘못된 시점에 수행되는 불운이 없는 경우).

### 미니필터 콜백 연결 해제를 통한 EDR 우회
Windows 필터 관리자 시스템을 사용하면 EDR이 "미니필터" 드라이버를 로드하고 콜백을 등록하여 파일 열기, 읽기, 쓰기 등 I/O 작업에 대한 알림을 받을 수 있습니다.

필터 관리자에서 사용하는 다양한 내부 구조체에 대한 간단한 요약은 다음과 같습니다.
- 필터 관리자는 "프레임" (`_FLTP_FRAME`)을 루트 구조체로 설정합니다.
- 필터 관리자가 관리하는 각 "디스크"에 대해 "볼륨" 구조체 (`_FLT_VOLUME`)가 인스턴스화됩니다(파티션, 섀도 복사본, 또는 명명된 파이프나 원격 파일 시스템에 해당하는 특수 볼륨 포함).
- 등록된 각 미니필터 드라이버에는 지원되는 작업과 같은 다양한 속성을 설명하는 "필터" 구조체 (`_FLT_FILTER`)가 대응됩니다.
- 이러한 미니필터가 각 볼륨에 모두 연결되는 것은 아닙니다. 각각의 filter<->volume 연결을 표시하기 위해 "인스턴스" (`_FLT_INSTANCE`) 구조체가 생성됩니다.
- 미니필터는 특정 작업(파일 열기, 쓰기, 읽기 등) 전후에 실행될 콜백 함수를 등록합니다. 이러한 콜백은 `_CALLBACK_NODE` 구조체로 설명되며, 다양한 방법으로 접근할 수 있습니다.
  - 미니필터 인스턴스가 구현한 모든 `_CALLBACK_NODE`의 배열은 `_FLT_INSTANCE` 구조체에서 찾을 수 있습니다. 이 배열은 콜백이 처리하는 작업을 나타내는 상수인 IRP "주 함수" 코드(`IRP_MJ_CREATE`, `IRP_MJ_READ` 등)로 인덱싱됩니다.
  - 또한 특정 볼륨에 연결된 인스턴스가 구현한 모든 `_CALLBACK_NODE`는 IRP 주 함수 코드로 인덱싱된 `_FLT_VOLUME.Callbacks.OperationLists` 배열에 저장된 연결 리스트로 그룹화됩니다.

이러한 다양한 구조체는 `EDRSandblast`에 의해 탐색되어 EDR 관련 드라이버와 연결된 필터를 감지하고, 모니터링 기능을 포함하는 콜백 노드가 열거됩니다. 이들의 효과를 비활성화하기 위해 노드는 해당 리스트에서 연결 해제되어 필터 관리자에서 일시적으로 보이지 않게 됩니다.

이렇게 하면 지정된 기간 동안 EDR이 파일 작업을 완전히 인식하지 못할 수 있습니다. 기본적인 예로 lsass 메모리 덤프 파일을 디스크에 생성하는 경우 EDR의 분석을 전혀 트리거하지 않으므로 파일 자체에 기반한 탐지도 이루어지지 않습니다.

### ETW Microsoft-Windows-Threat-Intelligence 공급자 비활성화를 통한 EDR 우회

`ETW Microsoft-Windows-Threat-Intelligence` 공급자는 일반적으로 악의적으로 사용되는 일부 Windows API 사용에 대한 데이터를 기록합니다. 여기에는 `nt!NtReadVirtualMemory`(LSASS 메모리 덤프에 사용됨)에 의해 호출되는 `nt!MiReadWriteVirtualMemory` API가 포함되며, `nt!EtwTiLogReadWriteVm` 함수에 의해 모니터링됩니다.

EDR 제품은 각각 `SERVICE_LAUNCH_PROTECTED_ANTIMALWARE_LIGHT` 또는 `PS_PROTECTED_ANTIMALWARE_LIGHT`로 실행되는 서비스 또는 프로세스를 통해 `ETW TI` 공급자가 생성한 로그를 소비할 수 있으며, `Early Launch Anti Malware (ELAM)` 드라이버와 연결됩니다.

[`slaeryan`이 `CNO Development Labs` 블로그 게시물](https://public.cnotools.studio/bring-your-own-vulnerable-kernel-driver-byovkd/exploits/data-only-attack-neutralizing-etwti-provider)에서 공개한 바와 같이, `ETW TI` 공급자는 커널 메모리에서 해당 `ProviderEnableInfo` 속성을 `0x0`으로 패치하여 완전히 비활성화할 수 있습니다. 자세한 내용은 위의 훌륭한 블로그 게시물을 참조하십시오.

커널 콜백 제거와 유사하게, 필요한 `ntoskrnl.exe` 오프셋(`nt!EtwThreatIntProvRegHandleOffset`, `_ETW_REG_ENTRY`의 `GuidEntry`, `_ETW_GUID_ENTRY`의 `ProviderEnableInfo`)은 다양한 Windows 커널 버전에 대해 `NtoskrnlOffsets.csv` 파일에서 계산됩니다.

### 사용자 영역 후킹 우회를 통한 EDR 우회
#### 사용자 영역 후킹 작동 방식
프로세스에 의해 수행되는 작업을 쉽게 모니터링하기 위해 EDR 제품은 종종 *사용자 영역 후킹*이라는 메커니즘을 배포합니다. 먼저, EDR 제품은 각 프로세스 시작 시 알림을 받을 수 있는 커널 콜백(일반적으로 *이미지 로딩* 또는 *프로세스 생성* 콜백, 위 참조)을 등록합니다.

Windows가 프로세스를 로드하고 실제로 시작되기 전에 EDR은 모니터링 로직이 포함된 사용자 지정 DLL을 프로세스 주소 공간에 주입할 수 있습니다. 로드되는 동안 이 DLL은 EDR이 모니터링할 모든 함수의 시작 부분에 "*후크*"를 주입합니다. 런타임 시 감시 중인 프로세스에 의해 모니터링되는 함수가 호출되면 이러한 후크는 제어 흐름을 EDR DLL에 있는 일부 감독 코드로 리디렉션하여 호출의 인수와 반환 값을 검사할 수 있도록 합니다.

대부분의 경우 모니터링되는 함수는 `ntdll.dll`에 구현이 있는 시스템 호출(예: `NtReadVirtualMemory`, `NtOpenProcess` 등)입니다. `Nt*` 함수에 대한 호출을 가로채면 제품이 사용자 영역/커널 영역 경계에 최대한 가까이 접근할 수 있지만(사용자 영역에 머무르면서), 일부 상위 수준 DLL의 함수도 모니터링될 수 있습니다.

아래는 동일한 함수가 EDR 제품에 의해 후킹되기 전과 후의 예시입니다.```assembly
NtProtectVirtualMemory   proc near
	mov r10, rcx
	mov eax, 50h
	test byte ptr ds:7FFE0308h, 1
	jnz short loc_18009D1E5
	syscall
	retn
loc_18009D1E5:
	int 2Eh
	retn
NtProtectVirtualMemory   endp			

입력:```assembly NtProtectVirtualMemory proc near jmp sub_7FFC74490298 ; --> "hook", jump to EDR analysis function int 3 ; overwritten instructions int 3 ; overwritten instructions int 3 ; overwritten instructions test byte_7FFE0308, 1 ; <-- execution resumes here after analysis jnz short loc_7FFCB44AD1E5 syscall retn loc_7FFCB44AD1E5: int 2Eh retn NtProtectVirtualMemory endp

root@kitploit:~
#### Hook 감지
사용자 공간 후크는 사용자 공간 메모리에 위치한다는 "약점"이 있습니다. 즉, 검사 대상 프로세스가 직접 관찰하고 수정할 수 있습니다. 프로세스 주소 공간에서 후크를 자동으로 감지하기 위한 주요 아이디어는 디스크의 원본 DLL과 메모리에 있는 (EDR에 의해 잠재적으로 변경된) 라이브러리 간의 차이점을 비교하는 것입니다. 이 비교를 수행하기 위해 EDRSandblast는 다음 단계를 따릅니다:
* 로드된 모든 DLL 목록은 `PEB` 내의 `InLoadOrderModuleList`를 통해 열거됩니다 (모니터링되거나 의심스러운 API 호출을 피하기 위해)
* 각 로드된 DLL에 대해, 디스크의 내용을 읽고 헤더를 구문 분석합니다. 메모리에 있는 해당 라이브러리도 구문 분석하여 섹션, 익스포트 등을 식별합니다.
* DLL의 재배치(relocations)를 구문 분석하고 적용하며, 해당 로드된 라이브러리의 기본 주소를 고려합니다. 이를 통해 메모리 내 라이브러리와 디스크에서 가져온 DLL의 내용이 (재배치가 적용된 섹션에서) 정확히 동일해지고, 따라서 비교가 신뢰할 수 있게 됩니다.
* 익스포트된 함수를 열거하고 "메모리 내" 버전과 "디스크 상" 버전의 첫 번째 바이트를 비교합니다. 차이가 있으면 DLL이 로드된 후에 변경이 발생했음을 나타내며, 이는 거의 확실히 EDR 후크입니다.

참고: 이 과정은 쓰기 불가능한 섹션의 아무 곳에서나 차이점을 찾도록 일반화할 수 있으며, 익스포트 함수의 시작 부분에만 국한되지 않습니다. 예를 들어 EDR 제품이 함수 중간에 후크를 적용하기 시작하는 경우에도 가능합니다 :) 따라서 도구에서 사용되지는 않지만, `findDiffsInNonWritableSections`에 구현되어 있습니다.


이러한 후크가 수행하는 모니터링을 우회하기 위해 여러 가지 기술이 가능하며, 각각 장단점이 있습니다.

#### 후크 우회: 언후킹(unhooking) 사용
후크 기반 모니터링을 우회하는 가장 직관적인 방법은 후크를 제거하는 것입니다. 후크는 프로세스 자체가 접근 가능한 메모리에 존재하므로, 후크를 제거하기 위해 프로세스는 다음을 수행할 수 있습니다:
* 후크가 위치한 페이지의 권한 변경 (RX -> RWX 또는 RW)
* 디스크 DLL 내용을 통해 알려진 원본 바이트 쓰기
* 권한을 다시 RX로 변경

이 접근 방식은 매우 간단하며, 감지된 모든 후크를 한 번에 제거하는 데 사용할 수 있습니다. 공격 도구가 시작 시 이를 수행하면, 나머지 코드는 후킹 메커니즘을 전혀 인식하지 못하고 모니터링 없이 정상적으로 작동할 수 있습니다.

그러나 두 가지 주요 단점이 있습니다. EDR은 아마도 `NtProtectVirtualMemory` 사용을 모니터링할 것이므로, 이를 사용하여 후크가 설치된 페이지의 권한을 변경하는 것은 (적어도 개념상) 좋지 않은 생각입니다. 또한, EDR이 스레드를 실행하여 주기적으로 후크의 무결성을 확인하는 경우, 이 또한 탐지를 유발할 수 있습니다.

구현 세부 사항은 `unhook_method`가 `UNHOOK_WITH_NTPROTECTVIRTUALMEMORY`일 때 `unhook()` 함수의 코드 경로를 확인하세요.

**중요 참고: 단순함을 위해 이 기술은 EDRSandblast에서 다른 우회 기술을 *시연*하는 기본 기술로 구현되었습니다; 각 기술은 모니터링되지 않는 버전의 `NtProtectVirtualMemory`를 획득하는 방법을 보여주지만, 이후에는 동일한 작업(특정 후크 언후킹)을 수행합니다.**

#### 사용자 정의 트램펄린을 사용한 후크 우회
특정 후크를 우회하려면 단순히 "뛰어넘어" 함수의 나머지 부분을 그대로 실행하는 것이 가능합니다. 먼저, EDR이 후크를 설치하기 위해 덮어쓴 모니터링 대상 함수의 원본 바이트를 DLL 파일에서 복구해야 합니다. 이전 코드 예제에서는 이는 다음 명령어에 해당하는 바이트가 될 것입니다:```assembly
mov r10, rcx
mov eax, 50h

이 바이트들을 식별하는 것은 간단한 작업입니다. 앞서 설명한 대로 메모리와 디스크 버전의 라이브러리를 깔끔하게 diff 비교할 수 있기 때문입니다. 그런 다음, 후크 직후의 코드로 제어 흐름을 리디렉션하도록 설계된 점프 명령어를 NtProtectVirtualMemory + sizeof(overwritten_instructions) 주소에 어셈블합니다.```assembly jmp NtProtectVirtualMemory+8

root@kitploit:~
마지막으로, 이러한 opcode들을 연결하여 (새로) 실행 가능한 메모리에 저장하고 포인터를 유지합니다. 이 객체는 "*trampoline*"이라고 불리며, 원래의 `NtProtectVirtualMemory` 함수와 완전히 동일한 함수 포인터로 사용될 수 있습니다.

이 기술의 주요 이점은 아래의 모든 기술과 마찬가지로, 훅이 절대 지워지지 않는다는 점입니다. 따라서 EDR이 수행하는 모든 무결성 검사를 통과해야 합니다. 그러나 쓰기 가능한 메모리를 할당한 후 실행 가능한 메모리로 만들어야 하며, 이는 일반적인 셸코드 할당 방식으로 EDR의 감시를 받게 됩니다.

구현 세부 사항은 `unhook()` 함수의 코드 경로에서 `unhook_method`가 `UNHOOK_WITH_INHOUSE_NTPROTECTVIRTUALMEMORY_TRAMPOLINE`인 경우를 확인하세요. 이 기술은 우리 구현에서만 시연되며, 결국 아래의 모든 기술과 마찬가지로 메모리에서 훅을 **제거**하는 데 사용됩니다.

#### EDR의 자체 트램펄린을 사용한 훅 우회
EDR 제품이 훅을 작동시키려면 제거한 opcode를 메모리 어딘가에 저장해야 합니다. 최악(*또는 "더 나은", 공격자 관점에서*), 원래 명령어를 효과적으로 사용하기 위해 EDR은 호출을 가로챈 후 원래 함수를 실행할 수 있도록 자체적으로 *trampoline*을 할당했을 가능성이 높습니다.

이 트램펄린을 검색하여 훅된 함수의 대체로 사용할 수 있으며, 실행 가능한 메모리를 할당하거나 `VirtualQuery` 외의 API를 호출할 필요가 없습니다. `VirtualQuery`는 무해한 함수이므로 모니터링되지 않을 가능성이 높습니다.

메모리에서 트램펄린을 찾기 위해 `VirtualQuery`를 사용하여 전체 주소 공간을 탐색하며, 커밋되고 실행 가능한 메모리를 찾습니다. 이러한 각 메모리 영역에 대해, 덮어쓰여진 명령어 다음 주소(이전 예제에서는 `NtProtectVirtualMemory+8`)를 대상으로 하는 점프 명령어를 찾기 위해 스캔합니다. 그런 다음 이 트램펄린을 사용하여 훅을 트리거하지 않고 훅된 함수를 호출할 수 있습니다.

이 기술은 테스트된 EDR에서 거의 모든 트램펄린을 복구할 수 있을 정도로 놀랍게 잘 작동합니다. 구현 세부 사항은 `unhook()` 함수의 코드 경로에서 `unhook_method`가 `UNHOOK_WITH_EDR_NTPROTECTVIRTUALMEMORY_TRAMPOLINE`인 경우를 확인하세요.

#### 중복 DLL을 사용한 훅 우회
`NtProtectVirtualMemory` 함수의 모니터링되지 않는 버전에 접근하는 또 다른 간단한 방법은 프로세스 주소 공간에 `ntdll.dll` 라이브러리의 중복 버전을 로드하는 것입니다. 이름이 다르면 두 개의 동일한 DLL을 동일한 프로세스에 로드할 수 있으므로, 합법적인 `ntdll.dll` 파일을 다른 위치에 복사하고 `LoadLibrary`를 사용하여 로드하거나 로드 프로세스를 재구현한 다음, 예를 들어 `GetProcAddress`를 사용하여 함수에 접근할 수 있습니다.

이 기술은 이해하고 구현하기가 매우 간단하며, 성공 가능성이 높습니다. 대부분의 EDR 제품은 프로세스가 실행 중일 때 새로 로드된 DLL에 훅을 다시 설치하지 않기 때문입니다. 그러나 주요 단점은 Microsoft 서명된 바이너리를 다른 이름으로 복사하는 것이 EDR 제품 자체에서 종종 의심스러운 행동으로 간주된다는 점입니다.

그러나 이 기술은 `EDRSandblast`에 구현되어 있습니다. 구현 세부 사항은 `unhook()` 함수의 코드 경로에서 `unhook_method`가 `UNHOOK_WITH_DUPLICATE_NTPROTECTVIRTUALMEMORY`인 경우를 확인하세요.

#### 직접 시스템 콜을 사용한 훅 우회
시스템 호출 관련 함수를 사용하기 위해, 프로그램은 시스템 콜을 (어셈블리로) 재구현하여 EDR에 의해 모니터링될 수 있는 `ntdll.dll`의 코드를 실제로 건드리지 않고 해당 OS 기능을 호출할 수 있습니다. 이는 `ntdll.dll` 내 시스템 콜 함수에 대해 수행된 모든 사용자 후킹을 완전히 우회합니다.

그러나 여기에는 몇 가지 단점이 있습니다. 첫째, 프로그램이 필요로 하는 함수들의 시스템 콜 번호 목록을 알아야 한다는 점인데, 이는 Windows의 각 버전마다 다릅니다. 그러나 이는 Windows NT의 모든 과거 버전에서 작동하는 것으로 알려진 여러 휴리스틱을 구현하고(예: `ntdll`의 `Zw*` 내보내기 정렬, 관련 `ntdll` 함수에서 `mov rax, #syscall_number` 명령어 검색 등), 모두 동일한 결과를 반환하는지 확인함으로써 완화됩니다(자세한 내용은 `Syscalls.c` 참조).

또한 기술적으로 시스템 콜이 아닌 함수(예: `LoadLibraryX`/`LdrLoadDLL`)도 모니터링될 수 있으며, 시스템 콜로 간단히 재구현할 수 없습니다.

직접 시스템 콜 기술은 EDRSandblast에 구현되어 있습니다. 앞서 언급했듯이, 이는 `NtProtectVirtualMemory`를 안전하게 실행하고 감지된 모든 훅을 제거하는 데만 사용됩니다.

구현 세부 사항은 `unhook()` 함수의 코드 경로에서 `unhook_method`가 `UNHOOK_WITH_DIRECT_SYSCALL`인 경우를 확인하세요.

### 취약한 드라이버 악용
앞서 언급했듯이, 커널 메모리 읽기나 쓰기가 필요한 모든 작업은 이 프리미티브를 제공하는 취약한 드라이버에 의존합니다. EDRSandblast에서는 읽기/쓰기 프리미티브를 제공하는 새 드라이버에 대한 지원을 "쉽게" 추가할 수 있으며, 세 가지 함수만 구현하면 됩니다:
* `ReadMemoryPrimitive_DRIVERNAME(SIZE_T Size, DWORD64 Address, PVOID Buffer)` 함수: `Size` 바이트를 커널 주소 `Address`에서 사용자 공간 버퍼 `Buffer`로 복사합니다.
* `WriteMemoryPrimitive_DRIVERNAME(SIZE_T Size, DWORD64 Address, PVOID Buffer)` 함수: `Size` 바이트를 사용자 공간 버퍼 `Buffer`에서 커널 주소 `Address`로 복사합니다.
* `CloseDriverHandle_DRIVERNAME()`: 드라이버에 대한 모든 핸들이 닫혔는지 확인합니다(드라이버 제거 작업 전에 필요하며, 현재 드라이버에 관계없이 수행됨).

예를 들어, 현재 EDRSandblast는 두 개의 드라이버를 지원합니다: `RTCore64.sys` (SHA256: `01AA278B07B58DC46C84BD0B1B5C8E9EE4E62EA0BF7A695862444AF32E87F1FD`) 및 `DBUtils_2_3.sys` (SHA256: `0296e2ce999e67c76352613a718e11516fe1b0efc3ffdb8918fc999dd76a73a5`). 사용 중인 취약한 드라이버를 변경하거나 새로운 드라이버를 구현해야 하는 경우 `KernelMemoryPrimitives.h`의 다음 코드를 업데이트해야 합니다.```C
#define RTCore 0
#define DBUtil 1
// Select the driver to use with the following #define
#define VULN_DRIVER RTCore

#if VULN_DRIVER == RTCore
#define DEFAULT_DRIVER_FILE TEXT("RTCore64.sys")
#define CloseDriverHandle CloseDriverHandle_RTCore
#define ReadMemoryPrimitive ReadMemoryPrimitive_RTCore
#define WriteMemoryPrimitive WriteMemoryPrimitive_RTCore
#elif VULN_DRIVER == DBUtil
#define DEFAULT_DRIVER_FILE TEXT("DBUtil_2_3.sys")
#define CloseDriverHandle CloseDriverHandle_DBUtil
#define ReadMemoryPrimitive ReadMemoryPrimitive_DBUtil
#define WriteMemoryPrimitive WriteMemoryPrimitive_DBUtil
#endif

EDR 드라이버 및 프로세스 탐지

특정 드라이버나 프로세스가 EDR 제품에 속하는지 여부를 판단하기 위해 현재 여러 기법이 사용됩니다.

첫째, 드라이버 이름을 단순히 그 목적으로 사용할 수 있습니다. 실제로 Microsoft는 커널에 콜백을 삽입해야 하는 모든 드라이버에 대해 "고도(Altitude)"라는 특정 번호를 할당합니다. 이는 콜백 실행 순서를 등록 순서와 관계없이 드라이버 사용에 기반한 결정론적 순서로 만듭니다. 특정 고도를 예약한 드라이버(및 해당 공급업체) 목록은 MSDN에서 확인할 수 있습니다. 결과적으로 Microsoft는 보안 제품과 연결된 보안 드라이버 이름의 거의 포괄적인 목록을 제공하며, 주로 "FSFilter Anti-Virus" 및 "FSFilter Activity Monitor" 목록에 포함됩니다. 이러한 드라이버 이름 목록은 EDRSandblast에 내장되어 있으며, 추가 기여 사항도 포함되어 있습니다.

또한 EDR 실행 파일과 DLL은 공급업체의 서명 인증서를 사용하여 디지털 서명되는 경우가 많습니다. 따라서 프로세스와 연결된 실행 파일 또는 DLL의 서명자를 확인하면 EDR 제품을 신속하게 식별할 수 있습니다.

또한 드라이버는 커널 공간에 로드되려면 Microsoft에서 직접 서명해야 합니다. 드라이버의 공급업체가 드라이버 자체의 직접적인 서명자는 아니지만, 공급업체 이름이 서명의 속성 내에 여전히 포함되어 있는 것으로 보입니다; 그럼에도 불구하고 이 탐지 기법은 아직 조사 및 구현되지 않았습니다.

마지막으로, EDRSandblast에 알려지지 않은 EDR에 직면했을 때 가장 좋은 방법은 도구를 "감사(audit)" 모드로 실행하고 커널 콜백을 등록한 드라이버 목록을 확인한 다음, 드라이버 이름을 목록에 추가하고 도구를 다시 컴파일하여 재실행하는 것입니다.

RunAsPPL 우회

Windows 8.1 및 Windows Server 2012 R2에서 처음 도입된 Local Security Authority (LSA) Protection 메커니즘은 Protected Process Light (PPL) 기술을 활용하여 LSASS 프로세스에 대한 액세스를 제한합니다. PPL 보호는 SeDebugPrivilege 권한을 가진 프로세스에서도 보호된 프로세스에 대한 메모리 주입이나 메모리 덤프와 같은 작업을 규제하고 제한합니다. 프로세스 보호 모델에서는 더 높은 보호 수준으로 실행되는 프로세스만 보호된 프로세스에 대해 작업을 수행할 수 있습니다.

Windows 커널이 커널 메모리에서 프로세스를 표현하는 데 사용하는 _EPROCESS 구조체는 Type (_PS_PROTECTED_TYPE) 및 Signer (_PS_PROTECTED_SIGNER) 속성을 통해 프로세스의 보호 수준을 정의하는 _PS_PROTECTION 필드를 포함합니다.

커널 메모리에 쓰기를 통해 EDRSandblast 프로세스는 자체 보호 수준을 PsProtectedSignerWinTcb-Light로 승격할 수 있습니다. 이 수준은 RunAsPPL 메커니즘으로 실행되는 LSASS 프로세스의 보호 수준인 PsProtectedSignerLsa-Light를 "지배"하므로 LSASS 프로세스 메모리를 덤프하기에 충분합니다.

EDRSandBlast는 다음과 같이 자체 보호를 구현합니다:

  • 현재 프로세스에 대한 핸들을 엽니다.
  • NtQuerySystemInformation을 사용하여 모든 시스템 핸들을 유출하여 현재 프로세스에 열린 핸들과 커널 메모리 내 현재 프로세스의 EPROCESS 구조체 주소를 찾습니다.
  • 취약한 드라이버의 임의 읽기/쓰기 취약점을 사용하여 커널 메모리에서 현재 프로세스의 _PS_PROTECTION 필드를 덮어씁니다. _PS_PROTECTION 필드의 EPROCESS 구조체에 대한 오프셋(사용 중인 ntoskrnl 버전에 의해 정의됨)은 NtoskrnlOffsets.csv 파일에 계산되어 있습니다.

Credential Guard 우회

Microsoft Credential Guard는 Microsoft Windows 10 (Enterprise edition)에서 도입된 가상화 기반 격리 기술로, LSASS 프로세스에 저장된 자격 증명에 대한 직접 액세스를 방지합니다.

Credentials Guard가 활성화되면 Virtual Secure Mode에 LSAIso (LSA Isolated) 프로세스가 생성됩니다. 이 기능은 CPU의 가상화 확장을 활용하여 메모리 내 데이터에 추가 보안을 제공합니다. LSAIso 프로세스에 대한 액세스는 NT AUTHORITY\SYSTEM 보안 컨텍스트에서도 제한됩니다. 해시를 처리할 때 LSA 프로세스는 RPC 호출을 LSAIso 프로세스에 수행하고 계속 진행하기 위해 LSAIso 결과를 기다립니다. 따라서 LSASS 프로세스에는 비밀이 포함되지 않으며 대신 LSA Isolated Data가 저장됩니다.

N4kedTurtle이 수행한 원래 연구에 명시된 바와 같이: "Wdigest는 메모리에서 g_fParameter_useLogonCredential 및 g_IsCredGuardEnabled 값을 패치하여 Credential Guard가 있는 시스템에서 활성화할 수 있습니다." Wdigest 활성화는 새 대화형 로그온(시스템 재부팅 없이)에 대해 LSASS 메모리에 일반 텍스트 자격 증명이 저장되도록 합니다. 이 기법에 대한 자세한 내용은 원본 연구 블로그 게시물을 참조하십시오.

EDRSandBlast는 원본 PoC를 opsec 친화적으로 약간 개선하고 여러 wdigest.dll 버전(g_fParameter_useLogonCredential 및 g_IsCredGuardEnabled에 대한 계산된 오프셋을 통해)을 지원합니다.

오프셋 검색

커널 모니터링 우회 작업을 안정적으로 수행하기 위해 EDRSandblast는 커널 메모리를 읽고 쓸 정확한 위치를 알아야 합니다. 이는 대상 이미지(ntoskrnl.exe, wdigest.dll) 내의 전역 변수 오프셋과 Microsoft가 기호 파일에 정의를 게시한 구조체의 특정 필드 오프셋을 사용하여 수행됩니다. 이러한 오프셋은 대상 이미지의 각 빌드에 고유하며 특정 플랫폼 버전에 대해 최소 한 번은 수집되어야 합니다.

EDRSandblast가 사용하는 구조체와 변수를 찾기 위해 패턴 검색 대신 "하드코딩된" 오프셋을 사용하기로 한 선택은, 커널 콜백 추가/제거를 담당하는 문서화되지 않은 API가 변경될 수 있으며, 잘못된 주소에서 커널 메모리를 읽거나 쓰려는 시도는 Bug Check (Blue Screen of Death)를 초래할 수 있다는 사실에 의해 정당화됩니다. 시스템 충돌은 레드팀 및 일반 침투 테스트 시나리오 모두에서 허용되지 않습니다. 충돌하는 시스템은 방어자에게 매우 가시적이며, 공격 시점에 메모리에 있던 모든 자격 증명이 손실되기 때문입니다.

각 특정 Windows 버전에 대한 오프셋을 검색하기 위해 두 가지 접근 방식이 구현됩니다.

수동 오프셋 검색

필요한 ntoskrnl.exe 및 wdigest.dll 오프셋은 제공된 ExtractOffsets.py Python 스크립트를 사용하여 추출할 수 있습니다. 이 스크립트는 radare2 및 r2pipe에 의존하여 PDB 파일에서 기호를 다운로드 및 구문 분석하고 필요한 오프셋을 추출합니다. 오프셋은 나중에 EDRSandblast에서 사용할 수 있도록 CSV 파일에 저장됩니다.

다양한 Windows 빌드를 즉시 지원하기 위해 Winbindex에서 참조하는 여러 버전의 ntoskrnl.exe 및 wdigest.dll 바이너리를 ExtractOffsets.py로 자동으로 다운로드(및 오프셋 추출)할 수 있습니다. 이를 통해 Windows 업데이트 패키지에 게시된 거의 모든 파일에서 오프셋을 추출할 수 있습니다(현재까지 450개 이상의 ntoskrnl.exe 및 30개 이상의 wdigest.dll 버전을 사용할 수 있으며 미리 계산되어 있습니다).

자동 오프셋 검색 및 업데이트

EDRSandBlast에 추가 옵션이 구현되어 프로그램이 Microsoft Symbol Server에서 필요한 .pdb 파일을 직접 다운로드하고, 필요한 오프셋을 추출하며, 해당하는 .csv 파일이 있으면 업데이트할 수 있습니다.

--internet 옵션을 사용하면 도구 실행이 훨씬 간단해지지만, 추가적인 OpSec 위험이 발생합니다. 프로세스 중에 .pdb 파일이 다운로드되어 디스크에 저장되기 때문입니다. 이는 기호 데이터베이스를 구문 분석하는 데 사용되는 dbghelp.dll 함수에 필요합니다. 그러나 향후 메모리 내 PDB 구문 분석을 완전히 구현하여 이 요구 사항을 제거하고 도구의 공격 표면을 줄일 수 있습니다.

사용법

취약한 드라이버

EDRSandblast는 최소 3개의 취약한 드라이버인 gdrv.sys (기본값), RTCore64.sys 및 DBUtil_2_3.sys에 대한 지원을 공개적으로 구현합니다. 실제 사용되는 드라이버는 도구 컴파일 전에 결정됩니다 (includes/KernelMemoryPrimitive.h의 #define VULN_DRIVER <driver name> 참조). 취약한 드라이버의 사본을 다운로드하여 EDRSandblast에 제공해야 커널 작업이 작동합니다.

테스트된 드라이버의 해시는 EDRSanblast에서 사용하는 커널 메모리 읽기 및 쓰기 기본 요소를 구현하는 각 Driver<name>.c 파일의 시작 부분에 명시되어 있습니다. 이러한 해시를 사용하여 드라이버 샘플은 인터넷, 특히 https://www.loldrivers.io에서 쉽게 찾을 수 있습니다.

지원되는 취약한 드라이버 목록과 다운로드 링크는 다음과 같습니다:

빠른 사용법```

Usage: EDRSandblast.exe [-h | --help] [-v | --verbose] <audit | dump | cmd | credguard | firewall | load_unsigned_driver> [--usermode] [--unhook-method ] [--direct-syscalls] [--add-dll ]* [--kernelmode] [--dont-unload-driver] [--no-restore] [--nt-offsets <NtoskrnlOffsets.csv>] [--fltmgr-offsets <FltmgrOffsets.csv>] [--wdigest-offsets <WdigestOffsets.csv>] [--ci-offsets <CiOffsets.csv>] [--internet] [--vuln-driver <RTCore64.sys>] [--vuln-service <SERVICE_NAME>] [--unsigned-driver <evil.sys>] [--unsigned-service <SERVICE_NAME>] [--no-kdp] [-o | --dump-output <DUMP_FILE>]

root@kitploit:~
### 옵션```
-h | --help             Show this help message and exit.
-v | --verbose          Enable a more verbose output.

Actions mode:

        audit                     Display the user-land hooks and / or Kernel callbacks without taking actions.
        dump                      Dump the process specified by --process-name (LSASS process by default), as '<process_name>' in the current directory or at the
                                  specified file using -o | --output <DUMP_FILE>.
        cmd                       Open a cmd.exe prompt.
        credguard                 Patch the LSASS process' memory to enable Wdigest cleartext passwords caching even if
                                  Credential Guard is enabled on the host. No kernel-land actions required.
        firewall                  Add Windows firewall rules to block network access for the EDR processes / services.
        load_unsigned_driver      Load the specified unsigned driver, bypassing Driver Signature Enforcement (DSE).
                                  WARNING: currently an experimental feature, only works if KDP is not present and enabled.

--usermode              Perform user-land operations (DLL unhooking).
--kernelmode            Perform kernel-land operations (Kernel callbacks removal and ETW TI disabling).


Hooking-related options:

--add-dll <dll name or path>            Loads arbitrary libraries into the process' address space, before starting
                                        anything.This can be useful to audit userland hooking for DLL that are not
                                        loaded by default by this program. Use this option multiple times to load
                                        multiple DLLs all at once.
                                        Example of interesting DLLs to look at: user32.dll, ole32.dll, crypt32.dll,
                                        samcli.dll, winhttp.dll, urlmon.dll, secur32.dll, shell32.dll...

--unhook-method <N>                     Choose the userland un-hooking technique, from the following:

        0                               Do not perform any unhooking (used for direct syscalls operations).
        1 (Default)                     Uses the (probably monitored) NtProtectVirtualMemory function in ntdll to remove all
                                        present userland hooks.
        2                               Constructs a 'unhooked' (i.e. unmonitored) version of NtProtectVirtualMemory, by                                        allocating an executable trampoline jumping over the hook, and remove all present
                                        userland hooks.
        3                               Searches for an existing trampoline allocated by the EDR itself, to get an 'unhooked'
                                        (i.e. unmonitored) version of NtProtectVirtualMemory, and remove all present userland
                                        hooks.
        4                               Loads an additional version of ntdll library into memory, and use the (hopefully                                        unmonitored) version of NtProtectVirtualMemory present in this library to remove all
                                        present userland hooks.
        5                               Allocates a shellcode that uses a direct syscall to call NtProtectVirtualMemory,                                        and uses it to remove all detected hooks

--direct-syscalls       Use direct syscalls to dump the selected process memory without unhooking unserland hooks.


BYOVD options:

--dont-unload-driver                    Keep the vulnerable driver installed on the host
                                        Default to automatically unsinstall the driver.
--no-restore                            Do not restore the EDR drivers' Kernel Callbacks that were removed.
                                        Default to restore the callbacks.
--vuln-driver <gdrv.sys>                Path to the vulnerable driver file.
                                        Default to 'gdrv.sys' in the current directory.
--vuln-service <SERVICE_NAME>           Name of the vulnerable service to intall / start.


Driver sideloading options:

--unsigned-driver <evil.sys>            Path to the unsigned driver file.
                                        Default to 'evil.sys' in the current directory.
--unsigned-service <SERVICE_NAME>       Name of the unsigned driver's service to intall / start.
--no-kdp                                Switch to g_CiOptions patching method for disabling DSE (default is callback swapping).


Offset-related options:

--nt-offsets <NtoskrnlOffsets.csv>      Path to the CSV file containing the required ntoskrnl.exe's offsets.
                                        Default to 'NtoskrnlOffsets.csv' in the current directory.
--fltmgr-offsets <FltmgrOffsets.csv>    Path to the CSV file containing the required fltmgr.sys's offsets
                                        Default to 'FltmgrOffsets.csv' in the current directory.
--wdigest-offsets <WdigestOffsets.csv>  Path to the CSV file containing the required wdigest.dll's offsets
                                        (only for the 'credguard' mode).
                                        Default to 'WdigestOffsets.csv' in the current directory.
--ci-offsets <CiOffsets.csv>            Path to the CSV file containing the required ci.dll's offsets
                                        (only for the 'load_unsigned_driver' mode).
                                        Default to 'WdigestOffsets.csv' in the current directory.
-i | --internet                         Enables automatic symbols download from Microsoft Symbol Server
                                        If a corresponding *Offsets.csv file exists, appends the downloaded offsets to the file for later use
                                        OpSec warning: downloads and drops on disk a PDB file for the corresponding image

Dump options:

-o | --dump-output <DUMP_FILE>          Output path to the dump file that will be generated by the 'dump' mode.
                                        Default to 'process_name' in the current directory.
--process-name <NAME>                   File name of the process to dump (defaults to 'lsass.exe')

빌드

EDRSandBlast(x64 전용)는 Visual Studio 2019(Windows SDK 버전: 10.0.19041.0, 플랫폼 도구 집합: Visual Studio 2019 (v142))에서 빌드되었습니다.

ExtractOffsets.py 사용법

ExtractOffsets.py는 Windows에서만 테스트되었습니다.```

Installation of Python dependencies

pip.exe install -m .\requirements.txt

Script usage

ExtractOffsets.py [-h] -i INPUT [-o OUTPUT] [-d] mode

positional arguments: mode ntoskrnl or wdigest. Mode to download and extract offsets for either ntoskrnl or wdigest

optional arguments: -h, --help show this help message and exit -i INPUT, --input INPUT Single file or directory containing ntoskrnl.exe / wdigest.dll to extract offsets from. If in download mode, the PE downloaded from MS symbols servers will be placed in this folder. -o OUTPUT, --output OUTPUT CSV file to write offsets to. If the specified file already exists, only new ntoskrnl versions will be downloaded / analyzed. Defaults to NtoskrnlOffsets.csv / WdigestOffsets.csv in the current folder. -d, --download Flag to download the PE from Microsoft servers using list of versions from winbindex.m417z.com.

root@kitploit:~
## 탐지
방어자(EDR 벤더, Microsoft, EDR 텔레메트리를 분석하는 SOC 분석가 등)의 관점에서 이러한 유형의 기술을 탐지하거나 방지하는 데 사용할 수 있는 여러 지표가 있습니다.

### 드라이버 허용 목록
커널 모드 메모리에서 도구가 수행하는 모든 작업이 취약한 드라이버를 사용하여 임의의 내용을 읽고 쓰는 데 의존하므로, 드라이버 로딩 이벤트는 EDR 제품(또는 SOC 분석가)에 의해 철저히 조사되어야 하며, 일반적이지 않은 드라이버 로딩에 대해 경고를 발생시키거나 알려진 취약한 드라이버를 차단해야 합니다. 후자의 접근 방식은 [Microsoft 자체에서 권장](https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-driver-block-rules)합니다. HVCI(*Hypervisor-protected code integrity*)가 활성화된 모든 Windows 장치에는 드라이버 차단 목록이 포함되어 있으며, 이는 점차 Windows의 기본 동작이 될 것입니다(Windows 11에서는 이미 기본입니다).

### 커널 메모리 무결성 검사
공격자가 알려지지 않은 취약한 드라이버를 사용하여 메모리에서 동일한 작업을 수행할 수 있기 때문에, EDR 드라이버는 주기적으로 커널 콜백이 여전히 등록되어 있는지 확인할 수 있습니다. 이 도구와 같이 커널 메모리를 직접 검사하거나, 단순히 이벤트(프로세스 생성, 스레드 생성, 이미지 로딩 등)를 트리거하여 콜백 함수가 실행 커널에 의해 실제로 호출되는지 확인할 수 있습니다.

참고로, 이러한 유형의 데이터 구조는 VBS(Virtual Based Security)에 의존하는 최근의 [KDP(Kernel Data Protection)](https://www.microsoft.com/security/blog/2020/07/08/introducing-kernel-data-protection-a-new-platform-security-technology-for-preventing-data-corruption/) 메커니즘을 통해 보호될 수 있으며, 올바른 API를 호출하지 않고는 커널 콜백 배열을 쓰기 불가능하게 만듭니다.

동일한 논리는 이 도구에서 ETW Threat Intelligence 이벤트 생성을 비활성화하기 위해 남용된 `ProviderEnableInfo`와 같은 민감한 ETW 변수에도 적용될 수 있습니다.

### 사용자 모드 탐지
프로세스가 사용자 영역 후킹을 적극적으로 회피하려고 시도하고 있다는 첫 번째 지표는 로드된 모듈에 해당하는 각 DLL에 대한 파일 액세스입니다. 정상적인 실행 중에 사용자 영역 프로세스는 `LoadLibrary` 호출 외에는 DLL 파일을 거의 읽을 필요가 없으며, 특히 `ntdll.dll`의 경우 더욱 그렇습니다.

API 후킹이 우회되는 것을 방지하기 위해 EDR 제품은 모니터링되는 각 프로세스 내에서 메모리의 후크가 변경되지 않았는지 주기적으로 확인할 수 있습니다.

마지막으로, 후크 제거를 수반하지 않는 후킹 우회(트램펄린 남용, 직접 시스템 콜 사용 등)를 탐지하기 위해 EDR 제품은 남용된 시스템 콜과 관련된 커널 콜백(예: `NtCreateProcess` 시스템 콜의 `PsCreateProcessNotifyRoutine`, `NtOpenProcess` 시스템 콜의 `ObRegisterCallbacks` 등)을 사용하여 사용자 모드 호출 스택 분석을 수행할 수 있으며, 시스템 콜이 정상 경로(`kernel32.dll` -> `ntdll.dll` -> 시스템 콜)에서 트리거되었는지 비정상 경로(예: `program.exe` -> 직접 시스템 콜)에서 트리거되었는지 확인할 수 있습니다.

## 감사의 말

- 커널 콜백 열거 및 제거:
  https://github.com/br-sn/CheekyBlinder

- 취약한 `Micro-Star MSI Afterburner` 드라이버를 통한 커널 메모리 읽기/쓰기 기본 요소:
  https://github.com/Barakat/CVE-2019-16098/

- ETW Threat Intelligence 공급자 비활성화:
  https://public.cnotools.studio/bring-your-own-vulnerable-kernel-driver-byovkd/exploits/data-only-attack-neutralizing-etwti-provider

- 드라이버 설치/제거: https://github.com/gentilkiwi/mimikatz

- EDR 드라이버 이름 초기 목록:
  https://github.com/SadProcessor/SomeStuff/blob/master/Invoke-EDRCheck.ps1

- `LSASS` 메모리 패치를 통해 `Wdigest`를 재활성화하여 Credential Guard 우회:
  https://teamhydra.blog/2020/08/25/bypassing-credential-guard/

## 저자

[Thomas DIOT (Qazeer)](https://github.com/Qazeer/)
[Maxime MEIGNAN (themaks)](https://github.com/themaks)

## 기여자 감사
- [v1k1ngfr](https://github.com/v1k1ngfr): Driver Signature Enforcement 우회(`g_CiOptions` 패칭) 및 GDRV.sys 드라이버 지원
- [Windy Bug](https://github.com/0mWindyBug): KDP 호환 Driver Signature Enforcement 우회(*콜백 교환* 방식) 및 미니필터 우회 기능에 대한 주요 기여

## 라이선스

CC BY 4.0 라이선스 - https://creativecommons.org/licenses/by/4.0/
도구 다운로드
지원되는 드라이버다운로드 링크SHA256
GDRV.sysLOLDrivers 링크31f4cfb4c71da44120752721103a16512444c13c2ac2d857a7e6f13cb679b427
RTCore64.sysLOLDrivers 링크01aa278b07b58dc46c84bd0b1b5c8e9ee4e62ea0bf7a695862444af32e87f1fd
DBUtil_2_3.sysLOLDrivers 링크0296e2ce999e67c76352613a718e11516fe1b0efc3ffdb8918fc999dd76a73a5