Už jsem tu psal o tom, že počítače si ukládají různá hesla v plné formě. Dneska se pověnujme detailněji heslům uloženým ve formě LSA secrets. To je poměrně stará technologie na zašifrované ukládání tajných informací v registrech počítače v klíči:
HKLM\SECURITY\Policy\Secrets
Systém (tedy systémový proces lsass.exe - neboli Local Security Authority sub system) si sem ukládá například hesla služeb (Windows service), pokud běží pod nějakým konkrétním uživatelským účtem. To by bylo v podklíčích začínajících prefixem _SC_. Také se zde ukládá a je k dispozici heslo počítače do domény. To je tady v podklíči $MACHINE.ACC viz. můj starší článeček. Tedy pokud je počítač členem domény. Pokud byl někdy použit autologon (automatic logon), je tam navždycky taky DefaultPassword.
Do toho klíče se normálně nedostanete. Pokud se tam chcete podívat v regeditu, klikněte si pravým tlačítkem a v kontextovém menu Permissions si prostě přidejte oprávnění, například pro skupinu Administrators.
Troška historie
Je zde také lokální master heslo pro DPAPI (klíč DPAPI_SYSTEM) o kterém jsem se mírně zmiňoval v předcházejícím článku. Tady se jedná pouze o lokální DPAPI, což nebylo přímo to, co jsem tam řešil s tím Key Distribution Service. Ale všechno souvisí se vším :-) DPAPI je novější metoda, jak se šifrují tajné informace v registrech, na disku a v databázích a všude možně jinde. A jeho bezpečnost samozřejmě stojí na tomto master key.
Historicky by se to dalo porovna asi takto - LSA secret od jakživa, DPAPI na Windows 2000 a novějších a potom Key Distribution Service (KDS) od Windows 2012.
Dneska o LSA secrets
Pokud si tedy systém pomocí LSA secret ukládá nějakou kritickou informaci, speciálně to heslo do domény, nebo heslo služeb (service password), je to zašifrované v podklíčích toho Secrets klíče. Pojem "zašifrované" znamená, že se to šifruje ještě nějakým jiným systémovým klíčem (syskey). Ten je samozřejmě taky někde v registrech (pokud ho nezadáváte při startu právě přes syskey), takže zase ne žádná super věda.
Jsou tam vždycky ještě dva další podklíče, CurrVal a OldVal a k nim ještě dvě časová razítka v klíči CupdTime, OupdTime repsektive. V CurrVal je aktuální hodnota toho hesla. V OldVal je předchozí hodnota toho tajemství. Časová razítka jsou ve formátu FILETIME a odpovídají jejich změnám. Předchozí hodnoty hesel jsou pro systém velmi důležité. Třeba Kerberos tikety mají nějakou určitou platnost a protože mohou být zašifrovány ještě tím starým heslem, musí být možnost je i nadále dešifrovat. Mimochodem použití starších hesel má zajímavé vlastnosti.
To je samozřejmě zajímavé i pro hackery, kteří se vám chtějí dostat k heslům. Sice asi ne automaticky, ale když se člověk podívá na dvě hesla a vidí, že se tam jenom mění koncovka, už se z toho dá něco zjistit.
V tom předchozím článku o vybírání hesel služeb jsem používal program Cain & Abel, ale to je zbytečné. Hlavně je to "zlý" program a navíc mi prozatím nefunguje na Windows 2012 R2.
Tak jsem si to naprogramoval v PowerShellu. Nejde vůbec, ale vůbec, o žádné hekování. Pokud si ten skript spustíte pod účtem skupiny Administrators, není důvod proč by to bylo něco nelegálního. Ono je tam totiž úplně normální Win32 API v knihovně ADVAPI32.DLL, normálně zdokumentované, na čtení těch hodnot z registrů.
Používají se Win32 funkce jako LsaOpenPolicy a LsaRetrievePrivateData. Byla to jen pekelná dřina rozchodit všechny ty definice pinvoke. Hlavně jsem chtěl dokázat, že to jde přes PowerShell. Takže opět žádný antivirus ani nemrkne jak jsem se snažil ukázat už na konferenci HackerFest.
Je to strašné množství kódu, takže jsem to neupravoval pro samotné zveřejnění. Je to prostě součást mých knihoven ADLAB (lib-common, lib-modifyActions a lib-utils). Pokud by to někdo chtěl vyzkoušet, tak samozřejmě může následovně. Stačí stáhnout ty tři soubory. Pokud si nestáhnete lib-modifyactions.ps1, tak budete mít jistotu, že vám to na systému nic nezmění. Veškeré měnící funkce jsou právě umístěné pouze v tom lib-modifyActions.ps1, abyste si je nemuseli stahovat pro jistotu.
Jenže bez jisté modifikace registrů z toho nepřečtete hesla služeb. Přečtete heslo počítače do domény, to ano ($machine.acc). A DefaultPassword taky. Prozatím se mi nepodařilo zjistit jak to udělat, abych nemusel ručně duplikovat tu registrovou hodnotu. Ony totiž LSA secrets, které začínají _SC_ jsou tak zvané machine secret, které může údajně číst pouze "operating system". Netuším, co znamená pojem operating system, ale nepodařilo se mi to překonat ani pomocí privileges, ani ničím jiným. Takže v tom článku borci prostě okopírují ta data a pak to přečtou. Tak to dělám taky. Akorát já to dělám tak, aby to fungovalo, narozdíl od nich (pinvoke RegQueryValueEx a RegSetValueEx :-)
Ale je to nepodporované a obával bych se, že vám to může poškodit LSA databázi, takže jen pro testovací účely a nikoliv v produkci.
Takže pouze BEZPEČNÉ čtení všeho co jde, BEZ MODIFIKACÍ. Nepřečtete ale hesla služeb (service passwords):
lib-common.ps1
lib-utils.ps1
Get-LsaSecrets
Pokud chcete číst hesla služeb, musíte nechat ten skript kopírovat klíče s těmi LSA private data object, takže POUZE do TESTOVACÍHO PROSTŘEDÍ, určitě NEZKOUŠET v PRODUKCI (nebo třeba offline pro forensic analýzu):
lib-common.ps1
lib-utils.ps1
lib-modifyActions.ps1
Get-LsaSecrets -Name $null -returnAsByteArray $false -forceMachineSecretsDecryptionByKeyCopyOperation $true
Výsledkem je prostě list jednotlivých LSA secrets. Pokud se něco nepodaří přečíst, prostě dostanete jenom datum a čas jeho změn, ten jde přečíst vždycky.