Comment j’ai gâché mes vacances en rétro-ingénierie de WSC
(blog.es3n1n.eu)- defendnot, créé lors d’un voyage à Séoul, était un outil visant à désactiver Windows Defender en appelant directement l’API du service Windows Security Center (WSC), ce qui a mené à plusieurs jours de rétro-ingénierie
- L’ancien outil no-defender utilisait du code d’un antivirus existant pour enregistrer auprès de WSC la présence d’un autre antivirus ; après avoir obtenu environ 1,5k étoiles GitHub, il a été supprimé à la suite d’une demande DMCA de l’éditeur de l’antivirus
- Au départ, les appels à l’API COM de WSC ont été reproduits en environ une heure, mais WSC vérifiant le processus appelant, l’accès était refusé depuis un processus ordinaire
- L’analyse a montré que WSC vérifiait le SID WinDefend, les droits administrateur, la signature et le drapeau
ForceIntegritydans lesDllCharacteristicsdu PE ; l’implémentation finale a utiliséTaskmgr.exe - Dans un environnement impliquant un MacBook arm64, un PC distant aux États-Unis, une latence Parsec de 210 ms et une VM Shadow.tech, l’implémentation a été finalisée en corrigeant une erreur de chemin
ctx.binet un problème de conditions d’alimentation pour l’autorun
Contexte de la création de defendnot
- defendnot est un outil qui utilise directement l’API du service Windows Security Center pour désactiver Windows Defender
- Le point clé de l’implémentation n’était pas tant l’appel à WSC lui-même que le contournement, un par un, des conditions de vérification qui le bloquaient et d’un environnement de travail inconfortable
- Une documentation technique plus détaillée sur WSC sera publiée ultérieurement par quelqu’un d’autre
no-defender et le DMCA un an plus tôt
- no-defender, publié il y a environ un an, utilisait une API Windows destinée aux antivirus pour désactiver Windows Defender
- Cette API servait à indiquer au système qu’« un autre antivirus est présent, il n’est donc pas nécessaire d’exécuter l’analyse de Defender »
- Le composant système qui gère cette zone est Windows Security Center (WSC)
- no-defender fonctionnait en utilisant du code tiers d’un antivirus existant afin de forcer l’enregistrement de cet antivirus auprès de WSC
- Quelques semaines après sa publication, il avait obtenu environ 1,5k stars, puis le contenu du dépôt a été supprimé lorsque l’éditeur de l’antivirus utilisé a déposé une demande de retrait DMCA
Reprise de l’analyse de WSC lors d’un voyage à Séoul
- Alors que je séjournais dans un Airbnb à Séoul, MrBruh, qui examinait no-defender, m’a envoyé un message disant qu’il cherchait s’il était possible de réaliser une implémentation « propre », sans binaire d’antivirus
- Pour les CTF ou le reverse x86, j’emporte d’habitude un ordinateur portable x86 séparé, mais pour ce voyage je n’avais pris que mon M4Pro MacBook
- Même dans ces conditions défavorables, sans machine dédiée au reverse x86, j’ai commencé l’analyse de WSC pendant les moments disponibles avant que mes amis ne se réveillent
Jour 1 : reproduction de l’API COM de WSC et premier refus d’accès
- MrBruh a fourni les derniers binaires de WSC, et l’implémentation d’enregistrement WSC de l’antivirus utilisé précédemment a servi de référence
- WSC expose une API COM utilisée par les antivirus, et les appels effectués par l’antivirus existant ont été reproduits en environ une heure
- Les tests ont été lancés en démarrant Windows arm64 dans Parallels, mais le résultat a été access denied
- D’après l’expérience précédente, je savais que WSC validait le processus appelant l’API, et j’ai d’abord soupçonné une vérification de signature
- En injectant du code dans le processus que l’antivirus existant utilisait pour les opérations WSC, les appels COM d’enregistrement d’un nouvel antivirus et de mise à jour d’état ont fonctionné correctement
Tentative de suppression du binaire antivirus
- Pour éviter qu’un nouveau projet ne fasse à nouveau l’objet d’une réclamation de la part de l’éditeur d’antivirus existant, l’objectif était d’utiliser un binaire fourni par le système plutôt qu’un binaire d’antivirus
- Le premier processus cible choisi a été
cmd.exe, mais les appels à l’API WSC ont été refusés - En examinant
wscsvc.dll, du code vérifiant si le processus appelant était PPL a été trouvé - Un processus créé avec un simple
CreateProcessAn’était pas un processus protégé PPL, et je n’ai pas pu avancer davantage cette nuit-là
Jour 2 : mise en place d’un environnement de débogage distant pénible
- Sur un MacBook arm64, il était difficile de manipuler correctement Windows x86, et je voulais éviter de devoir travailler dans un environnement arm64 ou de ne pas pouvoir utiliser x64dbg
- Mon ami pindos m’a donné accès à son PC, auquel je me suis connecté à distance avec Parsec
- Comme je me connectais depuis la Corée à un PC situé aux États-Unis, la latence moyenne était d’environ 210 ms
- Le flux de travail de l’époque était extrêmement fastidieux
- Compiler le module avec MSVC dans Windows arm64 sous Parallels
- Partager les artefacts de build avec l’hôte via un dossier partagé
- Copier les artefacts sur la VM du PC de pindos via AnyDesk
- Déboguer le service WSC dans un environnement Parsec avec 210 ms de latence
- L’environnement était si inconfortable qu’il ralentissait fortement le développement et l’analyse
Débogage du service WSC et SID WinDefend
- Le service WSC est une DLL exécutée par
svchost, et le principal obstacle à l’attachement d’un débogueur était la protection PPL - Dans la VM, le mode test a été activé, puis un driver retirant le PPL du processus cible avec quelques lignes de code en mode noyau a été utilisé
- Le point d’échec lorsque
cmd.exedemandait l’enregistrement d’un antivirus auprès de WSC étaitWscServiceUtils::CreateExternalBaseFromCaller - Cette fonction se faisait passer pour le client RPC, puis vérifiait si le jeton du processus appelant contenait le SID
WinDefend - Comme je connaissais mal le fonctionnement des jetons Windows à ce moment-là, j’ai conclu qu’il serait possible de passer le contrôle en usurpant
WinDefend - En manque de sommeil, j’ai aussi mal interprété le fait que le binaire de l’antivirus existant passait ce test
IsMember
Tentative d’usurpation de WinDefend et échec
- Après avoir étudié les jetons Windows pendant quelques heures, l’implémentation est partie dans la direction consistant à exécuter le code avec un jeton contenant le SID WinDefend afin de passer la vérification WSC
- J’ai exécuté le code avec le SID
WinDefendattaché àcmd, mais même si l’appel COM renvoyaitSTATUS_SUCCESS, aucun nouvel antivirus n’était effectivement enregistré - Cette approche s’est finalement révélée inutile, et il a fallu la revérifier le lendemain
Jour 3 : reconstruction de l’algorithme de vérification réel
- En revérifiant, il s’est avéré que le binaire de l’antivirus existant ne passait pas la vérification du SID WinDefend
- Passer cette vérification permettait de manipuler l’objet WSC de Windows Defender, mais comme les seuls appels WSC ne permettaient pas de désactiver immédiatement Defender, cela ne servait à rien
- Le code d’usurpation de WinDefend a été supprimé, et l’autre branche de la condition a été analysée
- Cette branche vérifiait les points suivants pour le binaire appelant
- Si le processus était elevated
- Si la signature du binaire était valide
- Si un drapeau spécifique était présent dans les
DllCharacteristicsdu PE
- Le drapeau
DllCharacteristicsvérifié dansCSecurityVerificationManager::CreateExternalBaseFromPESettingsétait ForceIntegrity - Du code reproduisant la vérification de binaire effectuée par WSC a été créé dans le dossier
wsc-binary-checkdu dépôt defendnot, puis testé sur des binaires System32
Utilisation de Taskmgr.exe et bug de ctx.bin
- Comme mon ami devait réutiliser son PC, je me suis connecté directement à la VM via Parsec, mais l’environnement est devenu encore plus lent à cause de l’encodage logiciel
Taskmgr.exea été utilisé à la place decmd.exe, mais des erreurs RPC se produisaient toujours- En raison de la latence et des problèmes de saisie, il est devenu difficile de déboguer dans la même VM, et sur recommandation j’ai payé 30 $ pour un abonnement shadow.tech
- La VM Shadow.tech avait une version de Windows plus ancienne, où le code de
wscsvcn’était pas aussi fortement inliné dans une seule fonction que dans les versions récentes, et le résultat de décompilation était plus lisible - La véritable cause de l’erreur était un nom d’AV incorrect transmis à WSC
defendnot-loaderutilisaitctx.bin, qui contenait des paramètres sérialisés, pour transmettre des données àdefendnot.dll- Un IPC séparé avait été implémenté pour le suivi d’état, mais pour la transmission de configuration, l’ancien mécanisme
ctx.bin, vestige du code de no-defender, subsistait - La fonction recherchant le chemin de
ctx.binutilisait comme base le dossier par défaut du moduleTaskmgr.exe, et non celui denodefend.dll - En conséquence, un octet nul était transmis comme nom d’AV, et WSC rejetait ce buffer
- Après correction du problème de chemin, le test a réussi
Nettoyage du code et problème d’autorun
- Pour terminer le jour même, le nettoyage du code et l’implémentation de fonctionnalités supplémentaires se sont poursuivis jusqu’à 8 h du matin
- Parmi les fonctionnalités ajoutées figurait l’ajout de lui-même à l’autorun
- À 8 h, seul l’autorun ne fonctionnait pas correctement ; après avoir testé plusieurs méthodes sans succès, je suis allé dormir
- En revérifiant le lendemain, la cause venait de deux cases à cocher liées à l’alimentation lors de la création d’une tâche dans le planificateur de tâches
- Comme l’ordinateur portable n’était pas branché sur secteur, la tâche ne s’exécutait pas ; après désactivation de ces drapeaux, l’autorun a fonctionné
- Quelques heures supplémentaires ont ensuite été consacrées au nettoyage du code, puis le travail a été terminé
Conclusion
- Le travail en lui-même était amusant, mais les problèmes d’environnement et le flux de débogage distant répétés pendant plusieurs jours sont une expérience que je ne veux pas revivre
- En particulier, le MacBook arm64, la VM x86 distante, la forte latence, l’encodage lent et le bug de chemin de fichier découvert tardivement ont beaucoup augmenté la difficulté de l’implémentation
- Une documentation WSC plus technique sera publiée séparément plus tard
1 commentaires
Avis sur Hacker News
La méthode la plus intrusive, mais efficace, que j’aie trouvée pour désactiver Defender consistait à démarrer sur un live USB Linux, à renommer
C:\ProgramData\Microsoft\Windows Defender, puis à créer un fichier vide à cet emplacementÀ noter que WSC signifie Windows Security Center
L’expression
the antivirus I was usingm’a pas mal embrouillé. Je ne comprenais pas pourquoi cet éditeur d’antivirus aurait une raison d’envoyer à l’auteur une demande de retrait DMCAJe suppose que cela veut dire que l’auteur a rétroconçu un autre antivirus et en a intégré une partie dans un projet open source. Mais comme on voit aussi des titres du genre
Impersonating WinDefend, je me demande au final si l’auteur a enfreint le droit d’auteur d’une manière ou d’une autreJuste avant le paragraphe cité, il est expliqué que « le projet utilisait du code tiers d’un antivirus déjà existant et forçait cet antivirus à s’enregistrer comme antivirus auprès de WSC »
Ce code donne l’impression d’être maudit :
https://github.com/es3n1n/defendnot/blob/master/defendnot-lo...
Si vous voulez savoir ce qui se passe réellement, c’est ici :
https://github.com/es3n1n/defendnot/blob/master/cxx-shared/s...
Par exemple, le langage D intègre directement la notion d’instruction exécutée à la fin d’une portée
En résumé, ce n’est pas écrit par une IA. Ce code diffère l’appel d’une fonction jusqu’au moment où l’objet sort de sa portée. L’implémentation utilise des macros C pour créer une syntaxe plus courte qui omet une partie de la définition nécessaire d’une lambda/fonction anonyme en C, et génère un nom de variable unique chargé de gérer l’appel différé
Cela dit, la syntaxe obtenue évite la convention courante des macros C, à savoir l’écriture en majuscules, et ressemble au premier coup d’œil à un appel de fonction sur un pointeur d’objet. Si l’on n’est pas familier de ce pattern, ou si l’on s’attend à ce que les macros soient signalées autrement, cela peut prêter à confusion
Pour certains, c’est suffisamment courant et utile pour être presque considéré comme un idiome dans certains contextes. Pour une explication technique, https://news.ycombinator.com/item?id=43959403#43960905 détaille bien le fonctionnement de la macro
Pendant mes vacances, j’ai rétroconçu les bureaux virtuels de Windows, et mes vacances n’en ont été que meilleures. Mon meilleur souvenir de l’an dernier, c’est d’avoir découvert à quel point la rétro-ingénierie est amusante
J’ai aussi appris beaucoup de choses intéressantes, notamment qu’il existe sous le RPC de Windows une couche de messagerie non documentée : https://csandker.io/2022/05/24/Offensive-Windows-IPC-3-ALPC....
À chaque fois, je constate que si la photo de profil est un personnage d’anime, l’article sera bon. Je garde ça de côté au cas où je devrais un jour revenir à un environnement Windows médiocre
Pour ceux qui se posent la question : WSC signifie Windows Security Center. J’ai dû le chercher moi aussi
Pourquoi vouloir désactiver WSC ?
Si vous êtes un éditeur d’EDR, il s’agit d’un appel d’API obfusqué pouvant servir à inhiber ou désactiver Windows Firewall. Par exemple, j’imagine que CrowdStrike peut soit utiliser Windows Firewall, soit sa propre implémentation
netcat.exeest interditJ’ai récemment lu https://nostarch.com/windows-security-internals, et cet article m’a beaucoup plus parlé grâce à ça
Je savais déjà vaguement comment ce genre de fonctionnement en coulisses se passe dans Windows, mais le timing était bon. Le dernier chapitre de ce livre creuse aussi assez en détail les tokens et SID, comme ce que traite l’auteur de cet article