Le « Hash Shucking » est une approche récente consistant à « éplucher » / « écailler » un hash ou jeton d’authentification vers un algorithme jugé plus faible et donc plus optimisé pour le cassage. Cette technique s’applique particulièrement bien pour les algorithmes reposant sur le DES, notamment les jetons NetNTLMv1.
1. Introduction et contextualisation
Lors d’audits offensifs internes, à l’encontre de cibles privilégiées comme les écosystèmes Active Directory, une très grande majorité des attaquants-auditeurs débutent en boîte noire avec une action d’écoute passive / active / man-in-the-middle du réseau via des outils comme Responder [RES] pour obtenir des challenges d’authentification. Une impersonation WPA2-Enterprise permet aussi d’obtenir de tel challenge (hostapd-wpe [WPE]) ou encore une capture d’une négociation PPTP-VPN MSCHAPv2 ($99$) via chapcrack [CHA].
De telles actions en tâche de fond permettent de récolter des jetons d’authentification sous divers formats, notamment NetNTLM, avec possibilité de forcer le downgrade avec Responder (--lm ou --disable-ess, quand le client dispose de la clé du Registre lmCompatibilityLevel < 3 [PRA]).
Bien que déconseillé de nos jours, le protocole d’authentification réseau NetNTLMv1 (introduit en 1993, figure 1) se base sur du chiffrement symétrique Data Encryption Standard [DES], dont l’insécurité au regard des puissances de calculs actuelles n’est plus à démontrer. Le NetNTLMv1 a par la suite été durci avec la notion de ESS/SSP (Extended Session Security / Security Support Provider), permettant d’inclure un autre challenge renforçant l’aléa final.
Parmi les nombreuses méthodologies de compromission d’un accès initial largement documentées, l’obtention d’un NetNTLMv1 par des auditeurs est souvent le premier sésame pour pénétrer le domaine.
Avec un NetNTLMv1, un attaquant peut chercher à :
- Casser celui-ci via hashcat [HAS] pour obtenir le plaintext (brute-force, wordlists, etc.) : ce qui est chronophage, sans assurer un résultat à 100% ;
- Méthode prolifique si la complexité du mot de passe est discutable, ou s’il est présent dans des fuites de données passées ;
- Méthode non prolifique dans le cas d’un NetNTLMv1 d’un compte machine (coercion), car mot de passe machine autogénéré et complexe ;
- Cette technique est locale (on-premise), et dépend de la puissance de calcul disponible (coût matériel).
- Casser celui-ci via le service en ligne Crack.Sh [CSH], employant des rainbow tables non publiques dédiées à des FPGA [RAI], pour obtenir un format intermédiaire, à savoir le NT-hash, qui, indépendamment de la complexité du plaintext restant inconnu, permet de réaliser des attaques pass-the-hash [PTH] ;
- L’usage de cet outil implique d’envoyer sur un service tiers une information très sensible : le NetNTLMv1, ce qui est rarement autorisé/souhaité lors d’un audit ;
- Le cassage du NetNTLMv1 vers le NT-hash est quasi instantané et gratuit si, et seulement si, le NetNTLMv1 a la valeur 1122334455667788 (rainbow tables) pour son challenge et n’est pas renforcé via ESS/SSP ;
- Dans les autres cas (challenge différent, ou présence de ESS/SSP), Crack.Sh propose toujours de le casser, mais avec plus de temps et un coût de $20 à $200 ;
- Reposer sur un service tiers en ligne implique de subir ses indisponibilités, comme ce fût le cas où Crack.Sh était en maintenance plusieurs mois fin 2022.
Le protocole d’authentification NTLM, et notamment NetNTLMv1 avec ou sans ESS/SSP reste technique à appréhender et est souvent incompris des auditeurs qui pourtant manipulent de tels outils, au même titre que d’autres formats de jetons basés sur DES comme MSCHAPv2, PPTP-VPN, $99$, etc.
Le présent article est voué à éclaircir le fonctionnement du NetNTLMv1(-ESS/SSP) ainsi que présenter la méthode de Hash Shucking employée par l’outil en ligne Shuck.Sh [SHU] et sa version on-premise ShuckNT [SNT] pour shucker des NetNTLMv1 vers les NT-hashs instantanément et sans surcoût. Cette approche est complémentaire-préliminaire à l’usage de Crack.Sh ou de hashcat.
2. Qu’est-ce que le « Hash Shucking » ?
2.1 What the Sh*ck !?
Le Hash Shucking ou Password Shucking est une approche optimisée de cassage de secret présentée en 2020 par Sam CROLEY (Chik3nman) à la DEFCON [DEF].
L’idée, synthétisée, est la suivante : imaginons un site web d’e-commerce, comportant 10M de clients inscrits et dont les mots de passe sont simplement hachés en MD5 (sans sel ni poivre). Le site subit une fuite de données et les 10M de MD5 se retrouvent dans la nature.
De nombreux attaquants s’attellent à casser ces 10M de hashs. Ils en obtiennent 80% en clair, soit 8 000 000. Il y a donc 2M de hashs non cassés.
Après la découverte de cette fuite, et invocation de la CNIL / RGPD, le site web d’e-commerce décide de passer tous les mots de passe en Bcrypt (plus robuste cryptographiquement).
Toutefois, les équipes techniques ne peuvent pas attendre que chaque client réinitialise son mot de passe. Alors, ils décident d’appliquer un bcrypt(md5()), pour que tous les hashs en base soient dorénavant au format Bcrypt (sans avoir eu connaissance ni besoin du plaintext).
Seulement, rebelote, le site web subit une nouvelle fuite de données et tous les hashs Bcrypt, incluant les nouveaux inscrits depuis la première fuite et ceux ayant renouvelé leur mot de passe, se retrouvent également dans la nature quelque temps après (disons 15M de hashs Bcrypt).
En tant qu’attaquant :
- Il est possible de chercher à casser tous ces Bcrypt (15M) à partir du dictionnaire des 8M de plaintexts obtenus lors de la première fuite. Cette approche sera lente (Bcrypt est très consommateur) et non-optimisée, car chaque plaintext sera d’abord haché en MD5 avant d’être haché en Bcrypt. De plus, de nombreux hashs Bcrypt seront testés alors qu’inutiles (les clients s’étant inscrits entre la fuite n°1 et n°2). Pour finir, les 2M de hashs MD5 non cassés suite à la première fuite ne font pas partie des tests menés dans le dictionnaire source.
- Une meilleure option pour l’attaquant est donc de tester tous les hashs MD5 issus de la fuite n°1 (10M) en les confrontant à la fuite des Bcrypt. Il en déduira la sous-liste des Bcrypt dont les hashs MD5 restent inchangés entre les deux fuites. Puis, avec ce sous-ensemble de MD5, il déroulera ses attaques (brute-force / dictionnaire) beaucoup plus rapidement.
Ce principe se nomme le Hash Shucking : l’idée est qu’à partir d’un secret protégé par un algorithme robuste (Bcrypt), le fait de revenir à un autre format intermédiaire du secret (MD5) facilite et optimise l’obtention du sésame final. Autrement dit, on « épluche » / « dé-coquille » / « écaille » le secret pour s’attaquer à une couche plus faible.
2.2 Hash Shucking et NetNTLMv1
Ce principe de Hash Shucking s’applique très bien pour les jetons d’authentification NetNTLMv1.
En effet, un NetNTLMv1 (ou un quelconque algorithme basé sur DES comme MSCHAPv2, PPTP-VPN, $99$, etc.) se calcule ainsi (figure 2) :
- À partir du NT-hash de l’identité (qui correspond au MD4 du plaintext après conversion en UTF-16 Little-Indian), ce hash est divisé en 3 parties nommées PT1 (7B), PT2 (7B) et PT3 (2B) ;
- Chacune de ces 3 parties subit quelques opérations binaires pour être dérivée en 3 clés K1, K2 et K3 de 8 octets chacune. La dérivation de PT3 (2B) en K3 (8B) induit une faiblesse, évidemment.
- En parallèle, un aléa de 8 octets appelé challenge est produit :
- Cet aléa est généré par le serveur (malveillant). Donc sa valeur peut être prédéfinie (1122334455667788 dans le Responder.conf) ;
- Pour renforcer significativement la sécurité, la notion de ESS/SSP peut être utilisée, où un second aléa est également généré, sur lequel l’attaquant n’a pas le contrôle. Celui-ci est placé dans la LM-response avec un padding de 0 (figure 3).
- Le challenge final est donc le client-challenge lui-même en cas d’absence de ESS/SSP, ou alors les 8 premiers octets du MD5 de la concaténation du client-challenge et du server-challenge en cas de ESS/SSP.
- Donc si une LM-response a 8 octets puis plusieurs 0 en bourrage, c’est qu’il y a présence de ESS/SSP.
- À partir des 3 clés secrètes K1, K2 et K3, l’algorithme symétrique DES-ECB est appliqué sur le challenge final pour produire trois chiffrés CT1, CT2 et CT3 de 8 octets chacun.
- La concaténation de ces trois chiffrés forme la NT-response qui est directement incluse dans les jetons finaux.
Au regard de l’algorithme pour générer des NetNTLMv1(-ESS/SSP), on remarque clairement que la source initiale est le NT-hash, et non pas le plaintext directement. Ainsi, le principe de Hash Shucking peut s’appliquer parfaitement pour cet algorithme basé sur DES : revenir à un NT-hash à partir d’un NetNTLMv1, sans avoir besoin de casser ni avoir connaissance du plaintext initial. Surtout que dans un écosystème Active Directory, avoir un NT-hash équivaut à un plaintext grâce au pass-the-hash !
Le fonctionnement de cet algorithme a été implémenté de manière ludique, détaillée et dynamique sur Shuck.Sh dans le Generator [SHU].
3. Casser du NetNTLMv1(-ESS/SSP)
3.1 Les différentes méthodes
La figure 4 résume les couches/coquilles d’un NetNTLMv1 (plaintext / NT-hash / DES keys / NetNTLMv1) et les modes d’attaques existants pour shucker et revenir à une couche antérieure.
À partir d’un NetNTLMv1, avec ou sans ESS/SSP et quelle que soit la valeur du challenge, il est possible pour un auditeur (dont la prestation est limitée dans le temps), de :
- Utiliser Shuck.Sh / ShuckNT (on-premise) en premier lieu, pour tenter de shucker le NT-hash instantanément en le confrontant à l’énorme base de données de HaveIBeenPwned [HIB]. Résultat non-garanti, mais permet de gagner un temps précieux.
- Employer hashcat (moyennant la puissance matérielle) pour :
- Retrouver le plaintext directement (mode 5500) via des wordlists et/ou masks/rules. Les résultats ne sont pas garantis et cela nécessite du temps (vitesse moindre) ;
- Retrouver le NT-hash (mode 27000), la vitesse est plus rapide, et tout dépend de la qualité du dictionnaire de NT-hashs fourni ;
- Casser les clés DES K1 et K2 (K3 étant obtenue instantanément) via le mode 14000 [KPA]. 100% de réussite, quel que soit la complexité initiale du mot de passe ! Mais un tel traitement prend maximum 15 jours avec une machine dédiée (RTX 3080Ti / i7 12th Gen / 32GB RAM pour mes tests), 7,5 jours en moyenne. Ce qui est généralement trop long lors d’une prestation. Une fois les deux clés obtenues, la reconstruction du NT-hash final peut se faire à la volée sur le Converter [SHU] de Shuck.Sh.
- Employer Crack.Sh pour 100% de résultats (si disponible) :
- Quasi instantané et gratuit si le NetNTLMv1 est dépourvu de ESS/SSP et que le challenge a pour valeur 1122334455667788, quelle que soit la complexité du mot de passe initial ;
- Sous quelques heures moyennant $20-$200 en présence d’ESS/SSP ou avec un challenge différent de 1122334455667788.
La technique du Hash Shucking employée par Shuck.Sh / ShuckNT ne remplace pas hashcat ni Crack.Sh, mais permet potentiellement de gagner du temps, sous réserve que le mot de passe ait fuité précédemment.
Mais comment est-il possible de shucker quasi instantanément un NetNTLMv1 vers son NT-hash, sans l’usage de rainbow tables / FPGA, ni d’un supercalculateur, alors que hashcat et Crack.Sh effectuent leurs traitements en plusieurs dizaines de minutes voire heures ? Détaillons le fonctionnement de Shuck.Sh et de son moteur ShuckNT.
3.2 Déterminer PT3 du NT-hash à partir du NetNTLMv1
Comme évoqué dans la description de l’algorithme pour générer des NetNTLMv1, la partie PT3 (2 derniers octets) du NT-hash sert à concevoir la clé DES K3 qui permet l’obtention du chiffré CT3 sur 8 octets. Une faiblesse en découle, il suffit de tester toutes les valeurs entre 0x0000 et 0xFFFF pour redéterminer les 2 derniers octets (PT3) d’un NT-hash à partir d’un NetNTLMv1 [HAU][EVI].
Un tel brute-force est instantané et est implémenté sur le Converter de Shuck.Sh de manière dynamique.
En connaissance de la fin d’un NT-hash instantanément à partir d’un quelconque NetNTLMv1(-ESS/SSP), une nouvelle optimisation en découle, couplée au Hash Shucking, dans le but de retrouver le NT-hash complet rapidement : l’utilisation de HaveIBeenPwned !
3.3 HIBP-DB à la rescousse !
Le service de Troy Hunt, HaveIBeenPwned [HIB], qui agrège, informe, notifie et contribue grandement à l’amélioration de l’hygiène des mots de passe au travers des fuites de données qu’il référence, fourni une base de données complète en libre téléchargement de tous les précédents mots de passe qui ont fuité par le passé, hachés en NT-hash.
Cette base, dont la v8 fait plusieurs Go pour 847 223 402 mots de passe fuités, se structure comme suit, avec #leak le nombre de fois où le mot de passe a été observé dans les fuites recensées :
Comme il est possible de déterminer instantanément les 4 derniers caractères d’un NT-hash en hexadécimal à partir d’un NetNTLMv1, pourquoi ne pas chercher dans l’énorme base de données de HIBP tous les NT-hashs qui terminent également par ces mêmes caractères, puis les tester un à un afin d’essayer de shucker le NetNTLMv1 ?
Seulement, rechercher parmi ces presque 850M de NT-hashs de HIBP uniquement ceux finissant par 4 caractères précis peut s’avérer chronophage si la technique de recherche n’est pas optimisée...
3.4 Recherche binaire dans une base optimisée
Un algorithme de recherche binaire peut parcourir une gigantesque base de données triée, avec une approche dichotomique, à la recherche des valeurs (de taille fixe) débutant par les mêmes 2 octets de manière très efficiente.
Afin d’optimiser une telle recherche, la base de données de HIBP doit être convertie :
- Pour chaque NT-hash qu’elle contient, inverser ceux-ci pour qu’ils débutent par les caractères de PT3 inversés. Soit :
00112233445566778899AaBbCcDdEeFf:#leak# devient :fFeEdDcCbBaA99887766554433221100:#leak
- Suite à cette inversion de tous les NT-hashs (prends plusieurs minutes), il est nécessaire de retrier tous les NT-hashs alphabétiquement ou « hexadécimalement » parlant (également plusieurs minutes) ;
- Finalement, comme chaque ligne n’a pas toujours la même taille (le #leak peut parfois être très important), il est nécessaire de convertir cette énorme base de données-inversées-triées en un format binaire. Le nombre d’occurrences #leak étant un int, 4 octets suffisent (toujours plusieurs minutes).
Avec ces modifications à n’effectuer qu’une fois, la base de données est optimisée pour une recherche binaire instantanée, et est également fortement réduite en termes de taille (plusieurs Go de gagnés).
En moyenne, il y a ~12 650 NT-hashs qui « finissent » tous par les 2 mêmes octets dans la base de données HIBP v8, soit que ~12 650 NT-hashs à tester pour shucker un NetNTLMv1 et non pas les ~850M.
3.5 Ready to shuck!
Avec tous ces éléments, le Hash Shucking du NetNTLMv1 avec ou sans ESS/SSP et quel que soit le challenge peut se faire, et ce instantanément via la recherche binaire dans la base HIBP.
Bien évidemment, les résultats dépendent de la base de données, et il n’est donc pas possible de garantir à 100% l’obtention du NT-hash.
L’algorithme final de shucking consiste donc à :
- Extraire CT1, CT2 et CT3 d’un NetNTLMv1(-ESS/SSP) ;
- Brute-forcer les 65 536 valeurs possibles des 2 derniers octets du NT-hash PT3 correspondant à K3 et donc CT3 ;
- De là, effectuer une recherche binaire dichotomique dans la base de données HIBP de tous les NT-hashs terminant par PT3 ;
- Pour chacun de ces NT-hashs (~12 650 en moyenne), extraire PT1’ et PT2’, dériver K1’ et K2’ puis calculer les CT1’ et CT2’ correspondants (avec le challenge du NetNTLMv1 initial) ;
- Si CT1’ et CT2’ sont identiques au CT1 et CT2 du NetNTLMv1 initial, alors le NT-hash a été shucké !
Cet algorithme est celui employé par le moteur ShuckNT, utilisable en local ainsi qu’intégré sur la version en ligne Shuck.Sh.
Cet outil détaille et dissèque un NetNTLMv1 pour y retrouver tous les éléments cryptographiques servant à sa composition (CT1, CT2, CT3, client-challenge, server-challenge, final-challenge, K1, K2, K3, PT1, PT2, PT3, etc.) jusqu’à l’obtention du NT-hash si présent dans la base de données HIBP.
4. Fonctionnalités additionnelles et synthèse
4.1 Les autres formats
Dans cet article, les jetons au format NetNTLMv1 sont détaillés. Pour mémoire, le format des NetNTLMv1 sans ESS/SSP est le suivant (incompatible Crack.Sh / compatible hashcat / capture via Responder [RES]) :
En cas de présence de ESS/SSP, un 0’s-padding est visible dans la LM-response (incompatible Crack.Sh / compatible hashcat / capture via Responder [RES]) :
Le format gratuit attendu par Crack.Sh lorsque le challenge est fixé à 1122334455667788 et qu’il n’y a pas d’ESS/SSP est le suivant (on note l’absence du challenge, incompatible avec hashcat) :
En présence d’ESS/SSP, et/ou quand le challenge final est différent de 1122334455667788, le format payant destiné à Crack.Sh est (on note la présence du challenge, incompatible avec hashcat, capture via hostapd-wpe [WPE]) :
Pour les authentifications WPA-Enterprise et PPTP-VPN qui reposent également sur le NT-hash et DES, les formats peuvent être les suivants (incompatible Crack.Sh et hashcat) :
Ainsi que le format $99$ destiné initialement à (feu) CloudCracker, mais compatible avec son successeur Crack.Sh (capture via chapcrack [CHA]) :
Tout ces formats sont donc équivalents bien que certains ne soient compatibles qu’avec hashcat ou Crack.Sh. Il est aisé de passer de l’un à l’autre et tous sont convertibles avec Shuck.Sh / ShuckNT, via le Converter.
À titre d’exemple, le jeton suivant $99$ESIzRFVmd4i8671kB52wcm9qK5VdJR7lJKU= pourrait être soumis à Crack.Sh moyennant $20-$200. En le soumettant à Shuck.Sh / ShuckNT, celui-ci n’est hélas pas shucké, mais il est converti au format NTHASH:BCEBBD64079DB0726F6A2B955D251EE57D6DD8A109D77A0D, qui lui est gratuit sur Crack.Sh !
4.2 Synthèse
Via le moteur ShuckNT [SNT] intégré à la version en ligne Shuck.Sh [SHU], il est possible de :
- Retrouver instantanément et gratuitement le NT-hash associé à un jeton, qu’importe la présence de ESS/SSP ou la valeur du challenge, si celui-ci a déjà fuité ;
- Convertir un jeton d’authentification d’un format à un autre (MSCHAPv2 vers NetNTLMv1 vers $99$... et vice-versa) ;
- Optimiser les formats des jetons non-shuckés vers un format potentiellement gratuit sur Crack.Sh [CSH] ;
- Générer automatiquement les lignes de commandes optimisées pour passer le jeton à hashcat (mode 5500, 27000 ou 14000) [HAS] ;
- Brute-forcer instantanément les 2 derniers octets du NT-hash [HAU] ;
- Régénérer le NT-hash suite à l’obtention de K1 et K2 [EVI] (après un hashcat mode 14000, Known Plaintext Attack [KPA]) ;
- Utilisable en ligne (avec des exemples fournis) ou on-premise pour garantir un contrôle sur toutes les données sensibles issues de vos prestations ;
- Comprendre, disséquer, générer vos propres jetons sous divers formats avec vos propres valeurs de manière dynamique.
Conclusion
Ce nouvel outil s’incruste dans la chaîne méthodologique des audits offensifs internes, en préliminaire de l’utilisation de Crack.Sh et/ou de hashcat qui peuvent induire du temps supplémentaire, des coûts additionnels, ou s’avérer tout simplement incompatibles avec certains formats de jeton.
Shuck.Sh et son moteur ShuckNT sont nés suite à la mise en maintenance / indisponibilité de Crack.Sh pendant plusieurs mois fin 2022, et dans l’objectif d’être indépendants d’un service tiers lors de prestation d’audit.
Cet article et ces outils s’orientent vers la famille d’algorithmes fondés sur DES en utilisant les NT-hash comme base de clés. Le NetNTLMv2, quant à lui, suit les mêmes concepts que le NetNTLMv1 à la différence des algorithmes cryptographiques sous-jacents qu’il emploie (HMAC-MD5 au lieu de DES). En conséquence, ce format n’est pas compatible ni avec Shuck.Sh/ShuckNT, ni avec Crack.Sh.
Ces outils contribuent de plus à démontrer à la communauté que l’usage d’algorithmes basés sur DES n’est plus jugé sécurisé. Au sein des écosystèmes Microsoft Active Directory, il est recommandé d’évincer les versions protocolaires NetNTLMv1 (avec ou sans ESS/SSP) voire même NetNTLMv2 en favorisant l’usage de Kerberos.
Pour finir, je tiens à saluer et remercier toute la communauté cybersécurité œuvrant au quotidien pour améliorer la sécurité (et l’insécurité) lors d’audits internes, Troy HUNT pour le fabuleux service HaveIBeenPwned ainsi que l’équipe de Crack.Sh, Hashcat et evilmog pour leurs outils d’une grande qualité. Salutations également à mon cher Zarbibi, qui m’a bien aidé lorsque les calculs binaires me procuraient des maux de crâne et à Tmenochet pour sa relecture attentive :) !
Références
[RES] Laurent GAFFIE, Responder.py, https://github.com/lgandx/Responder
[WPE] Brad ANTONIEWICZ, hostapd-wpe (Wireless Pwnage Edition), https://github.com/OpenSecurityResearch/hostapd-wpe
[CHA] Moxie MARLINSPIKE, chapcrack, https://github.com/h1kari/chapcrack
[PRA] Adam CROSSER, NTLMv1 vs NTLMv2: Digging into an NTLM Downgrade Attack, https://www.praetorian.com/blog/ntlmv1-vs-ntlmv2/
[DES] Wikipedia, Data Encryption Standard, https://en.wikipedia.org/wiki/Data_Encryption_Standard
[CSA] 0xcsandker, NTLM Authentication: A Wrap Up, https://csandker.io/2017/09/10/NTLMAuthenticationAWrapUp.html
[HAS] Hashcat team, Hashcat, https://hashcat.net/
[CSH] Crack.Sh team, The World’s fastest DES cracker, https://crack.sh/
[RAI] David HULTON, desrtfpga, https://github.com/h1kari/desrtfpga
[PTH] Wikipedia, Pass the hash attack, https://en.wikipedia.org/wiki/Pass_the_hash
[SHU] Yann CAM, Shuck.Sh, Shuck hash before trying to crack it, https://shuck.sh/
[SNT] Yann CAM, ShuckNT, on-premise engine of Shuck.Sh, https://github.com/yanncam/ShuckNT
[DEF] Sam CROLEY, What the Shuck? Layered Hash Shucking,
https://www.youtube.com/watch?v=OQD3qDYMyYQ
[HIB] Troy HUNT, Have I Been Pwned?, https://haveibeenpwned.com/
[KPA] Atom, How to make use of the DES KPA mode, https://hashcat.net/forum/thread-5832.html
[EVI] evilmog, ntlmv1-multi - ntlm-to-des, https://github.com/evilmog/ntlmv1-multi
[HAU] Hashcat team, Hashcat-utils – deskey_to_ntlm and ct3_to_ntlm,
https://github.com/hashcat/hashcat-utils