Produit

Comment les attaquants abusent de la manipulation des jetons d’accès (ATT&CK T1134)

Dans notre précédent article sur les jetons d’accès Windows pour les professionnels de la sécurité, nous avons abordé :

  • La relation entre les sessions de connexion et les jetons d’accès
  • Comment fonctionne l’authentification réseau dans les environnements Windows

Après avoir abordé certains des concepts clés de la sécurité de Windows, nous allons maintenant nous appuyer sur ces connaissances et commencer à étudier comment les attaquants peuvent abuser des fonctionnalités légitimes de Windows pour se déplacer latéralement et compromettre les domaines Active Directory.

Cet article essaie volontairement de faire abstraction du fonctionnement de certains protocoles d’authentification réseau Windows (par exemple, NTLM et Kerberos) dans la mesure du possible. Par conséquent, dans certains cas, le comportement propre à ces protocoles peut différer de celui décrit ci-dessous. Cela suppose également une certaine compréhension de base du protocole d’authentification Kerberos 1.

De plus, le contenu de cette série d’articles a été utilisé pour une présentation de BlackHat 2020, intitulée « Detecting Access Token Manipulation » (Détection des manipulations de jetons d’accès). La présentation se trouve ici et les slides ici.

Manipulation des jetons d’accès (technique ATT & CK : T1134)

Après avoir expliqué les principes de base du fonctionnement des sessions de connexion et des jetons d’accès dans notre précédent article, à la fois en local et pour les applications distribuées, cette section expliquera comment les attaquants peuvent abuser des jetons d’accès et cibler les relations de confiance fondamentales dans les domaines Windows afin de compromettre des réseaux entiers. Le but de cette section est de décrire les techniques de manipulation des jetons d’accès utilisées par les attaquants dans le cadre d’une simulation de compromission

.

À noter, il existe déjà de nombreuses excellentes études sur la manipulation des jetons d’accès (vers lesquelles vous trouverez de nombreux liens tout au long de cet article). Cet article tente de tirer parti de cet ensemble de connaissances en envisageant la manipulation des jetons d’accès sous un angle différent, à savoir la relation entre les jetons d’accès, les sessions de connexion et les informations d’identification mises en cache. De l’avis de l’auteur, toute description d’une manipulation symbolique sans tenir compte de ces relations ne représente que la partie visible de l’iceberg. Par conséquent, la définition de la manipulation des jetons d’accès donnée par cet article est peut-être bien plus large que ce que l’on pense généralement.

Compromis initial

Si un attaquant entre dans un réseau par le biais du spear phishing, il se retrouve généralement avec un shell qui s’exécute dans le contexte de sécurité de l’utilisateur compromis. Cela peut être réalisé en créant un nouveau processus ou en l’injectant directement dans la mémoire (selon la charge utile), mais le résultat final est le même : le code de l’attaquant s’exécute dans un processus qui possède un jeton d’accès appartenant à l’ 

utilisateur compromis.

Cela signifie que tout contrôle d’accès local utilisera le jeton d’accès de l’utilisateur compromis et que toute tentative d’authentification à distance utilisera les informations d’identification mises en cache de l’utilisateur compromis2. L’attaquant peut donc, à la fois localement et sur le réseau, effectuer toutes les actions possibles de l’utilisateur compromis. Par exemple, si des applications Web internes utilisent le SSO de Windows, un attaquant pourra y accéder comme s’il en était l’utilisateur

.

Manipulation de jetons : « l’art du possible »

En général, un attaquant souhaite passer du terminal compromis à un autre hôte le plus rapidement possible3. Si l’on considère les mouvements latéraux du point de vue de la manipulation des jetons, l’attaquant dispose en fait de trois options, 4, chacune étant limitée par la relation fondamentale entre les jetons d’accès, les sessions de connexion et les informations d’identification mises en cache, comme illustré ci-dessous

 :

1-access-tokens-logon-sessions-blog-access-token-manipulation.png

Illustration 1 - La relation entre les jetons d’accès, les sessions de connexion et les informations d’identification mises en cache
.


Si un attaquant veut se déplacer latéralement via Windows SSO, ces trois conditions doivent être réunies (par exemple, il doit disposer d’un identifiant permettant d’accéder à un jeton lié à une session de connexion utilisant les identifiants de sa cible). Sinon, la liberté de mouvement d’un attaquant repose soit sur la création de nouveaux liens (par exemple, de nouvelles sessions de connexion), soit sur la modification de liens existants (par exemple, la modification des informations d’identification mises en cache ou de la session de connexion vers laquelle pointe son jeton d’accès). Ces contraintes sont abordées plus en détail dans les trois options ci-dessous :

1. Voler le jeton d’un utilisateur privilégié déjà connecté (connexion hors réseau)

Si un autre utilisateur privilégié est déjà connecté à l’hôte compromis, un attaquant peut augmenter ses privilèges et obtenir l’identifiant d’un jeton d’accès représentant cet utilisateur. Que l’attaquant se fasse passer pour le jeton volé ou qu’il lance un nouveau processus, si ce jeton est lié à une session de connexion hors réseau, ses informations d’identification seront mises en cache. L’attaquant pourra donc s’authentifier automatiquement auprès d’un autre hôte 5. Cette technique permet donc à un attaquant d’utiliser les informations d’identification d’un autre utilisateur pour accéder à des hôtes distants sur le réseau (via Windows SSO), et donc de pivoter sans avoir à vider ses informations d’identification6

.

À noter que les attaques par manipulation de jetons ont généralement deux objectifs distincts : se déplacer latéralement (ce qui concerne le présent article) et augmenter les privilèges au niveau local7. Le vol de jetons a tendance à être associé à ce dernier (par exemple, le vol ou l’usurpation d’identité d’un jeton dans le but de contourner les contrôles d’accès locaux, plutôt que d’utiliser les informations d’identification mises en cache pour l’authentification à distance). Cet article n’en parlera donc pas plus en détail, mais les ressources suivantes sont utiles pour en

savoir plus : https://labs.f-secure.com/assets/BlogFiles/mwri-security-implications-of-windows-access-tokens-2008-04-14.pdf

