Kvůli některým svým pokusům, pentestům a zkoumání volatile state jsem si napsal prográmek na vyhledávání AES klíčů v paměti. Vzhledem k tomu, že to je zajímavý koncept a přitom poměrně neznámý, tak jsem si říkal, že udělám kamarádovi radost a napíšu i něco techničtějšího než kalendář :-)
Je to součást mého nástroje BitColdKit, přesněji jeho funkce BitColdKit-FindAesKeys. Funkce hledá AES klíče buď v nějakém souboru na disku (nejspíš asi memory dump provedený procdumpem nebo celý RAM imidž - ten vytvářím třeba pomocí nástroje RamCapturer). Umí ale hledat i přímo v paměti nějakého běžícího procesu, stačí zadat jeho jméno, nebo process Id.
AES klíče jsou bezva :-) Cokoliv je dneska šifrované AESem. BitLocker například. Nebo webové aplikace a služby (web service) velmi rády využívají šifrované cookies, nebo view state. SQL databáze mohou být šifrované. ADFS i microsoft identity manager (FIM/MIM/MIIS/ILM) si šifrují nějaké tajné údaje v databázi. SharePoint má hesla managed accountů i jiné tajné údaje samozřejmě šifrovaná v databázi. Rozličné password managery (keepass) také šifrují svoje databáze hesel pomocí AES a mají tedy tyto šifrovací klíče v paměti po dobu svého běhu.
Jak to funguje
Nemusíte vůbec vědět, kde ty klíče v paměti jsou. AES klíče jsou sice jen 16B (AES 128) až 32B (AES 256) dlouhé. Takže jak je najdete aniž byste věděli, kde by v té paměti přibližně měly být? Mohli byste začít tím, že vyhledáte bloky paměti s vysokou entropií - klíče budou nejspíš hodně náhodné, aby byla šifra kvalitní. Ale tohle není efektivní, jak jsem prověřil. Paměť je plná různých entropických bloků. Tohle není cesta.
Lepší je využít key schedule. Na šifrování se nepoužívá přímo jen AES klíč. Nejprve se AES key rozšíří do tzv. key schedule, což je blok o velikosti 176B pro AES 128, délce 208B pro AES 192 a velikosti 240B pro AES 256. A teprve touto key schedule se projíždí a xorují vstupní data a vzniká výsledný šifrát. Generování key schedule je zbytečně pomalé na to, aby se to dělalo při každém požadavku na šifrování. Takže všechny AES knihovny vždycky při inicializaci klíče vytvoří rovnou key schedule a tu mají dlouhodobě v paměti místo toho klíče. Dělají to tak samozřejmě i netfx třídy RijndaelManaged a AesCryptoServiceProvider.
Není až tak důležité, jak taková AES key schedule vzniká z klíče, ale můžete se podívat na obrázky:
Části klíče se prostě nějak zaxorují do sebe a tak se postupuje až je to komplet tak dlouhé, jak je potřeba. No a máme key schedule.
Co je na tom parádní, že na začátku je přímo ten AES key. A za ním následuje mnoho bajtů, které jsou z něho přímo vypočítány. Takže se to krásně hledá.
Prostě jedete po paměti, u každého bajtu se zastavíte a zkusíte to od jeho pozice vzít jako potenciální AESový klíč. Podle těchto 16B/32B napočítáte, jak by vypadala šedula, kdyby to byl opravdu klíč. A porovnáte to s tím, co je ve stutečnosti v paměti. Pokud to sedí, tak to byl klíč. Pokud to nesedí, tak to klíč nebyl.
Napsal jsem si tedy svoji vlastní implementaci AESu do C# (viz. zdrojáky BitColdKitu) a používám svoji počítačku key schedule.
Jak to vyzkoušet
Pokud to chcete otestovat, prostě si stáhněte BitColdKit. Přímo z paměti procesu můžete klíče hledat buď pokud proces běží pod stejným účtem jako BitColdKit - to ani nemusíte být členem skupiny Administrators. Pokud proces běží pod jiným účtem, budete muset být členem skupiny Administrators, aby mu mohl BitColdKit přečíst paměť. Přesněji řečeno, pro čtení paměti cizích procesů potřebujete právo (user right) Debug programs (SeDebugPrivilege).
Nejjednodušší a nejhezčí je pokus na BitLocker. Jestli máte na počítači BitLockerem zašifrovaný, a aktuálně odemčený, nějaký oddíl, jeho AES klíč je v paměti RAM. Udělejte si memory dump pomocí RamCapturer a ve výsledku najdete AES klíče (neboli FVEK). Trvá to cca 20 minut pro 8 GB RAM memory image pro jednu délku klíče, pokud víte jakou hledáte.
Dá se to zkusit také na lsass, nebo nějaké w3wp procesy IISka. A cokoliv jiného, co šifruje AESem.
Krásně to funguje na keepass. Keepass si šifruje databázi hesel právě AES klíčem odvozeným z vašeho vstupního hesla. Stačí ho tedy spustit, zadat to vstupní heslo (master password) a potom pomocí BitColdKit-FindAesKeys -process keepass klíč vyndat z paměti.
Jen tak bokem, keepass má také v paměti všechna uložená hesla, která jste použili, v čisté formě, takže se také dají získat z memory dumpu. BitColdKit má na to funkci BitColdKit-FindString, která právě hledá v paměti procesů nějaké řetězce v čisté formě.