Kilka słów o persistence w systemie Windows – cz. 2

Ostatnio obiecałem Wam kontynuację wątku o persistence w systemach Windows. W poprzednim wpisie opisałem dwie, dość proste metody:

  • Logon Script
  • Windows Service

Obydwie mają odzwierciedlenie w tablicy MITRE, ale moim zdaniem nie należą do najbardziej wyrafinowanych. Niemniej, zarówno skrypty logowania jak i persistence z wykorzystaniem Windowsowych serwisów były powszechnie wykorzystywane przez znane grupy APT, m.in. Kimsuky z Korei Północnej (obydwie techniki). W dzisiejszym wpisie chciałbym podzielić się z Wami kolejną techniką uzyskiwania persistence w systemach Windows:

  • WMI Event Subscription

Powyższa metoda jest nieco bardziej skomplikowana i może być trudniejsza w detekcji od serwisów i skryptów.

Elevated: WMI Events Subscription – kilka słów teorii

WMI jest zestawem protokołów, który pozwala na monitorowanie i zarządzanie elementami zarówno lokalnego jak i zdalnego hosta. Część z Was pewnie wie, że za pomocą WMI (Windows Management Instrumentation) możemy wykonać również lateral movement poprzez wykonanie programów na zdalnym hoście, możemy również uzyskać dostęp do różnych informacji zarówno na lokalnym jak i zdalnym systemie. WMI opiera się na hierarchicznej strukturze przestrzeni nazw i klas, np. klasa „win32_Process” odpowiada za procesy, a win32_service za serwisy. Za tworzenie nowych procesów odpowiada np. metoda Create klasy win32_Process1, widzimy więc tu czysto obiektowe podejście. Choć sama idea WMI jako narzędzia umożliwiającego zarządzanie elementami systemu w rozproszonym środowisku może wydawać się nieco zawiła, to uzyskanie persistence za pomocą WMI jest całkiem proste.

Opis klasy Win32_Process

Persistence za pomocą eventów WMI możemy uzyskać na dwa sposoby – z wykorzystaniem plików języka MOF (Managed Object Format) i kompilatora mofcomp.exe lub za pomocą zwykłego powershella. Język MOF opisuje klasy standardu CIM (czyli klasy WMI, który jest Microsoftową implementacją CIM), za pomocą języka MOF możemy stworzyć nową klasę i przypisać jej metody i inne parametry, a także stworzyć instancje (obiekty) istniejących już klas.

Możemy zarządzać elementami systemu za pomocą instancji klas WMI (na obrazku Win32_CDROMDrive).

Elevated: WMI Events Subscription – wstęp do praktyki

Stworzenie persistence za pomocą WMI polega w dużym skrócie na stworzeniu instancji klasy __EventFilter, która jest triggerem, czyli definiuje nam warunki przy których ma zostać wykonana pewna czynność. Tymi warunkami może być np. otworzenie notatnika, programu Word, zainicjowanie ruchu sieciowego na konkretny port czy restart stacji. Potem należy stworzyć instancje klasy CommandLineEventConsumer, która definiuje nam czynności, które mają się wydarzyć przy spełnieniu wcześniej opisanego warunku. Ostatnim etapem jest stworzenie obiektu klasy __FilterToConsumerBinding, która łączy, mapuje ze sobą pozostałe dwie instancje.

źródło: https://pentestarmoury.com/2016/07/13/151/

Spróbujmy więc stworzyć persistence, który polega na monitorowaniu logowania się użytkownika do systemu. Tradycyjnie, za ten event odpowiada EventCode 4624. O elementy dziennika zdarzeń za pomocą WMI możemy zapytać w następujący sposób:

Listując kolejne wydarzenia z dziennika zdarzeń widzimy jednak, że dziennik pełny jest eventów niezwiązanych z interaktywnym logowaniem użytkowników. Najczęściej widzimy logowania konta SYSTEM oraz logowania konta hosta, które wynikają z wewnętrznych mechanizmów Windowsa.

Jeden z wielu eventów generowanych przez wewnętrzne mechanizmy systemu Windows

Wprawdzie moglibyśmy ograniczyć się do wyszukania nazwy konta użytkownika w polu „Message”, ale wtedy uzyskamy persistence tylko i wyłącznie w sytuacji w której zaloguje się konkretny użytkownik – choć to też może mieć swoje zastosowanie. Jeżeli chcemy wykonać jakieś działanie w przypadku każdego interaktywnego logowania warto przeszukać event pod kątem wystąpienia stringu „User32”, który znajduje się wtedy w polu „Logon Process”.