2. Créer une nouvelle session de connexion avec des informations d’identification volées et usurper l’identité du jeton renvoyé ou lancer un nouveau processus.

Dans ce cas, aucun utilisateur privilégié n’est déjà connecté (et donc aucun jeton d’accès/session de connexion utile correspondant), mais l’attaquant doit tout de même trouver un moyen de modifier son contexte de sécurité

.

L’attaquant doit donc trouver des identifiants de connexion ailleurs et les utiliser pour créer une nouvelle session de connexion en tant qu’utilisateur compromis. Comme Windows met automatiquement en cache les informations d’identification pour certains types de connexion, l’attaquant peut désormais obtenir un nouveau jeton d’accès qui est sauvegardé par les informations d’identification volées. Une fois que l’attaquant a identifié un jeton représentant l’utilisateur compromis, il peut s’authentifier immédiatement en utilisant le processus SSO standard de Windows

.

Les attaquants trouvent généralement des identifiants de connexion en texte brut via Kerberoasting ou en les recherchant en texte brut non sécurisés sur toutes les ressources accessibles, telles que les partages réseau, Sharepoint, les wikis internes, GitHub d’entreprise, Zendesk, etc. 8

3. Remplacer les identifiants de connexion mis en cache associés à leur jeton d’accès actuel par des données volées (par exemple, légitimement via une API ou « illégitimement » en modifiant directement la mémoire lsass)

Dans ce scénario, plutôt que de créer une nouvelle session de connexion, l’attaquant modifie les identifiants de connexion mis en cache associés à son jeton d’accès actuel (et donc à sa session de connexion). Comme nous allons le voir, de nombreux fournisseurs de support de sécurité (SSP) Windows proposent des méthodes natives pour le faire (et qui ne nécessitent pas de privilèges élevés)

.

Les attaquants peuvent également suivre la voie « directe » et modifier manuellement les identifiants de connexion mis en cache stockés dans lsass. Cela nécessite des privilèges élevés pour obtenir un descripteur d’écriture (par exemple, PROCESS_VM_WRITE) pour lsass via OpenProcess. C’est typique des attaques de type « pass-the-hash », comme nous le verrons plus loin.

Attaques par manipulation des jetons d’accès

Cet article aborde quatre techniques couramment utilisées par les attaquants (qui peuvent toutes être classées comme des variantes de l’option 3 ci-dessus) :

  • le drapeau NETONLY Pass-The-Ticket Pass-The-Hash
  • Overpass-The-Hash 1
.

Le drapeau NETONLY L’API Windows fournit la fonction LogonUser qui permet de créer une nouvelle session de connexion pour un utilisateur (ou principal) donné9 :

BOOL LogonUserW (
LPCWSTR LPSZUserName,
LPCWSTR LPSZDomain,
LPCWSTR LPSZPassword,
DWORD DWLogonType,
DWORD DWLogonProvider,
PHANDLE PHToken) ;

le paramètre clé à prendre en compte ici est le DWLogonType, qui spécifie le type de connexion à effectuer. Par exemple, si un utilisateur se connecte physiquement à son poste de travail, celui-ci sera réglé sur LOGON32_LOGON_INTERACTIVE. Le type de connexion spécifié déterminera le type et les privilèges du jeton renvoyé

.

Par exemple, dans le cas d’une connexion interactive, LogonUserW renverra un jeton d’accès principal et, si l’UAC est activé, ce jeton sera un jeton filtré (ce qui signifie que son intégrité sera moyenne et non élevée). Il y a une exception : si l’utilisateur possède un compte administrateur local (par exemple, un SID *-500), Windows renverra automatiquement un jeton 10 élevé.

Dans le cas d’une connexion réseau (LOGON32_LOGON_NETWORK), un jeton d’usurpation d’identité est renvoyé (car il est généralement utilisé par un serveur pour effectuer des tâches pour le compte de clients distants). De plus, si l’utilisateur fait partie du groupe d’administrateurs local, le jeton est élevé et tous les privilèges sont activés11

Ces permutations de LogonUser sont répertoriées dans le tableau ci-dessous : Le jeton DWLogonType a

d’identité Non 12

renvoyé des informations de cache ?

Le jeton retourné est-il élevé ?

(si administrateur) Interactif (LOGON32_LOGON_INTERACTIVE) Principal Oui Non (l’UAC s’applique) Interactif (compte administrateur local, par exemple, RID-500)

Principal Oui Oui Réseau (LOGON32_LOGON_NETWORK)

Usurpation

Oui (+ tous les privilèges sont activés) Réseau (compte administrateur local, par exemple, RID-500) L’usurpation d’identité

dépend des paramètres UAC de la télécommande13

Tableau 1 - Les permutations de LogonUser pour le DWLogonType correspondant.


L’essentiel est que LogonUser

renvoie un identifiant à un jeton récemment créé, qui peut désormais être utilisé pour

usurper l’identité.

