Moduły PowerShell – wsparcie leniwego admina czy szwajcarski scyzoryk hakera - część 2

26.10.2022 | Bartosz Chałek

Wstęp

W pierwszej części artykułu pokazywałem przykłady użycia powershella w automatyzacji, zaprezentowałem moduły i przedstawiłem ich możliwości wykorzystania. Teraz czas na kolejną porcje informacji o powershellu. 

 

Moduły importowane domyślnie

Jak wcześniej wspomniałem moduł PSReadLine jest wczytywany domyślnie z katalogu C:\Program Files\WindowsPowerShell\Modules przy każdym uruchomieniu konsoli.  Co jeśli jednak skopiujemy taki moduł do katalogu modułów naszego użytkownika?

Źródło: opracowanie własne

 

Wygląda ciekawie, ale z jakiegoś powodu powershell nie był w stanie go zaimportować…Tylko dlaczego? Pozwala nam to odkryć komenda Import-Module PSReadLine:

Źródło: opracowanie własne

 

Jak widać występuje problem z wczytaniem pewnych plików modułu. Sprawdźmy co stanie się jeśli uruchomimy powershella z flagą –ExecutionPolicy Bypass?

Źródło: opracowanie własne

 

Jak widać moduł został nie tylko wczytany poprawnie , ale pomimo że znajduje się on też w katalogu C:\Program Files\WindowsPowerShell\Modules to został wczytany z katalogu użytkownika.

Jeśli jednak mamy uruchamiać to z flagą bypass, to równie dobrze moglibyśmy zawrzeć to w plikach profile. Spróbujmy więc doprowadzić do sytuacji kiedy moduł PSReadline zostanie wczytany bez niej.

Skoro błąd występuje przy imporcie pliku PSReadLine.format.ps1xml to spróbujmy go usunąć – ważne, żeby usunąć go również z pliku psd1 zawierającego deskryptor modułu:

Źródło: opracowanie własne

 

Źródło: opracowanie własne

 

Niestety moduł w dalszym ciągu nie importuje się poprawnie ze względu na blokadę pliku PSReadLine.psm1. Analogicznie jak wcześniej spróbujmy go usunąć:

Źródło: opracowanie własne

 

Jak widać udało się poprawnie wczytać moduł, a ponowne uruchomienie powershella wskazuje, że został on automatycznie załadowany. Zerkając do proces hackera można zobaczyć w modułach procesu, że wczytana została biblioteka z katalogu użytkownika:

Źródło: opracowanie własne

 

W tym miejscu warto się zatrzymać i zastanowić co nam to da? Jeżeli użytkownik wejdzie na dowolny inny komputer, jego profil zostanie wczytany, a następnie uruchomi konsolę powershella, to do pamięci procesu zostanie wczytana przygotowana przez nas biblioteka. Nie oznacza to jednak jeszcze uruchomienia jakiegokolwiek polecenia z tej biblioteki.

Szukając w internecie informacji o modułach powershella za pośrednictwem bibliotek dll, znalazłem ciekawy artykuł mówiący o istnieniu kilka klas i interfejsów, które są automatycznie uruchamiane przy imporcie biblioteki modułu. Te klasy to:

  • CmdletProvider
  • DriveCmdletProvider
  • IModuleAssemblyInitializer

Implementując swoją „złośliwą” bibliotekę zawierającą klasy dziedziczące po tych obiektach, jesteśmy w stanie wyzwolić swój kod już na etapie importu takiej biblioteki.

Spróbujmy przygotować przykładową klasę zawierającą „złośliwy kod”:

Źródło: opracowanie własne

 

Źródło: opracowanie własne

 

Źródło: opracowanie własne

 

Sukces! Udało się wykonać nasz złośliwy kod przy uruchomieniu procesu.

 

Zatrzymajmy się teraz po raz drugi. Uruchamiając interaktywnie konsolę wczytujemy naszą bibliotekę, a następnie wykonujemy kawałek naszego kodu. Co jeśli powershell zostanie uruchomiony z parametrem –Command albo –File, albo jeśli ktoś uruchomi np. Powershell ISE?

Niestety, ale moduł PSReadline uruchamiany jest tylko w przypadku otwarcia interaktywnej konsoli. W przypadku powershell ise domyślnie wczytywanym modułem jest moduł ISE, który z kolei znajduje się w katalogu:

Źródło: opracowanie własne

 

Co ciekawe, analogicznie jak w przypadku psreadline, przeniesienie modułu ISE do katalogu użytkownika pozwala na zastąpienie tego modułu naszym potencjalnie złośliwym:

