|
Bitdefender Hypervisor Memory Introspection
|
This file handles token steal detection and token privilege protection. More...
#include "wintoken.h"#include "winprocess.h"#include "winprocesshp.h"#include "decoder.h"#include "hook.h"#include "drivers.h"#include "alerts.h"#include "winpool.h"#include "gpacache.h"Go to the source code of this file.
Functions | |
| static INTSTATUS | IntWinTokenPrivsHandleWrite (void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action) |
| EPT callback triggered when a write occurs over the Privileges bitfields in a nt!_TOKEN structure protected through EPT. More... | |
| static void | IntWinTokenPrivsSendEptAlert (EXCEPTION_KM_ORIGINATOR *Originator, EXCEPTION_VICTIM_ZONE *Victim, INTRO_ACTION Action, INTRO_ACTION_REASON Reason) |
| Sends an EVENT_EPT_VIOLATION for a token privileges violation. More... | |
| static void | IntWinTokenPrivsSendIntegrityAlert (EXCEPTION_VICTIM_ZONE *Victim, INTRO_ACTION Action, INTRO_ACTION_REASON Reason) |
| Sends an EVENT_INTEGRITY_VIOLATION when checks over the token privileges have failed. More... | |
| static BOOLEAN | IntWinTokenPrivsShouldHook (WIN_PROCESS_OBJECT *Process, QWORD NewTokenPtr) |
| Decides if the given token address should be hooked through EPT or not. More... | |
| static INTSTATUS | IntWinTokenProtectPrivsInternal (WIN_PROCESS_OBJECT *Process, QWORD NewTokenPtr) |
| If needed, this function will establish an EPT hook on the given token pointer for privileges protection. Note that, this function might get called in the case where Process->OriginalTokenPtr != NewTokenPtr, in order to re-establish the hook in the case where the token pointer has changed between timer ticks. More... | |
| static INTSTATUS | IntWinTokenFetchTokenAddress (WIN_PROCESS_OBJECT *Process, QWORD *OldValue, QWORD *NewValue) |
| Fetches the token pointer from inside the EPROCESS and returns the old token pointer and the new token pointer which may have changed at the time of the read. More... | |
| BOOLEAN | IntWinTokenPtrIsStolen (WIN_PROCESS_OBJECT *Process, BOOLEAN Check, WIN_PROCESS_OBJECT **FromProcess, QWORD *OldValue, QWORD *NewValue) |
| This function checks if the security token of a given process has been stone from another process. More... | |
| INTSTATUS | IntWinTokenPtrCheckIntegrityOnProcess (WIN_PROCESS_OBJECT *Process) |
| This function checks if the security token of a given process has been stone from another process. More... | |
| INTSTATUS | IntWinTokenCheckCurrentPrivileges (WIN_PROCESS_OBJECT *Process, QWORD TokenPtr, BOOLEAN *PresentIncreased, BOOLEAN *EnabledIncreased, QWORD *Present, QWORD *Enabled) |
| Verifies the current token if the current Privileges.Present and Privileges.Enabled fields were not altered in a malicious way. More... | |
| INTSTATUS | IntWinTokenPrivsCheckIntegrityOnProcess (WIN_PROCESS_OBJECT *Process) |
| This function checks if the privileges bitfields for the given process have been changed in a malicious manner, sending an alert if needed. More... | |
| TIMER_FRIENDLY INTSTATUS | IntWinTokenCheckIntegrity (void) |
| This function checks the integrity of the security token for all the processes inside gWinProcesses. The checks include both verifying if there are token pointers belonging to multiple processes, indicating a stolen token, and verifying if the Token Privileges have not changed in a malicious way, indicating a privilege escalation. More... | |
| INTSTATUS | IntWinTokenPrivsProtectOnProcess (WIN_PROCESS_OBJECT *Process) |
| Updates the stored original Privileges bitfields (Present and Enabled) and hooks through EPT the Privileges inside the assigned token of the given process, if needed. More... | |
| INTSTATUS | IntWinTokenPrivsUnprotectOnProcess (WIN_PROCESS_OBJECT *Process) |
| INTSTATUS | IntWinTokenProtectPrivs (void) |
| Protects all the currently unprotected tokens belonging to processes against privileges manipulation. More... | |
| INTSTATUS | IntWinTokenUnprotectPrivs (void) |
| Unprotects all the currently protected tokens belonging to processes against privileges manipulation. More... | |
Variables | |
| LIST_HEAD | gWinProcesses |
| The list of all the processes inside the guest. More... | |
This file handles token steal detection and token privilege protection.
This module will assure, through integrity protection, once every second, that there are no tokens which are assigned to two processes simultaneously. If two processes share the same token, it means that either some rootkit or some kernel exploit leveraging some arbitrary writes has stolen a token (most probably a more privileged one) and assigned it to a malicious process. In this case, the introspection engine will raise an alert. Moreover, the privileges field in the token structures are protected against modifications. Note that, due to some privilege escalation, a process might exploit some vulnerability such that the assigned privileges are increased, for example CVE-2020-0796 leverages such a vulnerability in the srv2.sys driver so that it gains SYSTEM privileges. The privileges protection is available, due to performance reasons, only on dynamically detected processes (e.g. processes that start after introspection engine initializes), or on all processes on systems which support sub page protection (SPP). The performance improvement in this case is provided by the fact that, once introspection engine initializes, all the token allocations are forced to one page, thus there will not be extra exits outside the protected structure. It is also worth mentioning that dynamic processes can have tokens which are allocated before introspection engine initialization. For this purpose we will check that those allocations have the size of a 4kb page. Note that, on static detected processes introspection engine will verify the assigned privileges to every process once every second, through the integrity mechanism, but due to the fact that, on detection, the LPE has already been executed and the vulnerability leveraged, the introspection engine cannot enforce protection in these case, meaning that rewriting the privileges would be futile, since the process had very high privileges for around 1 second, which is more than enough to provoke damage and enforce persistence on the system. The checks performed on integrity on privileges are:
Definition in file wintoken.c.
| INTSTATUS IntWinTokenCheckCurrentPrivileges | ( | WIN_PROCESS_OBJECT * | Process, |
| QWORD | TokenPtr, | ||
| BOOLEAN * | PresentIncreased, | ||
| BOOLEAN * | EnabledIncreased, | ||
| QWORD * | Present, | ||
| QWORD * | Enabled | ||
| ) |
Verifies the current token if the current Privileges.Present and Privileges.Enabled fields were not altered in a malicious way.
The checks performed on integrity on privileges are:
| [in] | Process | The process for which the checks are done. |
| [in] | TokenPtr | The GVA which points to the assigned token, may be different from Process->OriginalTokenPtr. |
| [out] | PresentIncreased | It will store a boolean representing whether the current privileges violate the first check. |
| [out] | EnabledIncreased | It will store a boolean representing whether the current privileges violate the second check. |
| [out] | Present | The current value in the Privileges.Present field. |
| [out] | Enabled | The current value in the Privileges.Enabled field. |
| INT_STATUS_SUCCESS | On success. |
| INT_STATUS_INVALID_PARAMETER_1 | If a NULL Process has been given. |
| INT_STATUS_INVALID_PARAMETER_3 | If a NULL PresentIncreased has been given. |
| INT_STATUS_INVALID_PARAMETER_4 | If a NULL EnabledIncreased has been given. |
Definition at line 696 of file wintoken.c.
Referenced by IntWinDpiValidateTokenPrivs(), and IntWinTokenPrivsCheckIntegrityOnProcess().
| TIMER_FRIENDLY INTSTATUS IntWinTokenCheckIntegrity | ( | void | ) |
This function checks the integrity of the security token for all the processes inside gWinProcesses. The checks include both verifying if there are token pointers belonging to multiple processes, indicating a stolen token, and verifying if the Token Privileges have not changed in a malicious way, indicating a privilege escalation.
| INT_STATUS_SUCCESS | On success. |
Definition at line 942 of file wintoken.c.
Referenced by IntHandleTimer().
|
static |
Fetches the token pointer from inside the EPROCESS and returns the old token pointer and the new token pointer which may have changed at the time of the read.
Note: the returned old value and new value can be the same, one should check those value after calling this function in order to ensure that the token pointer has changed. If the change is considered alright, one should update Process->OriginalTokenPtr after calling this function.
| [in] | Process | The WIN_PROCESS_OBJECT for which new token should be fetched. |
| [out] | OldValue | The old token pointer, stored internally in OriginalTokenPtr field of WIN_PROCESS_OBJECT. |
| [out] | NewValue | The value fetched from the Token field of the given EPROCESS inside the guest. |
| INT_STATUS_SUCCESS | On success. |
| INT_STATUS_PAGE_NOT_PRESENT | If the eprocess is not present in memory and the token cannot be read. |
Definition at line 449 of file wintoken.c.
Referenced by IntWinTokenPrivsCheckIntegrityOnProcess(), and IntWinTokenPtrIsStolen().
| INTSTATUS IntWinTokenPrivsCheckIntegrityOnProcess | ( | WIN_PROCESS_OBJECT * | Process | ) |
This function checks if the privileges bitfields for the given process have been changed in a malicious manner, sending an alert if needed.
| [in] | Process | The WIN_PROCESS_OBJECT for which the privileges are checked in the assigned token. |
| INT_STATUS_SUCCESS | On success. |
Definition at line 818 of file wintoken.c.
Referenced by IntWinProcCreateProcessObject(), IntWinProcDeleteProcessObject(), and IntWinTokenCheckIntegrity().
|
static |
EPT callback triggered when a write occurs over the Privileges bitfields in a nt!_TOKEN structure protected through EPT.
| [in] | Context | The process for which the given nt!_TOKEN structure has been associated with. |
| [in] | Hook | The GPA_HOOK structure which was set on the given token. |
| [in] | Address | The guest physical address on which the write took place. |
| [out] | Action | The action decided by the engine for the current violation. |
| INT_STATUS_SUCCESS | On success. |
| INT_STATUS_NOT_FOUND | If a process is not given as Context. |
Definition at line 322 of file wintoken.c.
Referenced by IntWinTokenProtectPrivsInternal().
| INTSTATUS IntWinTokenPrivsProtectOnProcess | ( | WIN_PROCESS_OBJECT * | Process | ) |
Updates the stored original Privileges bitfields (Present and Enabled) and hooks through EPT the Privileges inside the assigned token of the given process, if needed.
| [in,out] | Process | The WIN_PROCESS_OBJECT for which the privileges information is stored, and for which a hook would be established on the assigned token, if needed. |
| INT_STATUS_SUCCESS | On success. |
| INT_STATUS_INVALID_PARAMETER_1 | If the given process is NULL. |
Definition at line 1008 of file wintoken.c.
Referenced by IntWinProcCreateProcessObject(), and IntWinTokenProtectPrivs().
|
static |
Sends an EVENT_EPT_VIOLATION for a token privileges violation.
| [in] | Originator | The originator driver which has written over the privileges. |
| [in] | Victim | Describes the victim of the given violation. |
| [in] | Action | The action which was decided to be taken by the exceptions engine. |
| [in] | Reason | The reason why the given action was given. |
Definition at line 64 of file wintoken.c.
Referenced by IntWinTokenPrivsHandleWrite().
|
static |
Sends an EVENT_INTEGRITY_VIOLATION when checks over the token privileges have failed.
| [in] | Victim | The victim, which is denoted by the process for which the privileges are increased. |
| [in] | Action | The action taken by the exceptions engine. |
| [in] | Reason | The reason for which the given action has been taken. |
Definition at line 116 of file wintoken.c.
Referenced by IntWinTokenPrivsCheckIntegrityOnProcess().
|
static |
Decides if the given token address should be hooked through EPT or not.
The decision is taken based on various considerations. If we have hardware support for sub page protection, we will always hook the tokens through EPT, as the impact will be much lower, even lower that with the "force allocation to page size" trick. On static detected processes, most likely the token was allocated before. On dynamically detected processes we will check if the token has been allocated with one page size, in which case we will hook the given token through EPT.
| [in] | Process | The WIN_PROCESS_OBJECT for which the token would be decided if it should be protected or not. |
| [in] | NewTokenPtr | The given token pointer. |
| TRUE | If the given token pointer should be hooked through EPT for the privileges protection. |
| FALSE | If protecting the given token through EPT would induce a high performance impact. |
Definition at line 171 of file wintoken.c.
Referenced by IntWinTokenProtectPrivsInternal().
| INTSTATUS IntWinTokenPrivsUnprotectOnProcess | ( | WIN_PROCESS_OBJECT * | Process | ) |
Definition at line 1069 of file wintoken.c.
Referenced by IntWinProcRemoveProcess().
| INTSTATUS IntWinTokenProtectPrivs | ( | void | ) |
Protects all the currently unprotected tokens belonging to processes against privileges manipulation.
| INT_STATUS_SUCCESS | On success. |
| INT_STATUS_NOT_NEEDED_HINT | If the option INTRO_OPT_PROT_KM_TOKEN_PRIVS is not activated. |
Definition at line 1094 of file wintoken.c.
Referenced by IntGuestUpdateCoreOptions().
|
static |
If needed, this function will establish an EPT hook on the given token pointer for privileges protection. Note that, this function might get called in the case where Process->OriginalTokenPtr != NewTokenPtr, in order to re-establish the hook in the case where the token pointer has changed between timer ticks.
| [in] | Process | The process for which the token should be protected or not. |
| [in] | NewTokenPtr | The address of the token for which the privileges would be protected. |
| INT_STATUS_SUCCESS | On success. |
Definition at line 267 of file wintoken.c.
Referenced by IntWinTokenPrivsCheckIntegrityOnProcess(), IntWinTokenPrivsHandleWrite(), and IntWinTokenPrivsProtectOnProcess().
| INTSTATUS IntWinTokenPtrCheckIntegrityOnProcess | ( | WIN_PROCESS_OBJECT * | Process | ) |
This function checks if the security token of a given process has been stone from another process.
| [in] | Process | The process whose token has to be verified. |
| INT_STATUS_SUCCESS | On success. |
Definition at line 604 of file wintoken.c.
Referenced by IntWinProcCreateProcessObject(), IntWinProcDeleteProcessObject(), IntWinTokenCheckIntegrity(), and IntWinTokenPrivsHandleWrite().
| BOOLEAN IntWinTokenPtrIsStolen | ( | WIN_PROCESS_OBJECT * | Process, |
| BOOLEAN | Check, | ||
| WIN_PROCESS_OBJECT ** | FromProcess, | ||
| QWORD * | OldValue, | ||
| QWORD * | NewValue | ||
| ) |
This function checks if the security token of a given process has been stone from another process.
| [in] | Process | The process who`s token has to be verified. |
| [in] | Check | If TRUE, gWinProcesses will be iterated to see if the token value is the same for another process (same thing happens if the original token pointer has been modified). |
| [out] | FromProcess | The process where the token has been stolen from. |
| [out] | OldValue | The old token. |
| [out] | NewValue | The new token. |
| TRUE | The given process has a stolen token. |
| FALSE | The given process has its original token. |
Definition at line 510 of file wintoken.c.
Referenced by IntWinDpiValidateParentProcessToken(), and IntWinTokenPtrCheckIntegrityOnProcess().
| INTSTATUS IntWinTokenUnprotectPrivs | ( | void | ) |
Unprotects all the currently protected tokens belonging to processes against privileges manipulation.
| INT_STATUS_SUCCESS | On success. |
| INT_STATUS_NOT_NEEDED_HINT | If the option INTRO_OPT_PROT_KM_TOKEN_PRIVS is in fact activated. |
Definition at line 1135 of file wintoken.c.
Referenced by IntGuestUpdateCoreOptions().
| LIST_HEAD gWinProcesses |
The list of all the processes inside the guest.
Definition at line 11 of file winprocesshp.c.