Si le jeton renvoyé est un jeton principal, il doit d’abord être converti en jeton d’usurpation d’identité via DuplicateTokenEx en transmettant un TokenType de TokenImpersonate 14 : BOOL, DuplicateTokenEx (
HANDLE,
HExistingToken,
DWORD,
DWDesiredAccess
,
LPSECURITY_ATTRIBUTES,
LPTokenAttributes,

 


SECURITY_IMPERSONATION_LEVEL (ImpersonationLevel,
TOKEN_TYPE,
TOKENtype,
PHANDLE,
PHNewToken) ; la fonction SetThreadToken peut ensuite être utilisée pour attribuer le jeton d’usurpation d’identité renvoyé au fil de discussion en cours :

 

BOOL SetThreadToken (
PHANDLE Thread,
HANDLE Token) ; sinon, l’API Windows fournit la fonction ImpersonateLoggedOnUser, qui permet au thread appelant de se faire passer pour le contexte de sécurité de l’utilisateur

représenté par le jeton transmis :

BOOL
ImpersonateLoggedOnUser (HANDLE hToken) ; ImpersonateLoggedOnUser a l’

avantage supplémentaire de vérifier automatiquement le type de jeton transmis et le convertit en jeton d’usurpation d’identité (via NTDuplicateToken) si un jeton principal a été transmis (car ce type de jeton ne peut pas être utilisé par un fil de discussion pour se faire passer pour un utilisateur) 15.

Notez que du point de vue de la défense, ces deux API d’usurpation d’identité sont des enveloppes légères qui recoupent l’appel système non documenté NTSetInformationThread (par exemple, appelé avec une classe ThreadInformationClass de ThreadImpersonationToken). C’est donc une bonne cible pour les attaquants qui utilisent des appels système directs pour contourner les hooks en mode utilisateur grâce à des techniques telles que https://github.com/jthuraisamy/SysWhispers.

En outre, il est important de souligner que Windows applique des règles strictes en matière d’usurpation d’identité. Elles sont répertoriées ci-dessous et extraites de la page MSDN de ImpersonateLoggedOnUser : Toutes les fonctions d’usurpation d’identité, y compris ImpersonateLoggedonUser

, autorisent l’usurpation d’identité demandée si l’une des conditions suivantes est vraie :
- Le niveau d’usurpation d’identité demandé du jeton est inférieur à SecurityImpersonation, comme SecurityIdentification ou SecurityAnonymous
- L’appelant possède le privilège SeImpersonatePrivilege.
- Un processus (ou un autre processus de la session de connexion de l’appelant) a créé le jeton à l’aide d’informations d’identification explicites via la fonction LogonUser ou LSAlogonUser.

L’identité authentifiée est la même que celle de l’appelant. De plus, le niveau d’intégrité du jeton usurpé doit également être inférieur ou égal au niveau d’intégrité du processus d’appel, sinon l’appel d’usurpation d’identité échouera également 16. Par conséquent, en supposant qu’un attaquant de niveau inférieur se connecte à un administrateur de manière interactive via des identifiants de connexion volés et que l’UAC soit activé, il recevra un jeton non élevé (filtré) et n’aura donc aucun problème à se faire passer pour l’utilisateur renvoyé et à se déplacer latéralement, etc.

« Le curieux drapeau /NETONLY » 17. Un attaquant peut toutefois constater que la

tentative de connexion d’un utilisateur avec des identifiants de connexion volés échoue.

Cela peut être dû à une multitude de raisons, telles que la validité des identifiants de connexion, mais le compte n’est pas autorisé à se connecter à cette station de travail en particulier, mais ils ne sont valables que dans un autre domaine, etc. En outre, l’attaquant peut également éviter de se connecter à un compte hautement privilégié, car cela peut sembler très anormal dans certains contextes (par exemple, un administrateur de domaine qui se connecte à l’hôte d’un utilisateur professionnel peu privilégié devrait être extrêmement méfiante). 18. Dans ce scénario, le drapeau LOGON32_LOGON_NEW_CREDENTIALS vient à la rescousse de l’attaquant. Si un attaquant appelle la fonction LogonUserW avec cet indicateur et transmet un ensemble d’informations d’identification valides (par exemple, en fouillant les partages de fichiers), Windows permettra à l’appelant de dupliquer son jeton actuel en le renvoyant vers une nouvelle session de connexion, appelée session de connexion New Credentials, qui met en cache les informations d’identification volées.

Par conséquent, l’utilisateur a toujours le même contexte de sécurité en local (par exemple, il possède toujours une copie du même jeton d’accès ; cela indique simplement une nouvelle session de connexion). Cependant, toute tentative d’authentification à distance fournira les nouvelles informations d’identification transmises lors de l’appel à LogonUserw 19. Ceci est illustré dans le schéma ci-dessous :

2-logon-new-credentials-blog-access-token-manipulation.gif

Illustration 2 - Fonctionnement du drapeau LOGON32_LOGON_NEW_CREDENTIALS en arrière-plan. Le drapeau LOGON32_LOGON_NEW_CREDENTIALS fournit un


mécanisme natif pour définir votre accès

actuel les jetons pointent vers une autre session de connexion et donc des informations d’identification différentes .20.

Notez qu’appeler LogonUserW avec l’indicateur LOGON32_LOGON_NEW_CREDENTIALS ne valide pas les informations d’identification au moment de l’appel (elles peuvent être totalement indésirables), mais ne sont validées que par un contrôleur de domaine au moment de toute demande d’authentification

à distance.

Autre exemple, une rapide revue du code de la tâche « MakeToken » depuis le code source ouvert. Le framework NET C2 Covenant adopte exactement la même approche : il utilise une combinaison nom d’utilisateur/mot de passe et crée une nouvelle session de connexion avec ce dernier en transmettant l’indicateur LOGON32_LOGON_NEW_CREDENTIALS avant de se faire passer pour le jeton

renvoyé.

De plus, vous pouvez reproduire exactement le même comportement avec CreateProcessWithLogonW en transmettant un DWLogonFlags de LOGON_NETCREDENTIALS_ONLY. 21

BOOL CreateProcessWithLogonOne (
LPCWSTR LPusername,
LPCWSTR LPDomain,
LPCWSTR LPPassword,
DWORD DWLogonFlags,
LPCWSTR LPApplicationName,
LPWSTR LPCommandline,
DWORD DWCreationFlags,
LPVOID LPEnvironment,
LPCWSTR LPCurrentDirectory,
LPStartuPInfoW LPStartupInfo,
LPPROCESS_INFORMATION
LPProcessInformation) ; La principale différence est qu’il s’agit de créer un nouveau processus avec le jeton renvoyé, par opposition à l’usurpation
d’identité en cours de processus

comme vu précédemment. En fait, l’utilitaire Windows intégré Runas est un simple wrapper autour de CreateProcessWithLogonW et le drapeau /NETONLY fournit un moyen natif de générer un nouveau processus avec des informations d’identification différentes uniquement sur le réseau, comme indiqué ci-dessous : Illustration 3 - Exemple d’utilisation du runas

3-using-the-runas-blog-access-token-manipulation.png

/NETONLY exécute l’indicateur pour créer un nouveau processus en tant qu’utilisateur astro \ cosmo, mais avec des informations d’identification mises en cache différentes.


Exactement comme décrit précédemment, la nouvelle invite de commande semble être exécutée localement par le même utilisateur (c’est-à-dire que les attributs mis en cache dans le jeton sont les mêmes pour tous les contrôles d’accès locaux ; whoami renvoie donc « astro \ cosmos »), mais toutes les tentatives d’authentification à distance seront effectuées à l’aide des identifiants de connexion volés pour l’utilisateur « ASTRO \ Administrator ». 

Ces sessions de connexion peuvent être consultées à l’aide de l’outil LogonSessions de SysInternals.

Les sessions d’ouverture de session créées avec l’indicateur NewCredentials peuvent être déterminées à l’aide du champ Type de connexion, comme indiqué ci-dessous : 4-logon-session-blog-access-token-manipulation.png

Illustration 4 - Exemple de session de connexion NewCredentials généralement générée par le drapeau NETONLY
En outre,

Les sessions de connexion anormales NewCredentials (produites par exemple via le gadget NETONLY) laissent des artefacts dans les journaux des événements Windows. Ils peuvent être identifiés grâce à l’ID d’événement 4642 et à un LogonType de 9. L’image ci-dessous en donne un exemple :

5-windows-event-log-blog-access-token-manipulation.png

Illustration 5 - Exemple de journal des événements Windows pour l’ID d’événement 4624, qui est généralement généré par le drapeau NETONLY.


Notez que l’utilisateur d’origine est indiqué par le champ SubjectUserName et et que seuls

les identifiants de connexion du réseau spécifié (par exemple, les idnetifiants de connexion transmis) sont affichées dans les champs TargetOutboundUser/DomainName.22

Élévation automatique

Une autre particularité du point de vue de l’augmentation des privilèges locaux est que pour les comptes RID-500, CreateProcessWithLogonW augmentera automatiquement le jeton renvoyé pour les connexions interactives (par exemple, il ignorera l’UAC). Il est donc possible de transmettre à CreateProcessWithLogonW un compte administrateur local/de domaine afin d’exécuter un processus élevé à partir d’un contexte moyen/non élevé

.

Ce comportement peut être vérifié à l’aide de runas. Par exemple, lorsque runas est utilisé pour lancer un processus à l’aide d’un compte d’administrateur local (par exemple, runas /user : "Administrator" cmd.exe), le processus qui en résulte sera amélioré (par exemple, haute intégrité). Cependant, lorsqu’un compte autre que le compte RID-500 est utilisé (mais qu’il appartient toujours au groupe des administrateurs locaux), le processus ne sera pas amélioré (par exemple, il s’agira d’un jeton filtré ou d’une intégrité moyenne)

.

Notez que ce comportement est conforme aux permutations répertoriées pour LogonUserW dans le Tableau 1. Par conséquent, un attaquant non qualifié pourrait également connecter un administrateur (autre que le RID-500) en tant que connexion réseau et recevoir un jeton élevé avec

tous les privilèges activés.

Cependant, conformément aux règles d’usurpation d’identité décrites précédemment, l’attaquant ne devrait pas être en mesure de faire quoi que ce soit avec ce jeton, car toute tentative visant à usurper l’identité d’un jeton élevé devrait échouer, car son niveau d’intégrité est supérieur à celui de l’appelant. Néanmoins, il est possible de dupliquer le jeton élevé, de réduire le niveau d’intégrité du jeton copié à moyen (NB, « IsElevated » est toujours vrai) 23 et de commencer à se faire passer pour le jeton élevé dans un contexte d’intégrité non élevé/moyen 24. Du point de vue des jetons d’usurpation d’identité, vous pouvez contourner le comportement par défaut de Windows qui consiste à ne surclasser que certains comptes et à vous faire passer pour un jeton élevé, qu’il s’agisse d’un compte RID-500

ou non.

Création de processus

Notez que par défaut, lorsque vous créez un processus enfant, il hérite de votre jeton principal, même si vous vous faites passer pour un autre contexte de sécurité. 25. Par exemple, si vous vous faites passer pour un jeton SYSTEM et que vous appelez CreateProcess(), il héritera toujours d’une copie du jeton de processus principal (au lieu d’hériter du contexte de sécurité SYSTEM du thread).26

Par conséquent, si un attaquant souhaite créer un nouveau processus dans un contexte de sécurité différent, il doit soit : utiliser CreateProcessWithLogonW avec des identifiants de connexion explicites (comme indiqué précédemment) Appeler soit CreateProcessWithTokenW

soit CreateProcessAsUserW et transmettre un
  • handle vers un jeton (par exemple, avec le jeton renvoyé par LogonUser ou, plus souvent, via un jeton volé) 

Ces deux fonctions peuvent être transmises un handle à un jeton qui représente le contexte de sécurité du nouveau processus.27

 BOOL CreateProcessWithTokenW (
HANDLE hToken,
DWORD DWLogonFlags,
LPCWSTR LPApplicationName,
LPWSTR LPCommandline,
DWORD DWCreationFlags,
LPVOID LPEnvironment,
LPCWSTR LPCurrentDirectory,
LPSTARTUPINFO,
LPPROCESS_INFORMATION LPProcessInformation) ; BOOL CreateProcessAsUserw (HANDLE hApplicationDirectory,
LPCWSTR LPProcessInformation) ; BOOL CreateProcessAsUserw (HANDLE hApplicationDirectory,
LPCWSTR LPPAgnicationName Nom, LPWSTR LPCommandline, LPSECURITY_ATTRIBUTES LPProcessAttributes
,






LPSECURITY_ATTRIBUTES, LPThreadAttributes, BOOL, BinHeritHandles, DWORD

DWCreationFlags,
LPVOID LPEnvironment,
LPCWSTR, LPCurrentDirectory,
LPSTARTUPINFOW, LPStartupInfo,
LPPROCESS_INFORMATION (LPProcessInformation
) ;

par exemple, CreateProcessAsUserW est généralement utilisé par le système d’exploitation lui-même pour générer le shell de l’utilisateur après une connexion réussie (il est également utilisé par le service de connexion secondaire lorsqu’un utilisateur appelle CreatProcessWithLogonW). En ce sens, cela permet à un utilisateur d’ « injecter un processus dans la session de connexion de son choix » 28. À noter que ces deux API sont des wrappers autour de CreateProcessInternalW

(situé dans KernelBase.dll).

La principale différence, c’est que l’appelant doit disposer de certains privilèges pour appeler ces deux API29. Du point de vue des attaquants, l’objectif est le même : faire exécuter du code dans le contexte de sécurité de l’utilisateur cible afin de se déplacer latéralement

.

Une particularité intéressante est que le framework PowerShell Empire a été contraint d’adopter cette approche de génération de processus (qui est sans doute beaucoup plus bruyante du point de vue de la détection) en raison des limites liées à la façon dont PowerShell gère l’usurpation d’identité et le multithreading, comme l’expliquent les notes ici plus en détail.

Dans tous les cas, le flux de travail lié à l’utilisation des techniques de manipulation de jetons par génération de processus reste le même. Une fois que l’attaquant a obtenu le nom d’utilisateur du jeton (via OpenProcess/OpenProcessToken s’il s’agit du jeton principal, ou OpenThread/ OpenThreadToken dans le cas d’un thread usurpant l’identité), l’attaquant doit appeler DuplicateTokenex pour créer une copie locale (principale) du jeton cible, puis fournir cette copie aux fonctions CreateProcessWithTokenW ou CreateProcessAsUserW

.

Notez que dans ce cas encore, les attaquants ne s’intéressent qu’aux sessions de connexion privilégiées qui ne sont pas des connexions au réseau, car les connexions réseau ne mettent pas en cache les informations d’identification et ne peuvent donc pas s’authentifier auprès d’autres hôtes.

2. Pass-The-Ticket



Windows propose une méthode native pour appliquer une technique très similaire à celle du drapeau NETONLY à l’aide de Kerberos. 30. Cette technique est encore plus puissante dans le sens où elle ne nécessite pas qu’un attaquant crée une nouvelle session de connexion, mais modifie arbitrairement les identifiants Kerberos mis en cache (par exemple, TGT) associés à leur session de connexion (et donc au jeton d’accès actuel), comme démontré ci-dessous :

6-pass-the-ticket-blog-access-token-manipulation.gif

Illustration 6 - Comment fonctionne l’attaque Pass-the-ticket.
Dans cet exemple, l’utilisateur, ASTRO\cosmo, applique le TGT volé de l’utilisateur ASTRO\Administrator à sa session de connexion actuelle.


Pour commencer à interagir avec le SSP Kerberos et gérer le cache de tickets Kerberos, un processus peut appeler LsaCallAuthenticationPackage (situé dans Sspicl.dll) :

NTSTATUS LsaCallAuthenticationPackage( 
HANDLE LsaHandle,
ULONG AuthenticationPackage,
PVOID ProtocolSubmitBuffer,
ULONG SubmitBufferLength,
PVOID *ProtocolReturnBuffer,
PULONG ReturnBufferLength,
PNTSTATUS ProtocolStatus
);

Notez que l’utilisateur devra avoir préalablement appelé LsaConnectUntrusted afin d’obtenir un handle de connexion vers le serveur LSA et LsaLookupAuthenticationPackage pour trouver l’id du paquet kerberos (MICROSOFT_KERBEROS_NAME_A). De plus, l’inspection de ces fonctions dans l’IDA (là encore, elles peuvent être localisées en Sspicl.dll) révèle qu’elles sont connectées à la LSA via le RPC.31.

Grâce à LsaCallAuthenticationPackage, un utilisateur peut effectuer un certain nombre de requêtes sensibles, bien que les demandes exactes disponibles dépendent de leur élévation ou non. Par exemple, un utilisateur non élevé peut effectuer les actions de gestion de tickets debase 32, telles que l’énumération de ses tickets actifs actuels, le nettoyage du cache de tickets et l’application arbitraire de tickets à sa session de connexion 33 actuelle. Ainsi, cela permet effectivement à un utilisateur de modifier les identifiants mis en cache avec sa session de connexion actuelle et de spécifier ainsi des identifiants réseau arbitraires.

De plus, à partir d’un contexteélevé 34, un attaquant peut énumérer et vider des tickets (par exemple, identifiants) appartenant à d’autres utilisateurs, offrant ainsi une fonctionnalité similaire à mimikatz sans avoir besoin d’ouvrir un handle vers lsass35.

Une liste complète des types de messages pouvant être envoyés au package d’authentification Kerberos est disponible ici. Pour modifier le TGT actuel associé à une session de connexion donnée, le KerbSubmitTicketMessage peut être passé, qui utilise la structure de message suivante :

Typedef struct _KERB_SUBMIT_TKT_REQUEST {
KERB_PROTOCOL_MESSAGE_TYPE MessageType;
LUID LogonId;
ULONG Flags;
KERB_CRYPTO_KEY32 Key;
ULONG KerbCredSize;
ULONG KerbCredOffset;
} KERB_SUBMIT_TKT_REQUEST, *PKERB_SUBMIT_TKT_REQUEST

Ainsi, pour un KerbSubmitTicketMessage, le paramètre ProtocolSubmitBuffer pointe simplement vers un bloc de mémoire constitué d’une structure KERB_SUBMIT_TKT_REQUEST suivie immédiatement d’un ticket Kerberos encodé en ASN (qui est le ticket à appliquer à la session de connexion spécifiée). Le code pertinent dans mimikatz pour soumettre les requêtes KerbSubmitTicketMessage est disponible ici et dans Rubeus ici

Suite à l’appel à LsaCallAuthenticationPackage, le TGT de l’utilisateur a maintenant été mis à jour vers le ticket volé. À partir de ce moment, toute tentative d’accès aux ressources réseau par un processus/thread lié au jeton d’accès ou à la session de connexion interactive de l’utilisateur s’authentifiera automatiquement via Kerberos en utilisant le TGT volé (par exemple, en demandant différents tickets de service/TGS pour des ressources à travers le domaine). 

Notez qu’un utilisateur ne peut avoir qu’un seul TGT associé à sa session de connexion actuelle. Ainsi, l’application d’un nouveau ticket efface le ticket précédent de l’utilisateur. Et si un attaquant souhaitait préserver son TGT actuel ? Dans ce cas, une fois de plus, le drapeau NETONLY vient à la rescousse : un attaquant peut créer un processus NETONLY « sacrificiel » via CreateProcessWithLogonW avec des identifiants arbitraires ou inutilisables. Cela créera un nouveau processus factice et, surtout, une nouvelle session de connexion (et donc un jeton d’accès) à laquelle un TGT volé pourra être appliqué (et ainsi préserver le ticket actuel de l’utilisateur)36

Une conclusion importante à tirer de cette technique pour les praticiens de la défense est que, puisque toute l’activité est effectuée via LsaCallAuthenticationPackage (et donc via RPC), elle ne nécessite aucune interaction directe avec lsass (N.B. direct ici fait référence à l’ouverture d’un handle à lsass via OpenProcess). De plus, pour ce cas d’utilisation spécifique (ptt), toute l’activité se fait via un RPC local jusqu’à ce qu’un attaquant tente de s’authentifier à un hôte distant (ce qui générera de nouveaux points de connexion). 

À titre d’exemple supplémentaire, le README pour Rubeus inclut l’affirmation suivante : 

« Rubeus n’a aucun code pour toucher LSASS (et aucun n’est prévu), donc sa fonctionnalité se limite à l’extraction des tickets Kerberos via l’API LsaCallAuthenticationPackage() »

Par conséquent, toute logique de détection fondée sur l’accès à un handle à lsass (par exemple via une routine de noyau ObjectPreCallback pour une opération de handle de processus ou thread spécifiée, ou un hook en mode utilisateur sur OpenProcess/NtOpenProcess) pourrait manquer cette activité. C’est donc un angle mort potentiel, par exemple, pour les défenseurs qui s’appuient sur les événements d’accès aux processus Sysmon pour alerter en cas d’accès suspect à la prise de procédure.

3. Pass-the-hash (PtH)

Les deux dernières techniques que cet article abordera sont des exemples d’un attaquant modifiant « illégitimement » les identifiants mis en cache associés à son token d’accès/session de connexion actuelle en modifiant directement la mémoire LSASS. Dans le scénario PtH, le jeton d’accès de l’attaquant reste inchangé et pointe vers la même session de connexion, cependant les identifiants en cache associés sont directement écrasés en un hachage volé. À partir de ce moment, toute tentative d’authentification à distance utilisera le hachage volé, comme démontré ci-dessous :

7-under-the-hood-blog-access-token-manipulation.gif

Illustration 7 - Comment fonctionne l’attaque PtH.
Dans cet exemple, le hachage légitime de l’utilisateur, ASTRO\cosmo, est écrasé en mémoire par le hachage NTLM appartenant à l’utilisateur ASTRO\Admin.


En ce sens, PtH et OPtH peuvent être considérés comme fonctionnellement identiques à la technique NETONLY évoquée précédemment.

Le workflow typique d’une attaque PtH est le suivant :

  • Ouvrir un handle d’écriture sur lsass (par exemple via OpenProcess/NtOpenProcess avec un accès souhaité de PROCESS_VM_WRITE)
  • Énumérer la liste liée des sessions de connexion
  • Localiser la session de connexion d’intérêt et identifier le package d’authentification requis (dans le cas de PtH/NTLM, il s’agit du package d’authentification MSV1_0 ).
  • Mettre à jour les identifiants en cache associés

Notez que ces techniques reposent souvent sur l’analyse et la modification de structures Windows non documentées . Ce n’est pas un sujet abordé dans cet article, mais plus d’informations sur la façon dont cela se déroule sont disponibles ici et ici

Ainsi, une fois les identifiants mis en cache mis à jour en mémoire, ils seront automatiquement utilisés pour s’authentifier à distance, comme dans la conception habituelle de l’authentification unique de Windows, lorsque tout processus ou thread exécuté sous ce jeton tente d’accéder à une ressource distante.  

Notez que dans ce cas simple, aucun jeton de session de connexion ou d’accès supplémentaire n’a été créé. Cependant, de manière similaire aux attaques par pass the-ticket, ces outils devront aussi fréquemment créer de nouveaux processus/sessions de connexion NETONLY inutilisables afin de préserver les identifiants existants ou d’appliquer des identifiants volés. 

À noter, pour obtenir un handle d’écriture sur LSASS, les malwares adoptent généralement deux approches :

  • Acquérir SeDebugPrivilege37
  • Voler et usurper l’identité d’un jeton SYSTEM

La première approche a été discutée dans la première partie de cette série d’articles, cependant la seconde approche est un exemple typique de vol/usurpation d’identité d’un jeton dans le but de contourner les contrôles d’accès locaux (par exemple, voler un jeton SYSTEM avec un privilège spécifique activé, par exemple SeTcbPrivilege). Un jeton SYSTEM est généralement obtenu en volant le jeton principal à winlogon.

4.

Surpassement du hachage (OPtH)

La technique Overpass-the-hash applique le même concept que le pass-the-hash, avec une différence clé : elle convertit un hash en un ticket TGT complet. 

Lorsqu’un utilisateur se connecte pour la première fois à une station de travail Windows, dans le cadre du processus d’authentification Kerberos, le hachage du mot de passe de l’utilisateur est utilisé pour chiffrer un horodatage afin de valider l’identité de l’utilisateur auprès du Contrôleur de Domaine/Centre de Distribution de Clés (KDC) et de recevoir un TGT. Le Overpass-the-hash modifie ces hachages en cache de 38 la mémoire puis déclenche le protocole d’authentification normal de Kerberos (AS-REQ/AS_REP, etc.) afin d’obtenir un TGT complet Pour un haschich volé.39

Cette technique peut être exécutée via la commande pth de mimikatz (qui est trompeusement étiquetée pth alors qu’elle effectue en réalité un overpass-the-hash sous le capot) :

mimikatz # sekurlsa ::p th /user :Administrator /domain :ASTRO.testlab /ntlm : c0f969f35beb20e8f09ce86ef42ccd51

Cela effectue essentiellement les mêmes étapes que PtH, sauf qu’il cible le SSP de Kerberos (et donc kerberos.dll).40

8-opth-attack-blog-access-token-manipulation.gif

Illustration 8 - Comment fonctionne l’attaque OPtH.
Dans cet exemple, le hachage légitime de l’utilisateur, ASTRO\cosmo, est écrasé en mémoire par le hachage appartenant à l’utilisateur ASTRO\Administrator, déclenchant ainsi le processus normal d’authentification Kerberos.


Comme cette technique consiste à nouveau à effacer le TGT actuel associé à la session de connexion de l’utilisateur, un attaquant peut utiliser un processus NETONLY (avec une session de connexion factice associée) pour préserver son TGT actuel, ce qui est exactement la façon dont mimikatz effectue par défaut le surpassement du hachage. 

Premièrement, il génère un nouveau processus en état suspendu via CreateProcessWithLogonW avec le drapeau LOGON_NETCREDENTIALS_ONLY. Il obtient ensuite un handle pour le jeton principal de ce processus suspendu et récupère l’identifiant d’authentification pour la nouvelle session de connexion factice via GetTokenInformation. Cette fonction est utilisée pour interroger les informations mises en cache dans le jeton via l’enum TOKEN_INFORMATION_CLASS , qui dans ce cas est TokenStatistics

Une fois l’identifiant d’authentification obtenu, mimikatz peut désormais commencer à énumérer la liste chaînée des sessions de connexion dans LSASS, en cherchant la nouvelle session de connexion créée. Une fois qu’il a trouvé la session de connexion cible (via l’identifiant d’authentification), il peut alors procéder à la mise à jour des identifiants Kerberos qui lui sont associés. Une fois les identifiants mis à jour, le jeton (dont la session de connexion correspondante est désormais liée au hachage volé) peut être converti en jeton d’usurpation via DuplicateTokenEx et usurpé d’identité via SetThreadToken comme nous l’avons vu précédemment. 

Encore une fois à ce stade, toute tentative d’accès aux ressources du réseau par un attaquant utilisera la combinaison de hachage domaine\utilisateur et mot de passe fournie comme argument pour mimikatz en faveur de l’authentification. Par conséquent, toutes les interactions à distance seront effectuées avec l’accès et les privilèges des identifiants volés.

Conclusion

Le but de cette série d’articles en deux parties était d’expliquer comment fonctionnent les concepts fondamentaux de la sécurité Windows et de montrer comment les attaquants abusent de ces fonctionnalités afin de compromettre les domaines Windows. Cet article a démontré que, quels que soient les outils ou le fournisseur d’authentification qui est abusé, les attaquants agissent sous un ensemble de contraintes qui entraînent les mêmes signaux anormaux pour la manipulation des jetons d’accès (par exemple, des connexions réseau anormales uniquement). Ces contraintes sont déterminées par la relation fondamentale entre les jetons d’accès, les sessions de connexion et les identifiants mis en cache.

Prêt pour une protection globale des données avec Elastic Security ? Essayez-le gratuitement dès aujourd’hui, ou découvrez notre dernière version sur service Elasticsearch sur Elastic Cloud. Et profitez de notre formation Quick Start pour vous préparer à réussir.


Références

1. Pour un résumé du fonctionnement de l’authentification Kerberos, voir Programming Windows Security, Keith Brown ou https://posts.specterops.io/kerberosity-killed-the.... De plus, Rubeus, qui est une boîte à outils pour interagir avec Kerberos, propose un readme extrêmement informatif, recommandé pour une lecture complémentaire.

2. Rappelez-vous, Windows s’authentifiera automatiquement avec les identifiants mis en cache dans la session de connexion chaque fois qu’un utilisateur tente d’accéder à une ressource réseau conformément au mécanisme SSO de Windows. Les identifiants mis en cache ici peuvent désigner n’importe quel fournisseur d’authentification (par exemple, hachages NTLM ou tickets Kerberos). NB : cela suppose que l’utilisateur est connecté de manière interactive (hors réseau).

3. Cela vise généralement à éviter de perdre une présence due à une réponse aux incidents ou à l’isolement de l’hôte.

4. Cela ne s’applique évidemment qu’à l’activité de l’attaquant sur un hôte compromis, contrairement à un attaquant exécutant du code provenant d’une autre source, par exemple à distance via impacket.

5. https://clymb3r.wordpress.com/2013/11/03/powershel...

6. Voir la commande « steal_token » de Cobalt Strike comme exemple de cette technique : https://www.cobaltstrike.com/help-beacon

7. Ce commentaire du framework archivé de PowerSploit devrait également apporter des éclaircissements supplémentaires sur cette distinction entre le vol de tokens pour l’escalade locale des privilèges et le déplacement latéral.

8. Sinon, les attaquants peuvent aussi opter pour la manipulation de mots de passe ou tenter d’utiliser des attaques NTLM pour sniffing/rejouer via des outils comme le répondeur.

9. Notez que LogonUserA/W sont de simples enveloppes autour de LogonUserExExW dans SspiCli.dll

10. De la même manière, CreateProcessWithLogonW peut recevoir un compte administrateur local (rid-500) pour exécuter un processus élevé à partir d’un contexte moyen/non élevé.

11. Il existe des options de registre UAC distant qui peuvent modifier ce comportement.

12. Il existe un type de connexion supplémentaire, LOGON32_LOGON_NETWORK_CLEARTEXT, qui est essentiellement une connexion réseau mais avec des identifiants mis en cache. Voir Programming Windows Security, Keith Brown pour plus d’informations.

13. Voir pour plus d’informations :


https://blueteamer.blogspot.com/2018/12/disabling-...
https://support.microsoft.com/en-gb/help/951016/de...
https://labs.f-secure.com/blog/enumerating-remote-...

14. NB : il existe aussi une fonction DuplicateToken mais elle ne retourne qu’un jeton d’usurpation d’identité.

15. Cela peut être vérifié en examinant la fonction dans l’IDA. Sinon, consultez ici sur ReactOS.

16. Ce résumé est une légère simplification de la sécurité de l’usurpation d’identité. Pour un aperçu plus complet, voir les diapositives « Introduction to Logical Privilege Escalation on Windows » de James Forshaw (p. 26) : https://conference.hitb.org/hitbsecconf2017ams/mat...

17. Ce titre est tiré d’un excellent article de Raphael Mudge : Windows Access Tokens and Alternate Credentials (Jetons d’accès Windows et identifiants alternatifs).

18. C’est généralement la principale raison pour laquelle l’option 2 n’est pas couramment utilisée par les attaquants.

19. Ainsi, exécuter « whoami » affichera toujours le même utilisateur (puisque le jeton est toujours le même), même si le jeton dupliqué a des identifiants réseau différents. C’est une source fréquente de confusion lorsqu’on utilise la commande make_token de Cobalt Strike (qui exécute la même technique que celle décrite sous le capot).

20. Les API RPC/COM de Windows permettent également à un utilisateur de spécifier des identifiants réseau uniquement. Par exemple, cela peut être réalisé pour RPC en appelant RpcBindingSetAuthInfoExW et en passant une structure SEC_WINNT_AUTH_IDENTITY via le paramètre AuthIdentity. Pour plus d’informations, voir Programming Windows Security, Keith Brown et https://docs.microsoft.com/en-us/windows/win32/wmisdk/setting-authentication-using-c-.

21. Bien que les deux drapeaux portent des noms différents, leur signification est la même. Ces identifiants ne doivent être utilisés que sur le réseau.

22. Notez qu’il existe encore des moyens de contourner la création de journaux d’événements suspects pour les sessions de connexion anormales.

23. C’est un tour de James Forshaw – voir l’article suivant pour plus de détails : https://www.tiraniddo.dev/2017/05/reading-your-way.... De plus, TokenViewer est un excellent outil pour expérimenter ce type de technique.

24. Avec ce jeton d’usurpation résultant, il est possible d’écrire un fichier sur System32, etc.

25. Il peut toutefois y avoir des raisons légitimes d’usurper l’identité avant d’appeler une API, comme obtenir un privilège que vous n’avez pas actuellement avant d’appeler une API qui l’exige (bien que certaines API activent automatiquement ces privilèges).

26. Il y a plusieurs moyens de contourner cela. Par exemple, vous pouvez générer un processus en tant qu’enfant d’un processus SYSTEM en obtenant un handle pour un processus SYSTEM via OpenProcess avec le droit d’accès PROCESS_CREATE_PROCESS . Ce handle peut ensuite être transmis à NtCreateProcess en tant que paramètre ParentProcess. Cela peut également être réalisé via le paramètre PROC_THREAD_ATTRIBUTE_PARENT_PROCESS et CreateProcess : https://gist.github.com/xpn/a057a26ec81e736518ee50...

27. De manière étrange, CreateProcessWithTokenW adopte un argument dwLogonFlags alors qu’il nécessite également un handle pour un jeton existant, qui, par définition, devrait déjà avoir une session de connexion correspondante. Il semble probable que cela ait un rapport avec le chargement du profil utilisateur.

28. Programming Windows Security (Programmation de la sécurité Windows), Keith Brown

29. Plus précisément, SE_IMPERSONATE_NAME pour CreateProcessWithTokenW et SE_INCREASE_QUOTA_NAME (&) SE_ASSIGNPRIMARYTOKEN_NAME (si le jeton n’est pas assignable) pour CreateProcessAsUserW

30. Un résumé de l’authentification Kerberos est disponible ici et voir ce qui suit pour plus d’informations sur les attaques liées à Kerberos : https://www.blackhat.com/docs/us-14/materials/us-1..., , https://github.com/GhostPack/Rubeus#readme

31. https://googleprojectzero.blogspot.com/2019/12/cal...

32. Par exemple, l’outil natif Windows klist offre une fonctionnalité similaire et est clairement un wrapper autour de LsaCallAuthenticationPackage.

33. Notez qu’un utilisateur non élevé ne peut appliquer des tickets qu’à sa propre session de connexion. Des privilèges élevés sont nécessaires pour appliquer un TGT à une autre session de connexion.

34. Il y a quelques mises en garde et subtilités à cette affirmation qui sont mieux répondues par le readme de Rubeus. En résumé, l’appelant doit enregistrer une connexion LSA via LsaRegisterLsaProcess qui nécessite le privilège SeTcbPrivilege (c’est-à-dire que l’appelant fait partie de la base de calcul de confiance).

35. À titre d’observation, vous pouvez également communiquer avec le paquet d’authentification msv1_0 via LsaCallAuthenticationPackage et envoyer les types de messages suivants : https://docs.microsoft.com/en-us/windows/win32/api..., bien que je n’aie pas vérifié s’il est également possible de récupérer les identifiants NTLM via cette interface.

36. Pour plus d’informations, consultez le dépôt GitHub de Rubeus, readme, qui propose un excellent résumé de nombreuses fonctionnalités liées à kerberos et des considérations opsec.

37. Voir ici un exemple d’habilitation d’un privilège

38. Cela peut être vérifié en consultant PsOpenProcess/Thread dans IDA et en cherchant un appel vers SePrivilegeCheck.

39. Notez que l’acquisition de SeDebugPrivilege tend à être très bruyante du point de vue de la logique de détection.

40. Notez que le hachage/la clé peut être rc4_hmac (par exemple NTLM), aes128_hmac, aes256_hmac etc. Voir ici pour en savoir plus.

41. Voir pour plus de détails : https://www.blackhat.com/docs/us-14/materials/us-1...

42. À noter, la fonctionnalité asktgt de Rubeus effectue une variante du surpassement du hachage en construisant du trafic AS-REQ brut pour un hachage donné à partir d’un contexte non élevé et sans avoir besoin de toucher au lsass.