Długo zbierałem się do artykułu dotyczącego COM Hijackingu. Ostatnie projekty w których uczestniczyłem uświadomiły mnie, jak mała jest świadomość dotycząca metod persistence w systemie Windows, szczególnie tych, które wykraczają poza rejestry RunOnce czy katalog Startup. W tym wpisie powiemy sobie w jaki sposób uzyskać persistence za pomocą COM hijacking, oraz jak połączyć tę technikę z DLL Proxying w celu maksymalizacji powodzenia operacji. Artykuł jest kontynuacją wcześniejszych artykułów dotyczących persistence w systemie Windows.
Wstęp
COM (Component Object Model) jest standardem programowania interfejsów oprogramowania, który jest niezależny od języka programowania i umożliwia powoływanie obiektów klas niezależnie od wykorzystywanej technologii, a nawet niekoniecznie na tej samej stacji. COM jest powszechnie wykorzystywany w systemach Windows, a spora część oprogramowania (np. przeglądarka Edge, Eksplorator plików) korzysta z instancji obiektów klas COM oraz z ich zdefiniowanych interfejsów.
Komponenty COM są zarejestrowane w rejestrze systemu, a dla każdego komponentu przypisany jest zw. CLSID (Class ID). To umożliwia systemowi łatwe odnalezienie i załadowanie odpowiednich komponentów w razie potrzeby. Komponenty te znajdują się w następujących miejscach:
- HKCU:\SOFTWARE\Classes\CLSID\
- HKLM:\SOFTWARE\Classes\CLSID\
Czym jest COM Hijacking
Celem techniki COM Hijacking jest zapewnienie sobie persistence w systemie. Metoda ta ma pewne podobieństwa do DLL Hijacking. W przypadku DLL Hijacking najczęściej wyszukujemy biblioteki DLL, które sa poszukiwane przez system w katalogach zapisywalnych przez danego użytkownika, a następnie „podrzucamy” tam złośliwą DLLkę. W ten sposób uzyskujemy wykonanie kodu lub persistence, w zależności od okoliczności.
Technika COM Hijacking wygląda podobnie:
- Wyszukujemy CLSID klasy z rejestru HKCU, która próbuje być regularnie ładowana przez system, ale nie zostaje odnaleziona.
- Tworzymy nowy klucz rejestru HKCU z nazwą odnalezionego CLSIDu. Następnie tworzymy klucz o nazwie „InprocServer32” o domyślnej wartości wskazującej na „złośliwą” bibliotekę DLL.
- Od tej chwili „nasz” CLSID z HKCU jest ładowany przez dany proces.
W tym momencie mógłbym pokazać kilka screenów i zakończyć artykuł, ale podczas testowania ww. scenariusza często dochodziło do sytuacji, w której system operacyjny lub niektóre jego elementy przestawały działać. Nie ma w tym nic dziwnego, większość klas, których system nie znajduje w HKCU znajdują się w rejestrze HKLM. Umieszczając nową klasę i DLLkę w HKCU powodujemy, że system nie ładuje prawidłowych komponentów z HKLM. Z takim „kulawym” persistence nie zajechalibyśmy daleko w realnych działaniach. Z pomocą przychodzi nam technika zwana DLL Proxying.
DLL Proxying
Dll proxying to technika, dzięki której nasza DLL będzie przekazywać zapytania o nieznane funkcje do inne, oryginalnej biblioteki.
W sieci Internet istnieje wiele projektów które mogą pomóc nam w realizacji tej techniki, ale jednym z przyjemniejszych jest SharpDllProxy. Dzięki niemu łatwo uzyskamy wpisy do umieszczenia w złośliwej DLLce, a ponadto program skopiuje oryginalną bibliotekę nadając jej odpowiednią nazwę.
COM Hijacking w praktyce
Teorię mamy za sobą, czas najwyższy na praktykę. W celu zlokalizowania CLSIDów do podmiany, możemy wykorzystać program Process Monitor z pakietu SysInternals. Potrzebne nam będą:
- Operacje typu „RegOpenKey”, ponieważ szukamy wpisów rejestru,
- Ścieżka zawierająca InProcServer32, ponieważ znajduje się on w kluczu CLSID i zawiera ścieżkę do oryginalnej DLLki,
- Rezultat „NAME NOT FOUND”, ponieważ szukamy miejsca, które możemy podmienić.
Po uruchomieniu filtra należy zostawić go na parę minut oraz pracować na systemie. Po chwili program zwróci listę szukanych klas COM w rejestrze, które nie są znajdowane.
Następnie zapisujemy wyniki do formatu CSV i korzystamy ze skryptu COMHijacktoolkit z projektu aCOMplice.
Wynikiem jest nazwa binarki która szuka danej klasy oraz jej CLSID. To, że danego CLSID nie ma w HKCU, nie znaczy, że nie jest on obecny w HKLM. W takiej sytuacji zastąpienie go wpisem w HKCU mogłoby zakłócić działanie systemu.
Powyższy wynik potwierdza nasze przypuszczenia, ale dzięki technice DLL Proxying nie musimy się tym martwić. Wykorzystując narzędzie SharpDLLProxy skopiujmy oryginalną DLLkę i stwórzmy wpisy linkera do wykorzystania w złośliwej DLLce.
Narzędzie SharpDllProxy stworzyło:
- Szablon zlośliwej dllki, z którego pobierzemy tylko wpisy linkera
- Skopiowało oryginalną dllkę i nadało jej losową nazwę.
- tmp4F61 to kopia oryginalnej biblioteki CapabilityAccessManagerClient.dll
- CapabilityAccessManagerClient_pragma.c to szablon złośliwej dllki.
Z szablonu należy skopiować tylko instrukcje dla linkera, aby eksportował funkcje z oryginalnej DLL (CapabilityAccessManagerClient.dll) do biblioteki o nazwie tmp4F6.
Zostawiając tego typu wpisy, będziemy zmuszeni umieścić bibliotekę o nazwie tmp4F61.dll obok złośliwej, docelowej biblioteki. Jest to oczywiście możliwe, ale jeżeli chcemy, aby zapytania były przekazywane do oryginalnej biblioteki należy zmienić te wpisy, w taki sposób aby wskazywały na bibliotekę CapabilityAccessManagerClient.
Mając przygotowany kod złośliwej DLLki należy ją skompilować i utworzyć odpowiedni CLSID w rejestrze.
Po chwili jesteśmy w stanie zaobserwować pojawienie się MessageBox z komunikatem „Hello from Malicious dll”
Mamy wykonanie kodu! Ponadto, dzięki zastosowaniu techniki DLL Proxying działanie systemu pozostało nienaruszone, ponieważ biblioteka CapabilityAccessManagerClient jest w dalszym ciągu odpytywana przez źródłowy proces.
Podsumowanie
Połączenie dwóch technik:
- COM Hijacking
- Dll Proxying
stworzyło nam ciekawą możliwość na uzyskanie persistence w przejętym systemie. Ponadto, do wykonania ww. ataku nie potrzeba uprzywilejowanego użytkownika, ponieważ wszystkie operacje wykonujemy na rejestrze HKCU. Kluczem do sukcesu jest znalezienie odpowiedniej klasy COM, która będzie regularnie uruchamiana przez użytkownika podczas pracy systemu. Ponadto, w docelowym kodzie złośliwej bilioteki należy zaimplementować sleep lub instrukcję warunkujacą uruchomienie kodu.
W omawianym wyżej przypadku MessageBox pojawiał się co +/- 5 minut, podczas standardowej pracy na systemie. Taka ilość połączeń do C2 na pewno wzbudziłaby czujność EDRów. Myślę jednak, że prosty if w kodzie, który sprawdza czy połączenie jest nawiązane rozwiązuje taki problem.
Jak się bronić?
Mimo, że technika jest ciekawa i na pewno bardziej „stealthy” niż klasyczne metody persistence, jest już dość dobrze poznana i opisana. Podstawową metodą obrony jest prawidłowo skonfigurowany i wdrożony EDR oraz antywirus, który uniemożliwi umieszczenie złośliwego pliku DLL w systemie. Jeżeli chodzi o monitoring i logi, Blue Team powinien zwrócić szczególną uwagę na modyfikowanie wpisów CLSID w rejestrze.