Okej, znaleźliśmy już sposób na przeszukanie Dziennika Zdarzeń pod kątem interaktywnych logowań użytkowników. W ten sam sposób możemy napisać triggery dla innych, dowolnych zdarzeń. Interesuje nas uptime systemu? Nic prostszego, informacje o tym jak długo system jest uruchomiony znajdziemy dzięki klasie Win32_PerfFormattedData_PerfOS_System.

Znalezienie informacji o uptime systemu

Intrinsic Events – czyli jak śledzić zmiany w danych WMI

Z reguły nie chcemy triggerować naszych payloadów w każdej sytuacji, kiedy w Event Logach będą informacje o zalogowanych użytkownikach, ponieważ taka sytuacja będzie miała miejsce zawsze. Interesuje nas zmiana pewnych danych w logach lub pojawienie się nowych. I tu znów z pomocą przychodzi nam dokumentacja Microsoftu i pojęcie tzw. Intrinsic Events2 (pol. wewnętrzne eventy (?)). Intrinsic Events to zdarzenia, które są generowane przy każdej zmianie instancji czy klasy WMI. Innymi słowy – jeżeli pojawi się nowy event w Dzienniku Zdarzeń, to pojawi się nowa instancja klasy Win32_NTLogEvent co wygeneruje zdarzenie __InstanceCreationEvent. Ponadto, za pomocą słowa kluczowego „WITHIN” możemy wskazywać w zapytaniach WQL czas pomiędzy kolejnymi odpytaniami WMI.

Elevated: WMI Events Subscription – praktyka

Stworzenie persistence zacznijmy od wygenerowania triggera – czyli instancji klasy __EventFilter. Przykładowa instancja, która śledzi logowania kolejnych interaktywnych użytkowników w systemie wygląda następująco:

Następnie powinniśmy stworzyć instancję klasy CommandLineEventConsumer, która odpowiada za czynności, które mają zostać wykonane, gdy zostanie wywołany trigger.

Pod zmienną $StagerPayload powinna kryć się komenda, którą chcemy uruchomić gdy zostanie wygenerowany interesujący nas Event. Może być to uruchomienie biblioteki .dll za pomocą rundll32.exe, bezpośrednie odwołanie do pliku wykonywalnego lub jakiekolwiek inne metody code execution jakie znacie.

Ostatnim etapem jest utworzenie instancji klasy __FilterToConsumerBinding, czyli zamapowania czynności do triggera, który ma ją wywołać.

Po wykonaniu powyższego kodu powinniśmy mieć zarejestrowane w systemie obiekty klas __EventFilter, CommandLineEventConsumer oraz __FilterToConsumerBinding. Aby sprawdzić je po kolei należy wykonać polecenia:

  1. Get-WmiObject -Namespace root\Subscription -Class __EventFilter
  2. Get-WMIObject -Namespace root\Subscription -Class CommandLineEventConsumer
  3. Get-WMIObject -Namespace root\Subscription -Class __FilterToConsumerBinding
__EventFillter czyli trigger
Consumer, czyli czynność, która ma zostać wykonana w przypadku wyzwolenia triggera
__FilterToConsumerBinding, czyli zamapowanie czynności do triggera

Jak sami widzicie na powyższych slajdach, nazwałem swój filtr „Fileless WMI Persistence login”. Po pierwsze – żaden z niego fileless, ponieważ consumerem jest zwykły złośliwy plik .exe. Po drugie – w działaniach RT proponuję unikać sformułowań „Persistence”, bo rzuca się to w oczy prawie tak samo jak „fun.exe”.

Elevated: WMI Events Subscription – czy to w ogóle działa?

Po udanym logowaniu udało nam się otrzymać połączenie do serwera CS.

Używając programu Autoruns, możemy dowiedzieć się czy w naszym systemie mamy zarejestrowane Eventy WMI.

Wynik działania programu Autoruns

Dla Blue Teamów – na poniższej stronie macie numery eventów, które należy śledzić, aby odnaleźć ten typ persistence w Waszej infrastrukturze.

https://in.security/2019/04/03/an-intro-into-abusing-and-identifying-wmi-event-subscriptions-for-persistence

Zakończenie

Po omówieniu Persistence przez WMI został nam już tylko COM Hijacking, ale czuje, że ten temat zasługuje na oddzielny wpis. W niedługim czasie postaram się również pokazać coś bardziej przyziemnego – RBAC, czyli Resource Based Constrained Delegation na przykładzie challengu z TryHackme. Stay tuned!

  1. https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-process
  2. https://docs.microsoft.com/en-us/windows/win32/wmisdk/determining-the-type-of-event-to-receive

Dodaj komentarz