
EDRSandblast-GodFault
Di Gabriel Landau presso Elastic Security. Modifica di EDRSandblast - vedi README originale qui sotto.
Integra GodFault in EDR Sandblast, ottenendo lo stesso risultato senza l'uso di driver vulnerabili.
C:\Users\user\Desktop\Offsets>EDRSandblast.exe --kernelmode cmd
| | __ | __ \ / | | | | | | | |
| | | | | | |) | ( __ _ _ __ | | | | | __ _ | |
| | | | | | _ / _ \ / | '_ \ / _ | ' | |/ ` / __| __|
| || || | | \ \ ) | (| | | | | (| | |) | | (| _ | |
||_____/|| _|/ _,|| ||_,|_./||_,|__/__|
D3FC0N 30 Edition | Thomas DIOT (@_Qazeer) & Maxime MEIGNAN (@th3m4ks)
[!] If kernel mode bypass is enabled, it is recommended to enable usermode bypass as well (e.g. to unhook the NtLoadDriver API call)
[===== KERNEL MODE =====]
[+] Setting up prerequisites for the kernel read/write primitives... [+] Loading kernel related offsets from the CSV file [*] System's ntoskrnl.exe file version is: ntoskrnl_22621-1702.exe [+] Offsets are available for this version of ntoskrnl.exe (ntoskrnl_22621-1702.exe)! [+] Checking if any EDR kernel notify rountines are set for image loading, process and thread creations... [+] [NotifyRountines] Enumerating process creation callbacks [+] Running command: GodFault.exe -t 2684 [?] Server does not appear to be running. Attempting to install it... [+] CSRSS PID is 748 [+] Testing initial ability to acquire PROCESS_ALL_ACCESS to System: Failure [+] Ready. Spawning WinTcb. [+] SpawnPPL: Waiting for child process to finish. [+] Thread 2684 (KTHREAD FFFF910961E4C080) has been blessed by GodFault [+] [NotifyRountines] fffff8034df25500 [cng.sys + 0x5500] [+] [NotifyRountines] fffff8034e9efdc0 [WdFilter.sys + 0x4fdc0] [+] [NotifyRountines] Found callback belonging to EDR driver WdFilter.sys [+] [NotifyRountines] fffff803487bc460 [ksecdd.sys + 0x1c460] [+] [NotifyRountines] fffff8034eff3fd0 [tcpip.sys + 0x13fd0] [+] [NotifyRountines] fffff8034f5ed980 [iorate.sys + 0xd980] [+] [NotifyRountines] fffff8034dea8890 [CI.dll + 0x88890] [+] [NotifyRountines] fffff803525079f0 [dxgkrnl.sys + 0x179f0] [+] [NotifyRountines] fffff80352be0a70 [vm3dmp.sys + 0x10a70] [+] [NotifyRountines] fffff8036ebccd00 [peauth.sys + 0x3cd00] [+] [NotifyRountines] fffff8036eda1550 [wtd.sys + 0x1550] [+] [NotifyRountines] Found a total of 1 EDR / security products driver(s) [+] [NotifyRountines] Enumerating thread creation callbacks [+] [NotifyRountines] fffff8034e9f15c0 [WdFilter.sys + 0x515c0] [+] [NotifyRountines] Found callback belonging to EDR driver WdFilter.sys [+] [NotifyRountines] fffff8034e9f1350 [WdFilter.sys + 0x51350] [+] [NotifyRountines] Found callback belonging to EDR driver WdFilter.sys [+] [NotifyRountines] fffff8036eb71010 [mmcss.sys + 0x1010] [+] [NotifyRountines] Found a total of 2 EDR / security products driver(s) [+] [NotifyRountines] Enumerating image loading callbacks [+] [NotifyRountines] fffff8034e9f0820 [WdFilter.sys + 0x50820] [+] [NotifyRountines] Found callback belonging to EDR driver WdFilter.sys [+] [NotifyRountines] fffff80352ab5710 [ahcache.sys + 0x25710] [+] [NotifyRountines] Found a total of 1 EDR / security products driver(s)
[+] Checking if EDR callbacks are registered on processes and threads handle creation/duplication... [+] [ObjectCallblacks] Enumerating Process object callbacks : [+] [ObjectCallblacks] Callback at FFFF800C5E2F2940 for handle creations & duplications: [+] [ObjectCallblacks] Status: Enabled [+] [ObjectCallblacks] Preoperation at 0xfffff8034e9eda30 [WdFilter.sys + 0x4da30] [+] [ObjectCallblacks] Callback belongs to an EDR and is enabled! [+] [ObjectCallblacks] Enumerating Thread object callbacks : [+] [ObjectCallblacks] Object callbacks are present !
[+] [ETWTI] Checking the ETW Threat Intelligence Provider state... [+] [ETWTI] ETW Threat Intelligence Provider is ENABLED!
[+] Process is NOT "safe" to launch our payload, removing monitoring and starting another process...
[+] [ETWTI] Disabling the ETW Threat Intel provider by patching ProviderEnableInfo at 0xffff91095ce8c430 with 0x00. [+] [ETWTI] The ETW Threat Intel provider was successfully disabled!
[+] Removing kernel callbacks registered by EDR for process creation, thread creation and image loading... [+] [NotifyRountines] Removing process creation callbacks [+] [NotifyRountines] Removing callback of EDR driver "WdFilter.sys" [callback addr: 0xfffff8034970c2a8 | callback struct: 0xffff91095dbf3a5f | callback function: 0xfffff8034e9efdc0] [+] [NotifyRountines] Removing thread creation callbacks [+] [NotifyRountines] Removing callback of EDR driver "WdFilter.sys" [callback addr: 0xfffff8034970c4a0 | callback struct: 0xffff91095dbf3b1f | callback function: 0xfffff8034e9f15c0] [+] [NotifyRountines] Removing callback of EDR driver "WdFilter.sys" [callback addr: 0xfffff8034970c4a8 | callback struct: 0xffff91095dbf3b4f | callback function: 0xfffff8034e9f1350] [+] [NotifyRountines] Removing image loading callbacks [+] [NotifyRountines] Removing callback of EDR driver "WdFilter.sys" [callback addr: 0xfffff8034970c6a0 | callback struct: 0xffff91095dbf3e4f | callback function: 0xfffff8034e9f0820]
[+] Disabling kernel callbacks registered by EDR for process and thread opening or handle duplication... [+] [ObjectCallblacks] Disabling WdFilter.sys callback...
[+] All EDR drivers were successfully removed from Kernel callbacks!
[!] If kernel mode bypass is enabled, it is recommended to enable usermode bypass as well (e.g. to unhook the NtLoadDriver API call)
[===== KERNEL MODE =====]
[+] Setting up prerequisites for the kernel read/write primitives... [+] Loading kernel related offsets from the CSV file [*] System's ntoskrnl.exe file version is: ntoskrnl_22621-1702.exe [+] Offsets are available for this version of ntoskrnl.exe (ntoskrnl_22621-1702.exe)! [+] Checking if any EDR kernel notify rountines are set for image loading, process and thread creations... [+] [NotifyRountines] Enumerating process creation callbacks [+] Running command: GodFault.exe -t 8344 [+] Thread 8344 (KTHREAD FFFF91096169F080) has been blessed by GodFault [+] Initial blessing successful [+] [NotifyRountines] fffff8034df25500 [cng.sys + 0x5500] [+] [NotifyRountines] fffff803487bc460 [ksecdd.sys + 0x1c460] [+] [NotifyRountines] fffff8034eff3fd0 [tcpip.sys + 0x13fd0] [+] [NotifyRountines] fffff8034f5ed980 [iorate.sys + 0xd980] [+] [NotifyRountines] fffff8034dea8890 [CI.dll + 0x88890] [+] [NotifyRountines] fffff803525079f0 [dxgkrnl.sys + 0x179f0] [+] [NotifyRountines] fffff80352be0a70 [vm3dmp.sys + 0x10a70] [+] [NotifyRountines] fffff8036ebccd00 [peauth.sys + 0x3cd00] [+] [NotifyRountines] fffff8036eda1550 [wtd.sys + 0x1550] [+] [NotifyRountines] No EDR driver(s) found! [+] [NotifyRountines] Enumerating thread creation callbacks [+] [NotifyRountines] fffff8036eb71010 [mmcss.sys + 0x1010] [+] [NotifyRountines] No EDR driver(s) found! [+] [NotifyRountines] Enumerating image loading callbacks [+] [NotifyRountines] fffff80352ab5710 [ahcache.sys + 0x25710] [+] [NotifyRountines] No EDR driver(s) found!
[+] Checking if EDR callbacks are registered on processes and threads handle creation/duplication... [+] [ObjectCallblacks] Enumerating Process object callbacks : [+] [ObjectCallblacks] Callback at FFFF800C5E2F2940 for handle creations & duplications: [+] [ObjectCallblacks] Status: Disabled [+] [ObjectCallblacks] Preoperation at 0xfffff8034e9eda30 [WdFilter.sys + 0x4da30] [+] [ObjectCallblacks] Callback belongs to an EDR but is disabled. [+] [ObjectCallblacks] Enumerating Thread object callbacks : [+] [ObjectCallblacks] Object callbacks are not found !
[+] [ETWTI] Checking the ETW Threat Intelligence Provider state... [+] [ETWTI] ETW Threat Intelligence Provider is DISABLED!
[+] Process is "safe" to launch our payload
[+] Kernel callbacks have normally been removed, starting cmd.exe WARNING: EDR kernel callbacks will be restored after exiting the cmd prompt (by typing exit) WARNING: While unlikely, the longer the callbacks are removed, the higher the chance of being detected / causing a BSoD upon restore is!
Microsoft Windows [Version 10.0.22621.1702] (c) Microsoft Corporation. All rights reserved.
C:\Users\user\Desktop\Offsets>
# EDRSandBlast
`EDRSandBlast` è uno strumento scritto in `C` che arma un driver vulnerabile firmato
per bypassare le rilevazioni EDR (callback di Notify Routine, callback di oggetti
e provider `ETW TI`) e le protezioni di `LSASS`. Sono implementate anche tecniche multiple
di unhooking in userland per eludere il monitoraggio in userland.
Al momento del rilascio, la combinazione di tecniche in userland (`--usermode`) e in kernel
(`--kernelmode`) è stata utilizzata per dumpare la memoria di `LSASS` sotto il controllo di EDR,
senza essere bloccati né generare eventi correlati a "OS Credential Dumping"
nella console (cloud) del prodotto. I test sono stati effettuati su 3 diversi
prodotti EDR e hanno avuto successo in ogni caso.
## Descrizione
### Bypass EDR tramite rimozione delle Notify Routine del kernel
I prodotti EDR utilizzano callback "Notify Routines" del kernel su Windows per essere notificati dal kernel
dell'attività di sistema, come la creazione di processi e thread e il caricamento di immagini
(`exe` / `DLL`).
Queste callback del kernel sono definite dal kernel, di solito dal driver che le implementa, usando una serie di API documentate
(`nt!PsSetCreateProcessNotifyRoutine`, `nt!PsSetCreateThreadNotifyRoutine`,
ecc.). Queste API aggiungono routine di callback fornite dal driver a array
di routine non documentati nello spazio del kernel:
- `PspCreateProcessNotifyRoutine` per la creazione dei processi
- `PspCreateThreadNotifyRoutine` per la creazione dei thread
- `PspLoadImageNotifyRoutine` per il caricamento delle immagini
`EDRSandBlast` enumera le routine definite in questi array e rimuove qualsiasi
routine di callback collegata a un elenco predefinito di driver EDR (più di 1000
driver di prodotti di sicurezza supportati, vedere la [sezione rilevazione driver EDR](#edr-drivers-and-processes-detection)).
L'enumerazione e la rimozione sono rese possibili attraverso lo sfruttamento di una
primitiva arbitraria di lettura/scrittura della memoria del kernel fornita dallo sfruttamento di un driver vulnerabile (vedere la [sezione driver vulnerabili](#vulnerable-drivers-detection)).
Gli offset degli array menzionati vengono recuperati utilizzando tecniche multiple, fare riferimento alla [sezione Offset](#ntoskrnl-and-wdigest-offsets).
### Bypass EDR tramite rimozione delle callback di oggetti
I prodotti EDR (e anche EPP) spesso registrano "callback di oggetti" tramite l'uso dell'API del kernel
`nt!ObRegisterCallbacks`. Queste callback consentono al prodotto di sicurezza di
essere notificato a ogni generazione di handle su tipi specifici di oggetti (le callback di oggetti relative a processi, thread e
desktop sono ora supportate da Windows). Una generazione di handle
può avvenire all'apertura di un oggetto (chiamata a `OpenProcess`, `OpenThread`, ecc.) così come alla
duplicazione di handle (chiamata a `DuplicateHandle`, ecc.).
Essendo notificato dal kernel per ognuna di queste operazioni, un prodotto di sicurezza può
analizzare la legittimità della creazione dell'handle (*ad esempio, un processo sconosciuto sta tentando di aprire
LSASS*), e persino bloccarla se viene rilevata una minaccia.
A ogni registrazione di callback tramite `ObRegisterCallbacks`, un nuovo elemento viene aggiunto alla lista
doppiamente collegata `CallbackList` presente nell'oggetto `_OBJECT_TYPE` che descrive
il tipo di oggetto interessato dalla callback (un Processo, un Thread o un Desktop).
Sfortunatamente, questi elementi sono descritti da una struttura che non è documentata né
pubblicata nei file dei simboli da Microsoft. Tuttavia, studiandola da varie versioni di `ntoskrnl.exe`
sembra indicare che la struttura non sia cambiata tra (almeno) Windows
10 build 10240 e 22000 (dal 2015 al 2022).
La struttura menzionata, che rappresenta una registrazione di callback di oggetti, è la seguente:```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;
La struttura OB_CALLBACK menzionata sopra è anche non documentata, ed è definita come segue:```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;
Per disabilitare i callback degli oggetti registrati da EDR, tre tecniche sono implementate in `EDRSandblast`; tuttavia solo una è abilitata al momento.
#### Utilizzo del campo `Enabled` di `OB_CALLBACK_ENTRY`
Questa è la tecnica predefinita abilitata in `EDRSandblast`. Per rilevare e disabilitare i callback degli oggetti correlati a EDR, viene esplorata la lista `CallbackList` situata negli oggetti `_OBJECT_TYPE` associati ai tipi *Process* e *Thread*. Entrambi gli `_OBJECT_TYPE` sono puntati da simboli globali pubblici nel kernel, `PsProcessType` e `PsThreadType`.
Si assume che ogni elemento della lista corrisponda alla struttura `OB_CALLBACK_ENTRY` descritta sopra (supposizione che sembra valere almeno in tutte le build di Windows 10 al momento della scrittura). Le funzioni definite nei campi `PreOperation` e `PostOperation` vengono individuate per verificare se appartengono a un driver EDR, e in tal caso, i callback vengono semplicemente disabilitati commutando il flag `Enabled`.
Sebbene sia una tecnica abbastanza sicura, ha l'inconveniente di basarsi su una struttura non documentata; per ridurre il rischio di manipolazione non sicura di questa struttura, vengono eseguiti controlli di base per validare che alcuni campi abbiano i valori attesi:
* `Enabled` è `TRUE` o `FALSE` (*non ridere, un `BOOL` è un `int`, quindi potrebbe essere qualsiasi cosa diversa da `1` o `0`*);
* `Operations` è `OB_OPERATION_HANDLE_CREATE`, `OB_OPERATION_HANDLE_DUPLICATE` o entrambi;
* `ObjectType` punta a `PsProcessType` o `PsThreadType`.
#### Scollegamento della `CallbackList` di thread e processi
Un'altra strategia che non si basa su una struttura non documentata (ed è quindi teoricamente più robusta rispetto ai cambiamenti del kernel NT) è lo scollegamento dell'intera `CallbackList` sia per i processi che per i thread. L'oggetto `_OBJECT_TYPE` è il seguente:```C
struct _OBJECT_TYPE {
LIST_ENTRY TypeList;
UNICODE_STRING Name;
[...]
_OBJECT_TYPE_INITIALIZER TypeInfo;
[...]
LIST_ENTRY CallbackList;
}
Facendo sì che i puntatori Flink e Blink dell'LIST_ENTRY del CallbackList puntino all'LIST_ENTRY stessa si svuota effettivamente la lista. Poiché la struttura _OBJECT_TYPE è pubblicata nei simboli del kernel, la tecnica non si basa su offset/strutture hardcoded. Tuttavia, presenta alcuni svantaggi.
Il primo è l'impossibilità di disabilitare solo le callback dell'EDR; infatti, la tecnica influisce su tutte le callback degli oggetti che potrebbero essere state registrate da software "legittimo". Va comunque notato che le callback degli oggetti non sono utilizzate da alcun componente preinstallato su Windows 10 (al momento della scrittura), quindi la loro disabilitazione non dovrebbe compromettere la stabilità della macchina (ancor più se la disabilitazione è solo temporanea).
Il secondo svantaggio è che le operazioni sugli handle di processi o thread sono molto frequenti (quasi continue) nel normale funzionamento del sistema operativo. Pertanto, se la primitiva di scrittura nel kernel utilizzata non riesce a eseguire una scrittura QWORD "atomicamente", c'è un'alta probabilità che il puntatore _OBJECT_TYPE.CallbackList.Flink venga acceduto dal kernel nel bel mezzo della sua sovrascrittura. Ad esempio, il driver vulnerabile MSI RTCore64.sys può eseguire solo una scrittura DWORD alla volta, quindi saranno necessari 2 IOCTL distinti per sovrascrivere il puntatore, tra i quali il kernel ha un'alta probabilità di utilizzarlo (provocando un crash). D'altra parte, il driver DELL vulnerabile DBUtil_2_3.sys può eseguire scritture di dimensioni arbitrarie in un unico IOCTL, quindi usare questo metodo con esso non rischia di causare un crash.
Un'ultima tecnica che abbiamo trovato è disabilitare completamente il supporto alle callback degli oggetti per thread e processi. All'interno della struttura _OBJECT_TYPE corrispondente ai tipi processo e thread si trova un campo TypeInfo, che segue la struttura documentata _OBJECT_TYPE_INITIALIZER. Quest'ultima contiene un campo di bit ObjectTypeFlags, il cui flag SupportsObjectCallbacks determina se il tipo di oggetto descritto (Processo, Thread, Desktop, Token, File, ecc.) supporta o meno la registrazione di callback. Come detto in precedenza, solo i tipi di oggetto Processo, Thread e Desktop supportano queste callback in un'installazione Windows al momento della scrittura.
Poiché il bit SupportsObjectCallbacks viene verificato da ObpCreateHandle o ObDuplicateObject prima ancora di leggere il CallbackList (e prima di eseguire le callback, ovviamente), invertire il bit in fase di esecuzione del kernel disabilita efficacemente tutte le esecuzioni di callback degli oggetti.
Il principale svantaggio del metodo è semplicemente che KPP ("PatchGuard") monitora l'integrità di alcune (di tutte?) le strutture _OBJECT_TYPE e attiva un 0x109 Bug Check con il parametro 4 uguale a 0x8, il che significa che una struttura del tipo di oggetto è stata alterata.
Tuttavia, eseguire la disabilitazione / riabilitazione (e l'azione "maligno" nel mezzo) abbastanza velocemente dovrebbe essere sufficiente per "battere sul tempo" PatchGuard (a meno che non si sia sfortunati e un controllo periodico venga eseguito proprio nel momento sbagliato).
Il provider ETW Microsoft-Windows-Threat-Intelligence registra i dati sugli utilizzi di alcune API Windows comunemente usate in modo dannoso. Ciò include l'API nt!MiReadWriteVirtualMemory, chiamata da nt!NtReadVirtualMemory (che viene utilizzata per scaricare la memoria di LSASS) e monitorata dalla funzione nt!EtwTiLogReadWriteVm.
I prodotti EDR possono consumare i log prodotti dal provider ETW TI attraverso servizi o processi in esecuzione rispettivamente come SERVICE_LAUNCH_PROTECTED_ANTIMALWARE_LIGHT o PS_PROTECTED_ANTIMALWARE_LIGHT, e associati a un driver Early Launch Anti Malware (ELAM).
Come pubblicato da slaeryan in un post del blog CNO Development Labs, il provider ETW TI può essere completamente disabilitato modificando, nella memoria del kernel, il suo attributo ProviderEnableInfo a 0x0. Fare riferimento all'ottimo post del blog sopra menzionato per maggiori informazioni sulla tecnica.
Analogamente alla rimozione delle callback del kernel, gli offset necessari di ntoskrnl.exe (nt!EtwThreatIntProvRegHandleOffset, GuidEntry di _ETW_REG_ENTRY e ProviderEnableInfo di _ETW_GUID_ENTRY) vengono calcolati nel file NtoskrnlOffsets.csv per un certo numero di versioni del kernel Windows.
Per monitorare facilmente le azioni eseguite dai processi, i prodotti EDR spesso implementano un meccanismo chiamato hooking in userland. Innanzitutto, i prodotti EDR registrano una callback del kernel (solitamente callback di caricamento immagine o creazione processo, vedi sopra) che consente loro di essere notificati all'avvio di ogni processo.
Quando un processo viene caricato da Windows, e prima che inizi effettivamente, l'EDR è in grado di iniettare una DLL personalizzata nello spazio degli indirizzi del processo, che contiene la sua logica di monitoraggio. Durante il caricamento, questa DLL inietta "hook" all'inizio di ogni funzione che deve essere monitorata dall'EDR. In fase di esecuzione, quando le funzioni monitorate vengono chiamate dal processo sotto sorveglianza, questi hook reindirizzano il flusso di controllo verso un codice di supervisione presente nella DLL dell'EDR, che permette di ispezionare argomenti e valori di ritorno di queste chiamate.
La maggior parte delle volte, le funzioni monitorate sono chiamate di sistema (come NtReadVirtualMemory, NtOpenProcess, ecc.), le cui implementazioni risiedono in ntdll.dll. Intercettare le chiamate alle funzioni Nt* consente ai prodotti di essere il più vicino possibile al confine tra userland e kernel (rimanendo comunque in userland), ma possono essere monitorate anche funzioni di DLL di livello superiore.
Di seguito sono riportati esempi della stessa funzione, prima e dopo essere stata hookata dal prodotto 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
├───[tools]
│ bruteratel.py
│ cve_2017_7921.py
│ cve_2021_27905.py
│ cve_2021_3347.py
│ dirsearch.py
│ gobuster.py
│ ...```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
Gli hook in spazio utente hanno la "debolezza" di risiedere nella memoria dello spazio utente, il che significa che sono direttamente osservabili e modificabili dal processo sotto esame. Per rilevare automaticamente gli hook nello spazio degli indirizzi del processo, l'idea principale è confrontare le differenze tra la DLL originale su disco e la libreria residente in memoria, che potrebbe essere stata alterata da un EDR. Per eseguire questo confronto, EDRSandblast segue i seguenti passaggi:
InLoadOrderModuleList situato
nel PEB (per evitare di chiamare qualsiasi API che potrebbe essere monitorata e sospetta)Nota: Il processo può essere generalizzato per trovare differenze ovunque in sezioni non scrivibili,
e non solo all'inizio delle funzioni esportate, ad esempio se i prodotti EDR iniziano a
applicare hook nel mezzo di una funzione :) Quindi non utilizzato dallo strumento, questo è stato
implementato in findDiffsInNonWritableSections.
Per bypassare il monitoraggio eseguito da questi hook, sono possibili molteplici tecniche, e ognuna ha vantaggi e svantaggi.
Il metodo più intuitivo per bypassare il monitoraggio basato sugli hook è rimuovere gli hook. Poiché gli hook sono presenti in memoria accessibile dal processo stesso, per rimuovere un hook, il processo può semplicemente:
Questo approccio è abbastanza semplice e può essere utilizzato per rimuovere tutti gli hook rilevati in una sola volta. Eseguito all'inizio da uno strumento offensivo, consente al resto del codice di essere completamente inconsapevole del meccanismo di hooking e funzionare normalmente senza essere monitorato.
Tuttavia, presenta due principali svantaggi. L'EDR probabilmente monitora l'uso di
NtProtectVirtualMemory, quindi usarlo per modificare i permessi della pagina in cui gli
hook sono stati installati è (almeno concettualmente) una cattiva idea. Inoltre, se un thread
viene eseguito dall'EDR e controlla periodicamente l'integrità degli hook, questo potrebbe
innescare alcune rilevazioni.
Per i dettagli implementativi, controlla il percorso del codice della funzione unhook() quando unhook_method è
UNHOOK_WITH_NTPROTECTVIRTUALMEMORY.
Nota importante: per semplicità, questa tecnica è implementata in EDRSandblast come
tecnica base utilizzata per mostrare le altre tecniche di bypass; ognuna di esse dimostra
come ottenere una versione non monitorata di NtProtectVirtualMemory, ma esegue la stessa
operazione successivamente (rimuovendo un hook specifico).
Per bypassare un hook specifico, è possibile semplicemente "saltare oltre" ed eseguire il resto della funzione così com'è. Innanzitutto, i byte originali della funzione monitorata, che sono stati sovrascritti dall'EDR per installare l'hook, devono essere recuperati dal file DLL. Nel nostro precedente esempio di codice, questi sarebbero i byte corrispondenti alle seguenti istruzioni:```assembly mov r10, rcx mov eax, 50h
Identificare questi byte è un compito semplice poiché siamo in grado di eseguire un *diff* pulito sia della versione in memoria che di quella su disco della libreria, come descritto in precedenza. Poi, assembliamo un'istruzione di salto costruita per reindirizzare il flusso di controllo al codice che segue immediatamente l'hook, all'indirizzo `NtProtectVirtualMemory + sizeof(overwritten_instructions)````assembly
jmp NtProtectVirtualMemory+8
Finalmente, concateniamo questi opcode, li memorizziamo in memoria (appena resa) eseguibile e manteniamo un puntatore ad essi. Questo oggetto è chiamato "trampolino" e può quindi essere utilizzato come puntatore a funzione, strettamente equivalente alla funzione originale NtProtectVirtualMemory.
Il vantaggio principale di questa tecnica, come per tutte le tecniche seguenti, è che l'hook non viene mai cancellato, quindi qualsiasi controllo di integrità eseguito sugli hook dall'EDR dovrebbe essere superato. Tuttavia, richiede di allocare memoria scrivibile e poi eseguibile, tipica di un'allocazione di shellcode, attirando quindi l'attenzione dell'EDR.
Per i dettagli implementativi, controlla il percorso del codice della funzione unhook() quando unhook_method è UNHOOK_WITH_INHOUSE_NTPROTECTVIRTUALMEMORY_TRAMPOLINE. Ricorda che la tecnica è mostrata solo nella nostra implementazione e, in definitiva, viene utilizzata per rimuovere gli hook dalla memoria, come tutte le tecniche seguenti.
Il prodotto EDR, affinché il suo hook funzioni, deve salvare da qualche parte in memoria gli opcode che ha rimosso. Peggio (o "meglio", dal punto di vista dell'attaccante), per utilizzare effettivamente le istruzioni originali, l'EDR probabilmente si è allocato un trampolino da qualche parte per eseguire la funzione originale dopo aver intercettato la chiamata.
Questo trampolino può essere cercato e utilizzato come sostituto della funzione hookata, senza la necessità di allocare memoria eseguibile o chiamare alcuna API tranne VirtualQuery, che molto probabilmente non è monitorata in quanto funzione innocua.
Per trovare il trampolino in memoria, esploriamo l'intero spazio degli indirizzi utilizzando VirtualQuery alla ricerca di memoria committed ed eseguibile. Per ogni regione di memoria di questo tipo, la scansioniamo per cercare un'istruzione di salto che punti all'indirizzo successivo alle istruzioni sovrascritte (NtProtectVirtualMemory+8 nel nostro esempio precedente). Il trampolino può quindi essere utilizzato per chiamare la funzione hookata senza attivare l'hook.
Questa tecnica funziona sorprendentemente bene, poiché recupera quasi tutti i trampolini sugli EDR testati. Per i dettagli implementativi, controlla il percorso del codice della funzione unhook() quando unhook_method è UNHOOK_WITH_EDR_NTPROTECTVIRTUALMEMORY_TRAMPOLINE.
Un altro semplice metodo per ottenere l'accesso a una versione non monitorata della funzione NtProtectVirtualMemory è caricare una versione duplicata della libreria ntdll.dll nello spazio degli indirizzi del processo. Poiché due DLL identiche possono essere caricate nello stesso processo, a condizione che abbiano nomi diversi, possiamo semplicemente copiare il file ntdll.dll legittimo in un'altra posizione, caricarlo usando LoadLibrary (o reimplementare il processo di caricamento) e accedere alla funzione usando GetProcAddress, per esempio.
Questa tecnica è molto semplice da capire e implementare, e ha una discreta possibilità di successo, poiché la maggior parte dei prodotti EDR non re-installa gli hook sulle DLL appena caricate una volta che il processo è in esecuzione. Tuttavia, il principale svantaggio è che copiare i binari firmati Microsoft con un nome diverso è spesso considerato sospetto dagli stessi prodotti EDR.
Questa tecnica è comunque implementata in EDRSandblast. Per i dettagli implementativi, controlla il percorso del codice della funzione unhook() quando unhook_method è UNHOOK_WITH_DUPLICATE_NTPROTECTVIRTUALMEMORY.
Per utilizzare le funzioni relative alle chiamate di sistema, un programma può reimplementare le syscall (in assembly) per chiamare le funzionalità corrispondenti del sistema operativo senza toccare effettivamente il codice in ntdll.dll, che potrebbe essere monitorato dall'EDR. Ciò bypassa completamente qualsiasi hooking a livello utente effettuato sulle funzioni syscall in ntdll.dll.
Questo ha comunque alcuni svantaggi. Innanzitutto, implica essere in grado di conoscere l'elenco dei numeri di syscall delle funzioni di cui il programma ha bisogno, che cambia per ogni versione di Windows. Ciò è comunque mitigato implementando molteplici euristiche note per funzionare in tutte le versioni passate di Windows NT (ordinamento degli export Zw* di ntdll, ricerca dell'istruzione mov rax, #syscall_number nella funzione ntdll associata, ecc.) e verificando che tutte restituiscano lo stesso risultato (vedere Syscalls.c per maggiori dettagli).
Inoltre, le funzioni che non sono tecnicamente syscall (ad es. LoadLibraryX/LdrLoadDLL) potrebbero essere monitorate e non possono essere semplicemente reimplementate utilizzando una syscall.
La tecnica delle syscall dirette è implementata in EDRSandblast. Come affermato in precedenza, viene utilizzata solo per eseguire NtProtectVirtualMemory in sicurezza e rimuovere tutti gli hook rilevati.
Per i dettagli implementativi, controlla il percorso del codice della funzione unhook() quando unhook_method è UNHOOK_WITH_DIRECT_SYSCALL.
Come affermato in precedenza, ogni azione che richiede una lettura o scrittura della memoria del kernel si basa su un driver vulnerabile per fornire questa primitiva. In EDRSandblast, aggiungere il supporto per un nuovo driver che fornisce la primitiva di lettura/scrittura può essere fatto "facilmente"; devono essere implementate solo tre funzioni:
ReadMemoryPrimitive_DRIVERNAME(SIZE_T Size, DWORD64 Address, PVOID Buffer), che copia Size byte dall'indirizzo del kernel Address al buffer in spazio utente Buffer;WriteMemoryPrimitive_DRIVERNAME(SIZE_T Size, DWORD64 Address, PVOID Buffer), che copia Size byte dal buffer in spazio utente Buffer all'indirizzo del kernel Address;CloseDriverHandle_DRIVERNAME() che garantisce che tutti gli handle al driver siano chiusi (necessario prima dell'operazione di disinstallazione, che per ora è indipendente dal driver).Ad esempio, due driver sono attualmente supportati da EDRSandblast, RTCore64.sys (SHA256: 01AA278B07B58DC46C84BD0B1B5C8E9EE4E62EA0BF7A695862444AF32E87F1FD) e DBUtils_2_3.sys (SHA256: 0296e2ce999e67c76352613a718e11516fe1b0efc3ffdb8918fc999dd76a73a5). Il codice seguente in KernelMemoryPrimitives.h deve essere aggiornato se il driver vulnerabile utilizzato deve essere cambiato o se ne viene implementato uno nuovo.```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
### Rilevamento dei driver e dei processi EDR
Attualmente vengono utilizzate molteplici tecniche per determinare se un driver o un processo specifico appartiene o meno a un prodotto EDR.
Innanzitutto, il nome del driver può essere semplicemente usato per questo scopo. Infatti, Microsoft assegna numeri specifici chiamati "Altitudes" a tutti i driver che devono inserire callback nel kernel. Questo consente un ordine deterministico nell'esecuzione dei callback, indipendente dall'ordine di registrazione, ma basato solo sull'utilizzo del driver. Un elenco di (fornitori di) driver che hanno riservato una *altitude* specifica può essere trovato
[su MSDN](https://docs.microsoft.com/en-us/windows-hardware/drivers/ifs/allocated-altitudes).
Di conseguenza, Microsoft offre un elenco quasi completo dei nomi dei driver di sicurezza legati ai prodotti di sicurezza, principalmente nelle liste "FSFilter Anti-Virus" e "FSFilter Activity Monitor". Questi elenchi di nomi di driver sono incorporati in EDRSandblast, insieme a contributi aggiuntivi.
Inoltre, gli eseguibili e le DLL EDR sono spesso firmati digitalmente utilizzando il certificato di firma del fornitore. Pertanto, controllare il firmatario di un eseguibile o DLL associato a un processo può consentire di identificare rapidamente i prodotti EDR.
Inoltre, i driver devono essere firmati direttamente da Microsoft per poter essere caricati nello spazio kernel. Sebbene il fornitore del driver non sia direttamente il firmatario del driver stesso, sembra che il nome del fornitore sia comunque incluso all'interno di un attributo della firma; questa tecnica di rilevamento deve comunque ancora essere studiata e implementata.
Infine, quando si affronta un EDR sconosciuto a EDRSandblast, l'approccio migliore è eseguire lo strumento in modalità "audit" e controllare l'elenco dei driver che hanno registrato callback del kernel; quindi il nome del driver può essere aggiunto all'elenco, lo strumento ricompilato e rieseguito.
### Bypass di RunAsPPL
Il meccanismo di `Protezione dell'Autorità di Sicurezza Locale (LSA)`, introdotto per la prima volta in Windows 8.1 e Windows Server 2012 R2, sfrutta la tecnologia `Protected Process Light (PPL)` per limitare l'accesso al processo `LSASS`. La protezione `PPL` regola e limita operazioni come l'iniezione di memoria o il dumping della memoria di processi protetti, anche da un processo che detiene il privilegio `SeDebugPrivilege`. Nel modello di protezione dei processi, solo i processi in esecuzione con livelli di protezione superiori possono eseguire operazioni su processi protetti.
La struttura `_EPROCESS`, utilizzata dal kernel di Windows per rappresentare un processo nella memoria del kernel, include un campo `_PS_PROTECTION` che definisce il livello di protezione di un processo tramite i suoi attributi `Type` (`_PS_PROTECTED_TYPE`) e `Signer` (`_PS_PROTECTED_SIGNER`).
Scrivendo nella memoria del kernel, il processo EDRSandblast è in grado di aggiornare il proprio livello di protezione a `PsProtectedSignerWinTcb-Light`. Questo livello è sufficiente per eseguire il dump della memoria del processo `LSASS`, poiché "domina" `PsProtectedSignerLsa-Light`, il livello di protezione del processo `LSASS` in esecuzione con il meccanismo `RunAsPPL`.
`EDRSandBlast` implementa l'autoprotezione come segue:
- apre un handle al processo corrente
- perde tutti gli handle di sistema utilizzando `NtQuerySystemInformation` per trovare l'handle aperto sul processo corrente e l'indirizzo della struttura `EPROCESS` del processo corrente nella memoria del kernel.
- utilizza la vulnerabilità di lettura/scrittura arbitraria del driver `Micro-Star MSI Afterburner` per sovrascrivere il campo `_PS_PROTECTION` del processo corrente nella memoria del kernel. Gli offset del campo `_PS_PROTECTION` rispetto alla struttura `EPROCESS` (definiti dalla versione di `ntoskrnl` in uso) sono calcolati nel file `NtoskrnlOffsets.csv`.
### Bypass di Credential Guard
Microsoft `Credential Guard` è una tecnologia di isolamento basata sulla virtualizzazione, introdotta in `Windows 10 (edizione Enterprise)` di Microsoft, che impedisce l'accesso diretto alle credenziali memorizzate nel processo `LSASS`.
Quando `Credentials Guard` è attivato, viene creato un processo `LSAIso` (*LSA Isolated*) in `Virtual Secure Mode`, una funzionalità che sfrutta le estensioni di virtualizzazione della CPU per fornire una maggiore sicurezza dei dati in memoria. L'accesso al processo `LSAIso` è limitato anche per un accesso con il contesto di sicurezza `NT AUTHORITY\SYSTEM`. Durante l'elaborazione di un hash, il processo `LSA` esegue una chiamata `RPC` al processo `LSAIso` e attende il risultato di `LSAIso` per continuare. Pertanto, il processo `LSASS` non conterrà alcun segreto e memorizzerà al suo posto `LSA Isolated Data`.
Come affermato nella ricerca originale condotta da `N4kedTurtle`: "`Wdigest` può essere abilitato su un sistema con Credential Guard modificando i valori di `g_fParameter_useLogonCredential` e `g_IsCredGuardEnabled` in memoria". L'attivazione di `Wdigest` comporterà la memorizzazione di credenziali in chiaro nella memoria di `LSASS` per qualsiasi nuovo accesso interattivo (senza richiedere un riavvio del sistema). Fare riferimento al
[post del blog di ricerca originale](https://teamhydra.blog/2020/08/25/bypassing-credential-guard/) per maggiori dettagli su questa tecnica.
`EDRSandBlast` rende semplicemente il PoC originale un po' più opsec-friendly e fornisce supporto per un certo numero di versioni di `wdigest.dll` (tramite offset calcolati per `g_fParameter_useLogonCredential` e `g_IsCredGuardEnabled`).
### Recupero degli offset
Per eseguire in modo affidabile le operazioni di bypass del monitoraggio del kernel, EDRSandblast deve sapere esattamente dove leggere e scrivere la memoria del kernel. Ciò viene fatto utilizzando gli offset delle variabili globali all'interno dell'immagine target (ntoskrnl.exe, wdigest.dll), nonché gli offset di campi specifici in strutture le cui definizioni sono pubblicate da Microsoft nei file dei simboli. Questi offset sono specifici per ogni build delle immagini target e devono essere raccolti almeno una volta per una versione specifica della piattaforma.
La scelta di utilizzare offset "hardcoded" anziché ricerche di pattern per individuare le strutture e le variabili utilizzate da EDRSandblast è giustificata dal fatto che le API non documentate responsabili dell'aggiunta/rimozione dei callback del kernel sono soggette a modifiche e che qualsiasi tentativo di leggere o scrivere la memoria del kernel all'indirizzo sbagliato può (e spesso lo farà) provocare un `Bug Check` (`Blue Screen of Death`). Un crash della macchina non è accettabile sia negli scenari di red teaming che di normali penetration test, poiché una macchina che si blocca è altamente visibile ai difensori e perderà tutte le credenziali ancora in memoria al momento dell'attacco.
Per recuperare gli offset per ogni versione specifica di Windows, vengono implementati due approcci.
#### Recupero manuale degli offset
Gli offset necessari di `ntoskrnl.exe` e `wdigest.dll` possono essere estratti utilizzando lo script Python `ExtractOffsets.py` fornito, che si basa su `radare2` e `r2pipe` per scaricare e analizzare i simboli dai file PDB ed estrarre gli offset necessari. Gli offset vengono quindi memorizzati in file CSV per un uso successivo da parte di EDRSandblast.
Per supportare immediatamente un'ampia gamma di build di Windows, numerose versioni dei binari `ntoskrnl.exe` e `wdigest.dll` sono referenziate da
[Winbindex](https://winbindex.m417z.com/) e possono essere scaricate automaticamente (con estrazione dei loro offset) da `ExtractOffsets.py`. Ciò consente di estrarre offset da quasi tutti i file mai pubblicati nei pacchetti di aggiornamento di Windows (ad oggi sono disponibili e precalcolate oltre 450 versioni di `ntoskrnl.exe` e oltre 30 versioni di `wdigest.dll`).
#### Recupero e aggiornamento automatico degli offset
È stata implementata un'opzione aggiuntiva in `EDRSandBlast` per consentire al programma di scaricare da solo i file `.pdb` necessari dal Microsoft Symbol Server, estrarre gli offset richiesti e persino aggiornare i corrispondenti file `.csv` se presenti.
L'utilizzo dell'opzione `--internet` rende l'esecuzione dello strumento molto più semplice, introducendo al contempo un ulteriore rischio OpSec, poiché un file `.pdb` viene scaricato e salvato su disco durante il processo. Ciò è richiesto dalle funzioni `dbghelp.dll` utilizzate per analizzare il database dei simboli; tuttavia, in futuro potrebbe essere implementato un parsing completo dei PDB in memoria per eliminare questo requisito e ridurre l'impronta dello strumento.
## Utilizzo
Il driver vulnerabile `RTCore64.sys` può essere recuperato all'indirizzo:```
http://download-eu2.guru3d.com/afterburner/%5BGuru3D.com%5D-MSIAfterburnerSetup462Beta2.zip
Usage: EDRSandblast.exe [-h | --help] [-v | --verbose] <audit | dump | cmd | credguard> [--usermode [--unhook-method ]] [--kernelmode] [--dont-unload-driver] [--dont-restore-callbacks] [--driver <RTCore64.sys>] [--service <SERVICE_NAME>] [--nt-offsets <NtoskrnlOffsets.csv>] [--wdigest-offsets <WdigestOffsets.csv>] [--add-dll ]* [-o | --dump-output <DUMP_FILE>]
### Opzioni```
-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 LSASS process, by default as 'lsass' 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.
--usermode Perform user-land operations (DLL unhooking).
--kernelmode Perform kernel-land operations (Kernel callbacks removal and ETW TI disabling).
--unhook-method <N>
Choose the userland un-hooking technique, from the following:
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
Other options:
--dont-unload-driver Keep the vulnerable driver installed on the host
Default to automatically unsinstall the driver.
--dont-restore-callbacks Do not restore the EDR drivers' Kernel Callbacks that were removed.
Default to restore the callbacks.
--driver <RTCore64.sys> Path to the vulnerable driver file.
Default to 'RTCore64.sys' in the current directory.
--service <SERVICE_NAME> Name of the vulnerable service to intall / start.
--nt-offsets <NtoskrnlOffsets.csv> Path to the CSV file containing the required ntoskrnl.exe's offsets.
Default to 'NtoskrnlOffsets.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.
--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...
-o | --output <DUMP_FILE> Output path to the dump file that will be generated by the 'dump' mode.
Default to 'lsass' 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 ntoskrnl.exe and/or wdigest.dll
EDRSandBlast (solo x64) è stato compilato su Visual Studio 2019 (Windows SDK Versione: 10.0.19041.0 e Plateform Toolset: Visual Studio 2019 (v142)).
Nota che ExtractOffsets.py è stato testato solo su Windows.```
pip.exe install -m .\requirements.txt
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.
## Rilevamento
Dal punto di vista del difensore (fornitore EDR, Microsoft, analisti SOC che esaminano la telemetria EDR, ...), molteplici indicatori possono essere utilizzati per rilevare o prevenire questo tipo di tecniche.
### Whitelisting dei driver
Poiché ogni azione eseguita dallo strumento nella memoria in modalità kernel si basa su un driver vulnerabile per leggere/scrivere contenuto arbitrario, gli eventi di caricamento dei driver dovrebbero essere esaminati attentamente dal prodotto EDR (o dagli analisti SOC) e generare un avviso per qualsiasi caricamento di driver non comune, o addirittura bloccare i driver vulnerabili noti. Questo ultimo approccio è addirittura [raccomandato da Microsoft stessa](https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-driver-block-rules): qualsiasi dispositivo Windows con HVCI (*Hypervisor-protected code integrity*) abilitato incorpora una lista di blocco dei driver, e questo diventerà progressivamente un comportamento predefinito su Windows (lo è già su Windows 11).
### Verifiche dell'integrità della memoria del kernel
Poiché un attaccante potrebbe comunque utilizzare un driver vulnerabile sconosciuto per eseguire le stesse azioni in memoria, il driver EDR potrebbe periodicamente verificare che i suoi callback del kernel siano ancora registrati, sia ispezionando direttamente la memoria del kernel (come fa questo strumento), sia semplicemente attivando eventi (creazione di processi, creazione di thread, caricamento di immagini, ecc.) e controllando che le funzioni di callback siano effettivamente chiamate dal kernel esecutivo.
Come nota a margine, questo tipo di struttura dati potrebbe essere protetta tramite il recente meccanismo [Kernel Data Protection (KDP)](https://www.microsoft.com/security/blog/2020/07/08/introducing-kernel-data-protection-a-new-platform-security-technology-for-preventing-data-corruption/), che si basa sulla sicurezza basata su Virtual Based Security, al fine di rendere l'array di callback del kernel non scrivibile senza chiamare le API giuste.
La stessa logica potrebbe applicarsi a variabili ETW sensibili come `ProviderEnableInfo`, abusato da questo strumento per disabilitare la generazione di eventi ETW Threat Intelligence.
### Rilevamento in modalità utente
Il primo indicatore che un processo sta attivamente cercando di eludere l'hooking a livello utente è l'accesso ai file per ogni DLL corrispondente ai moduli caricati; in un'esecuzione normale, un processo in spazio utente raramente ha bisogno di leggere file DLL al di fuori di una chiamata `LoadLibrary`, specialmente `ntdll.dll`.
Per proteggere l'API hooking dall'essere aggirato, i prodotti EDR potrebbero controllare periodicamente che gli hook non vengano alterati in memoria, all'interno di ciascun processo monitorato.
Infine, per rilevare il bypass dell'hooking (abuso di un trampolino, uso di syscall dirette, ecc.) che non implichi la rimozione degli hook, i prodotti EDR potrebbero potenzialmente fare affidamento su callback del kernel associati alle syscall abusate (es. `PsCreateProcessNotifyRoutine` per la syscall `NtCreateProcess`, `ObRegisterCallbacks` per la syscall `NtOpenProcess`, ecc.) ed eseguire un'analisi dello stack di chiamate in modalità utente per determinare se la syscall è stata attivata da un percorso normale (`kernel32.dll` -> `ntdll.dll` -> syscall) o da uno anomalo (es. `program.exe` -> syscall diretta).
## Riconoscimenti
- Enumerazione e rimozione dei callback del kernel:
https://github.com/br-sn/CheekyBlinder
- Primitive di lettura/scrittura della memoria del kernel tramite il driver vulnerabile
`Micro-Star MSI Afterburner`:
https://github.com/Barakat/CVE-2019-16098/
- Disabilitazione del provider ETW Threat Intelligence:
https://public.cnotools.studio/bring-your-own-vulnerable-kernel-driver-byovkd/exploits/data-only-attack-neutralizing-etwti-provider
- Installazione/disinstallazione del driver: https://github.com/gentilkiwi/mimikatz
- Elenco iniziale dei nomi dei driver EDR:
https://github.com/SadProcessor/SomeStuff/blob/master/Invoke-EDRCheck.ps1
- Bypass di Credential Guard riabilitando `Wdigest` tramite patching della memoria di `LSASS`:
https://teamhydra.blog/2020/08/25/bypassing-credential-guard/
## Autori
[Thomas DIOT (Qazeer)](https://github.com/Qazeer/)
[Maxime MEIGNAN (themaks)](https://github.com/themaks)
## Licenza
Licenza CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/