Hibernacja jest zła, czyli o eskalacji przywilejów

Jak w przekonywujący sposób pokazać, że hibernacja jest niebezpieczna? Wystarczy w prosty sposób eskalować swoje uprawnienia, na przykład do poziomu Local System.

Chwila z debuggerem

Na jakiej podstawie chcę wykonać ten straszliwy atak? Zasada jego działania jest prosta – chcę zmodyfikować pamięć w taki sposób, by pewien proces miał nieco większe uprawnienia. W tym celu wystarczy jeśli zmodyfikuję nieco strukturę EPROCESS tak, by Token wskazywał nieco gdzie indziej.

Najpierw trzeba wybrać sobie ofiary, na przykład te dwa procesy:

PROCESS 8a17cda0 SessionId: none Cid: 04a4 Peb: 7ffd5000 ParentCid: 0004 DirBase: 0a940040 ObjectTable: e10171d0 HandleCount: 19. Image: smss.exe

PROCESS 88570020 SessionId: 0 Cid: 072c Peb: 7ffd9000 ParentCid: 0fc8 DirBase: 0a9406a0 ObjectTable: e1c733b8 HandleCount: 29. Image: cmd.exe

W ramach demonstracji przejmę sobie uprawnienia procesu smss.exe i przypiszę je do procesu cmd.exe. Najpierw zobaczę, gdzie znajdują się tokeny w przypadku tych procesów:

lkd> dp 8a17cda0+0x0C8 8a17ce68 e31e79d9 00000001 a780a1c0 00000000

lkd> dp 88570020+0x0C8 885700e8 e1fdde27 00000001 a6d73a80 00000000

Adresy 8a17cda0 oraz 88570020 to adresy struktury EPROCESS powiązanej z wybranymi procesami, 0x0c8 to offet pod którym znajduje się wskaźnik na token. Sztuka, której chcę dokonać sprowadza się do zmiany wartości e1fdde27 na e31e79d9. Można to zrobić tak:

lkd> ep 88570020+0x0C8 e31e79d9

A teraz wystarczy szybko sprawdzić czy operacja się powiodła:

C:\Program Files\Support Tools>whoami.exe /all [User] = “NT AUTHORITY\SYSTEM” S-1-5-18

[Group 1] = “BUILTIN\Administrators” S-1-5-32-544 [Group 2] = “Everyone” S-1-1-0 [Group 3] = “NT AUTHORITY\Authenticated Users” S-1-5-11

(X) SeTcbPrivilege = Act as part of the operating system (O) SeCreateTokenPrivilege = Create a token object (O) SeTakeOwnershipPrivilege = Take ownership of files or other objects (X) SeCreatePagefilePrivilege = Create a pagefile (X) SeLockMemoryPrivilege = Lock pages in memory (O) SeAssignPrimaryTokenPrivilege = Replace a process level token (O) SeIncreaseQuotaPrivilege = Adjust memory quotas for a process (X) SeIncreaseBasePriorityPrivilege = Increase scheduling priority (X) SeCreatePermanentPrivilege = Create permanent shared objects (X) SeDebugPrivilege = Debug programs (X) SeAuditPrivilege = Generate security audits (O) SeSecurityPrivilege = Manage auditing and security log (O) SeSystemEnvironmentPrivilege = Modify firmware environment values (X) SeChangeNotifyPrivilege = Bypass traverse checking (O) SeBackupPrivilege = Back up files and directories (O) SeRestorePrivilege = Restore files and directories (O) SeShutdownPrivilege = Shut down the system (O) SeLoadDriverPrivilege = Load and unload device drivers (X) SeProfileSingleProcessPrivilege = Profile single process (O) SeSystemtimePrivilege = Change the system time (O) SeUndockPrivilege = Remove computer from docking station (O) SeManageVolumePrivilege = Perform volume maintenance tasks (X) SeImpersonatePrivilege = Impersonate a client after authentication (X) SeCreateGlobalPrivilege = Create global objects

Nie, nie jest to podatność. Posiadając prawa administratora mogę modyfikować zawartość pamięci operacyjnej systemu. W tym wypadku trudno nawet powiedzieć, że dokonałem eskalacji uprawnień, jako administrator posiadam takie uprawnienia, lub jestem w stanie je sobie nadać. Problem pojawia się wtedy, gdy mogę modyfikować zawartość pamięci systemu bez posiadania odpowiednich uprawnień.

Plik hiberfil.sys

Z definicji jeśli system jest wyłączony, nie może się bronić (bo nie działa). W przypadku hibernacji system jest “jakby” wyłączony, ale jego stan jest zachowany w pliku hiberfil.sys , który jest zrzutem pamięci systemu. Oczywiście jest to pewne uproszczenie, bo pamięć jest przechowywana w kilku miejscach, między innymi w pliku wymiany pagefile.sys (przy okazji, patrz: Vista RC2 vs. pagefile attack (and some thoughts about Patch Guard)). Jeśli atakujący jest w stanie zmodyfikować zawartość pliku hiberfil.sys lub pagefile.sys to efektywnie modyfikuje zawartość pamięci w systemie, bo po wybudzeniu z hibernacji system załaduje już tę zmodyfikowaną pamięć.

By nie było za łatwo plik hiberfile.sys nie jest liniowym zrzutem pamięci. Jego format jest mniej więcej udokumentowany, istnieje również projekt sandman, który pozwala na czytanie i modyfikowanie zawartości pliku hiberfil.sys , do wykonania zadania w zasadzie wystarczy funkcja HiberPatch. Instrukcję jak dokładnie przeprowadzić atak na hiberfil.sys pominę.

Na zasadzie już zupełnie luźnych pomysłów podejrzewam, że poprzez modyfikację pamięci zapisanej w pliku hiberfil.sys oraz pagefile.sys można równie dobrze wpisać komuś malware bezpośrednio do pamięci.

Jak się (nie)obronisz

Osobiście uważam, że wraz ze wzrostem znaczenia urządzeń przenośnych (np. laptopów), zawartość dysków należy szyfrować. Jeśli ktoś później zgubi laptopa, dysk będzie zaszyfrowany razem z plikiem hiberfil.sys.

Ciekawym scenariuszem może być ochrona przed użytkownikiem, który koniecznie chce zwiększyć swoje uprawnienia na firmowym sprzęcie. Siłą rzeczy użytkownicy tacy znają hasło potrzebne do uruchomienia systemu (czyli rozszyfrowania dysku), tak więc szyfrowanie nie rozwiązuje problemu. Oczywiście można zakładać, że rozszyfrowanie dysku (podanie hasła) jest jednoznaczne z uruchomieniem systemu, a więc system zaczyna bronić się sam, ale założenie to jest nie do końca uprawnione. Wystarczy tu przykład TrueCrypt, z którego pomocą zupełnie “legalnie” mogę montować szyfrowane dyski bez bootowania systemu. Tego typu możliwość jest konieczna choćby z uwagi na odzyskiwanie systemu po awarii, bo jak inaczej dostać się do danych na zaszyfrowanym dysku, jeśli system operacyjny tchórzliwie odmawia współpracy witając nas porannym BSODem?

Warto przy okazji zwrócić uwagę, że problem, który tu opisuje nie jest ograniczony do pliku hiberfil.sys. Można sobie wyobrazić analogiczne scenariusze z wykorzystaniem na przykład firewire.

Oryginał tego wpisu dostępny jest pod adresem Hibernacja jest zła, czyli o eskalacji przywilejów

Autor: Paweł Goleń