Źródło: opracowanie własne

 

Jednak w dalszym ciągu wymagana jest interakcja użytkownika. Jak napisałem na początku artykułu, powershell jest używany przez wielu administratorów do automatyzacji wykonywanych operacji na komputerze np. do weryfikacji konfiguracji środowiska, przeprowadzenia automatycznych akcji, diagnostyki systemu itp. itd.

W takim razie może istnieją moduły, które są wczytywane zawsze i automatycznie tak jak PSReadLine i ISE? W tym celu trzeba zobaczyć jak mechanizm modułów działa. W procesie weryfikujemy biblioteki wczytane wraz z procesami powershell.exe i powershell_ise.exe. Warto zwrócić uwagę na bibliotekę System.Management.Automation.dll

Przy pomocy narzędzia dnSpy dekompilujemy ją:

Źródło: opracowanie własne

 

Jest to biblioteka napisana we .Net Frameworku, więc możemy podejrzeć jej kod oraz w łatwy sposób ją debugować. Poniżej zwrócę jednak uwagę na kilka ciekawych punktów w analizie flow importu.

W obiekcie System.Management.Automation.Runspaces.InitialSessionState można znaleźć informację o domyślnych metodach, dozwolonych wbudowanych aliasach i domyślnych modułach.

W obiekcie Microsoft.PowerShell.Commands.ModuleCmdletBase znajduje się wczytywanie modułu w zależności od rozszerzenia.

Na podstawie analizy działania można zauważyć kilka potencjalnie interesujących domyślnych modułów:

Źródło: opracowanie własne

 

Źródło: opracowanie własne

 

Warto w tym miejscu spojrzeć do plików psd1 tych modułów, żeby określić ich funkcjonalności. Na podstawie liczby funkcjonalności warto zwrócić uwagę na 3 moduły:

Źródło: opracowanie własne

 

Są to moduły bazowe, więc ich całkowita podmiana może zaburzyć ich działanie.  W związku z tym zamiast podmieniać bibliotekę zawierającą implementację komend, warto dodać w pliku psd1 dodatkową złośliwą bibliotekę (tą którą przygotowaliśmy i użyliśmy w przykładzie PSReadLine):

Źródło: opracowanie własne

 

Źródło: opracowanie własne

 

Źródło: opracowanie własne

 

Źródło: opracowanie własne

 

Następnie można obserwować jakie skrypty są uruchamiane automatycznie:

Źródło: opracowanie własne

 

Jaki w tym momencie mamy potencjalny zysk jako atakujący?

  • Jest to bardzo mało znana i nieoczywista metoda uzyskania persystencji.
  • Możemy zaimplementować np. bardzo małego droppera, który zapisze do katalogu użytkownika we wskazanej lokalizacji odpowiednie moduły. Następnie wystarczy, że poczekamy na dowolny domyślny skrypt uruchamiany jako użytkownik lub na otwarcie powershella przez użytkownika. Jeżeli profil użytkownika jest replikowany na inne serwery/komputery istnieje szansa, że nasz malware rozprzestrzeni się po organizacji.
  • Jeżeli użytkownik będzie miał podwyższone uprawnienia na komputerze, to taki malware może rozprzestrzenić się na innych użytkowników komputera poprzez umieszczenie się w ich katalogach domowych.

Uprzedzając pytanie: Jak taki user, nawet jako admin, miałby mieć dostęp do katalogu sieciowego innego użytkownika?

Wystarczy, że moduł skopiuje się do katalogu C:\Program Files\WindowsPowerShell\Modules. To sprawi, że każdy proces powershella, niezależnie od konta, taki złośliwy moduł wczyta:

Źródło: opracowanie własne

 

Podsumowanie

Jak widać  powershell to świetne i ułatwiające pracę,zarówno administratorom jak i hakerom,narzędzie. Skrypty i moduły powershella mogą być potężnym sprzymierzeńcem w arsenale jednych i drugich.

Zespoły Blue powinny zwrócić uwagę na pojawianie się w nowych modułów w katalogach użytkowników. Zwłaszcza na pojawianie się ich w globalnych katalogach modułów.

Zespoły Red mogą natomiast wykorzystać wskazane moduły zarówno przy próbie eksploitacji podatności pozwalających na zapis plików w systemie, jeśli w systemie dodatkowo działa jakiś skrypt który wyzwoli nasz moduł, jak również w próbach utrzymania persystencji lub stopniowego rozprzestrzeniania się w organizacji.