Analiza transkrypcji PowerShell

Raido Karro i Liisa Tallinn
28 maja 2020

nawet jeśli nie korzystasz z PowerShell na komputerach z systemem Windows, twoi przeciwnicy i testerzy pióra są. Po co używać niestandardowych narzędzi hax0r, gdy każda maszyna z systemem Windows ma wbudowane środowisko Skryptowe? Powershell pozwala atakującemu zrobić praktycznie wszystko, nie pozostawiając śladów na dyskach. Błędem jest nie kochać PowerShell jako atakującego i błędem jest nie kochać PowerShell logs jako obrońcy.

Poniżej znajduje się samouczek parsowania i zapytań za pomocą bezpłatnego analizatora dzienników SpectX, aby uzyskać ogólne statystyki, a także szczegółowe informacje z dzienników transkrypcji PowerShell, które są notorycznie trudne do przeanalizowania. Nie ma potrzeby importowania lub pobierania plików z ich bieżącego katalogu wyjściowego – SpectX uruchamia zapytania bezpośrednio na surowych dziennikach. Tworzenie czystego widoku z surowych dzienników zajmuje tylko kilka minut.

przesłaliśmy mały zestaw plików transkrypcji do naszego publicznego repozytorium S3-możesz wykonać poniższe zapytania dotyczące tych przykładowych danych. Pytania, które zadaliśmy w zapytaniach, mają na celu zbadanie podstawy i wykrycie nieprawidłowych (potencjalnie złośliwych) zachowań. Jakie były najwyższe komendy? Kiedy uruchamiano większość poleceń? Kiedy po raz pierwszy uciekli? Jakie były wyjścia poleceń, które pojawiły się na konsoli podczas uruchamiania polecenia-coś niezwykłego? Kim są najlepsi użytkownicy? Jacyś użytkownicy uruchamiający polecenia, których nie powinni uruchamiać? Najlepsze aplikacje hosta? Ile komend na godzinę / dzień / tydzień? A co z zamaskowanymi poleceniami? I tak dalej-gdy pojawi się powiesić spectx zapytań, kolejne pytania nigdy się nie kończy.

spis treści

informacje o transkrypcjach
jak włączyć rejestrowanie transkrypcji
Format dzienników transkrypcji
odczytywanie i analizowanie dzienników za pomocą SpectX
kto? Co? Kiedy? Jak? – zapytania

.. lub prawie ∞

Istnieją 3 rodzaje rejestrowania, które mogą być włączone dla PowerShell: rejestrowanie modułów, blokowanie skryptów i transkrypcja. Ponieważ dwa pierwsze mogą być postrzegane jako zdarzenia systemu Windows, często zaleca się ręczne czytanie plików tekstowych transkrypcji tylko wtedy, gdy pojawia się problem z monitorowaniem dwóch pierwszych. Jednocześnie informacje zawarte w transkrypcjach są najbardziej wszechstronne z tych trzech, a płaskie pliki tekstowe są znacznie bardziej wydajne niż zdarzenia Windows generowane przez rejestrowanie bloków modułów i skryptów. Na przykład uruchomienie prostego hosta zapisu „hello world” lub w tym przypadku „All you Need is Logs” powoduje 22 zdarzenia Windows z logowania modułów i bloków skryptów, ale te same informacje plus wyjście polecenia jest również rejestrowane w tym 1KB transkrypcji PowerShell:

**********************
Windows PowerShell transcript start
Start time: 20200521135800
Username: DESKTOP-7KL6SCQ\Loki
RunAs User: DESKTOP-7KL6SCQ\Loki
Configuration Name:
Machine: DESKTOP-7KL6SCQ (Microsoft Windows NT 10.0.18363.0)
Host Application: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Process ID: 5624
PSVersion: 5.1.18362.752
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.18362.752
BuildVersion: 10.0.18362.752
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1
**********************
**********************
Command start time: 20200521135818
**********************
PS C:\Users\Loki> write-host "All You Need is Logs"
All You Need is Logs
**********************
Command start time: 20200521135821
**********************
PS C:\Users\Loki> exit
**********************
Windows PowerShell transcript end
End time: 20200521135821
**********************

problem w tym, że logi transkrypcji były historycznie zaprojektowane do celów debugowania, czyli do czytania ludzi, a nie maszyn. Ich zawartość jest prawie swobodna i notorycznie trudna do przeanalizowania. Kopanie w internecie, można znaleźć kilka prób w Internecie, aby pobrać transkrypcje do narzędzia do przetwarzania dziennika, ale żadna z nich nie osiąga wyodrębniania poleceń, a także wyjścia poleceń do oddzielnych pól. Szkoda, bo wyjścia komend są rejestrowane tylko do transkrypcji, a wgląd w to, co faktycznie wydarzyło się w wyniku poleceń PS może być cenny.
Wpisz SpectX. Pomijając fazę przyjmowania i używając bloków konstrukcyjnych w języku parsowania, może wyodrębnić nie tylko pola użytkownika i hosta/maszyny w prologu, ale także czasy rozpoczęcia poleceń, polecenia i wyjścia. Ponieważ parser SpectX jest stosowany do surowych plików dziennika podczas wykonywania zapytania, oznacza to również, że możesz debugować, ulepszać i naprawiać parser z każdym zapytaniem w przypadku zmiany formatu dziennika. A dzienniki transkrypcji PowerShell są rzeczywiście niestabilne.
kiedy zaczynaliśmy pisać ten post, wierzyliśmy, że transkrypcje PowerShella są wszechmocne i rejestrują wszystko. Jednak bawiąc się poleceniami i wyjściami, okazało się, że jest wyjątek. Podczas uruchamiania skryptu PS z adresu URL transkrypt wychwytuje polecenie (w tym adres URL) i wyjście, ale pozostawia cię całkowicie ślepym w odniesieniu do zawartości skryptu lub poleceń uruchamianych przez skrypt. Na przykład, aby dowiedzieć się, co zrobił ten konkretny skrypt uruchamiany z adresu url, musisz przejść do zdarzeń systemu Windows utworzonych przez rejestrowanie modułów.

**********************
Windows PowerShell transcript start
Start time: 20200521141014
Username: DESKTOP-7KL6SCQ\Loki
RunAs User: DESKTOP-7KL6SCQ\Loki
Configuration Name:
Machine: DESKTOP-7KL6SCQ (Microsoft Windows NT 10.0.18363.0)
Host Application: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Process ID: 788
PSVersion: 5.1.18362.752
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.18362.752
BuildVersion: 10.0.18362.752
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1
**********************
**********************
Command start time: 20200521141021
**********************
PS C:\Users\Loki> iex (New-Object "net.webclient").DownloadString("http://spectx.com/test.ps1")
All You Need is Logs!
**********************
Command start time: 20200521141023
**********************
PS C:\Users\Loki> exit
**********************
Windows PowerShell transcript end
End time: 20200521141023
**********************

jak włączyć rejestrowanie transkrypcji PowerShell∞

1. Otwórz menu Start i wpisz „gpedit”, aby otworzyć okno Edytora zasad grupy lokalnej

2. Przejdź do szablonów administratora > komponenty systemu Windows > Windows PowerShell

3. Kliknij na 'Włącz transkrypcję PowerShell’

4. Wybierz 'Enabled’ i określ ścieżkę do katalogu wyjściowego. Ważne! Zaznacz to pole, aby włączyć nagłówki wywoływania. Spowoduje to zapisanie każdego uruchomienia polecenia z czasem rozpoczęcia polecenia.

5. Kliknij OK
6. Otwórz okno programu PowerShell, aby sprawdzić, czy rejestrowanie działa. Wpisz polecenie, np. prosty host zapisu: 'wszystko, czego potrzebujesz, to logi’, a następnie 'exit’.

7. Sprawdź, czy katalog wyjściowy podany w kroku 4 zawiera transkrypcję ze znacznikami czasu i działaniami w kroku 6.

na dłuższą metę dobrym pomysłem jest scentralizowanie zbioru transkryptów PowerShell w celu ich analizy na dużą skalę, np. sprawdź ten tutorial autorstwa @ dan_franciscus na blogu 4sysops.

Transcript Log Format ∞

kilka słów o formacie dziennika i logice parsera. Jeśli wolisz otrzymywać zapytania i nie interesujesz się anatomią plików dziennika i parsera, przejdź do następnej sekcji. Oto próbka surowego dziennika transkrypcji PS V. 5.1:

**********************
Windows PowerShell transcript start
Start time: 20171030223248
Username: WIN-FT17VBNL4B2\Administrator
RunAs User: WIN-FT17VBNL4B2\Administrator
Machine: WIN-FT17VBNL4B2 (Microsoft Windows NT 10.0.14393.0)
Host Application: C:\Windows\system32\WindowsPowerShell\v1.0\PowerShell.exe
Process ID: 4268
PSVersion: 5.1.14393.1770
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.14393.1770
BuildVersion: 10.0.14393.1770
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1
**********************
**********************
Command start time: 20171030223255
**********************
PS C:\Users\Administrator> echo test
test
**********************
Command start time: 20171030223256
**********************
PS C:\Users\Administrator> exit
**********************
Windows PowerShell transcript end
End time: 20171030223256
**********************

Z każdą sesją programu PowerShell tworzony jest plik transkrypcji. Pierwsza część transkrypcji to prolog zawierający pola specyficzne dla sesji, takie jak czas rozpoczęcia sesji, użytkownik, wersja PowerShell itp. Następnie, po linii gwiazdek, podczas tej sesji uruchamiany jest zbiór poleceń i wyjść. Na koniec opcjonalna sekcja epilogu na końcu pliku z czasem zakończenia sesji, ale tylko wtedy, gdy sesja została zakończona poleceniem exit (a nie przez zamknięcie okna).

liczba komend pomiędzy prologiem a epilogiem jest różna. Dlatego przyjęliśmy dwuetapowe podejście: najpierw parsowanie prologu, epilogu i poleceń-wyjścia zbiorcze; następnie wyodrębnianie poleceń i wyjść do oddzielnych pól w warstwie zapytań.

jak odczytać i przeanalizować transkrypcje ∞

SpectX odczytuje dane bezpośrednio z plików dziennika raw i przetwarza je w czasie wykonywania. We wzorze Zakładamy, że włączyłeś nagłówki wywołania, czyli każde polecenie PowerShell jest rejestrowane z czasem rozpoczęcia polecenia. Aby wyświetlić transkrypcje jako czystą tabelę:

1. Pobierz i zainstaluj Free SpectX.

2. Skopiuj to zapytanie bazowe (Github)do okna zapytania

3. Zmodyfikuj ścieżkę w linii 47, aby pasowała do katalogu wyjściowego plików dziennika transkrypcji. Nie zmieniaj zmiennych czasu w ścieżce-umożliwi to filtrowanie dzienników na podstawie znaczników czasu w ścieżce pliku. Na przykład, jeśli ścieżka do jednego z Twoich plików transkrypcji to

C:\Logs\powershell200405\PowerShell_transcript.WS01.5OoA7WLR.20200405152828.txt

, to URI w zapytaniu SpectX wskazuje na wszystkie pliki dziennika o podobnej ścieżce C:\Logs\powershell folder byłby:

file:/C:/Logs/powershell/$yyyy$$MM$$dd$/PowerShell_transcript.*.$yyyy$$MM$$dd$$HH$$mm$$ss$.txt

4. Zmień liczbę dni w skrypcie init na samym początku skryptu (linie 2-4), jeśli chcesz spojrzeć na starsze/nowsze logi.

5. Naciśnij run. Wyniki powinny wyglądać podobnie do tego:

kto? Co? Kiedy? Jak? Zapytania ∞

zadając pytania z dzienników, szukasz znanego lub nieznanego. Wyszukiwanie znanych jest łatwe-wystarczy filtrować potrzebne dane. Na przykład:

| filter(lower(output) CONTAINS 'error') 

daje wszystkie polecenia, które zawierają łańcuch 'error’ na wyjściu.

jeśli chcesz przyjrzeć się konkretnemu przedziałowi czasu, zmodyfikuj blok init zawierający znaczniki czasu na samym początku skryptu zapytania bazowego.

to staje się bardziej interesujące, jeśli szukasz nieznanego i chcesz zagłębić się w coś niezwykłego. Pierwszym krokiem jest ustalenie linii bazowej-zwykłej, a następnie odfiltrowanie jako coś, czym nie jesteś zainteresowany. Na przykład, zgrabną sztuczką jest sprawdzenie, kiedy polecenie zostało uruchomione po raz pierwszy,a następnie skupienie się na poleceniach, które zostały po raz pierwszy wyświetlone później niż inne (zobacz przykładowe zapytanie # 2 poniżej).
skopiuj i wklej te zapytania jeden po drugim na koniec zapytania bazowego. Kliknij dwukrotnie rekord, aby zobaczyć całą jego zawartość, kliknij prawym przyciskiem myszy pole, aby zastosować filtry (negatywne).

wgląd w polecenia i wyjścia poleceń

1. Najwyższe komendy

| select(cnt:count(*), command)
| group(@2)
| sort(cnt DESC)

2. Kiedy po raz pierwszy uruchomiono komendę?

| select(min(commandStartTime),count(*),command,*)
| group(command)
| sort(min_commandStartTime)

3. Top command-output pairs

| select(cnt:count(*), command,output)
| group(command,output)
| sort(cnt DESC)

4. Liczba poleceń na godzinę

| select(count(*),trunc_cmd_start:commandStartTime)
| group(trunc_cmd_start)

5. Polecenia, które prawdopodobnie zostały napisane ręcznie, tj. polecenia zaczynające się od ’ c:\\’

| select(start_time, end_time, Username, RunAs_User, Machine, PID, PSVersion, commandText)
| filter(lower(commandText) contains 'c:\')

6. Ponownie przeanalizuj pole wyjściowe, aby wykryć adresy IP w tekście poleceń

| select(parse("DATA* IPADDR:ip DATA*", commandText), commandText, *)
| filter_out(ip IS NULL)

7. Znajdź ciąg 'download’ wewnątrz command_output, nawet jeśli jest zaciemniony (Usuń interpunkcję). Na przykład, jeśli polecenie invoke-wyglądało tak:

| select(deobf_commandText:lower(REPLACEALL(commandText, "" , '')) ) 
| filter(deobf_commandText contains 'download')

statystyki ogólne

8. Ile sesji PowerShell na godzinę?

| select(start_time:start_time,count(*))
| group(start_time)

9. TOP 100 nazw użytkowników

| select(Username, cnt:count(*))
| group(@1)
| sort(cnt DESC)
| limit(100)

10. Ile rekordów użytkownik wygenerował na maszynę?

| select(Username,Machine,cnt:count(*))
| group(@1,@2)
| limit(100)

11. Top Host Applications-lista aplikacji uruchamiających PowerShell wraz z dodatkowymi parametrami poleceń.

| select(cnt:count(*),Host_Application)
| group(@2)
| sort(cnt DESC)
| limit(100)

12. Top 100 aplikacji hosta na użytkownika

| select(Host_Application, Username, cnt:count(*))
| group(@1,@2)
| sort(cnt DESC)
| limit(100)

13. Przyjrzyj się bliżej interpunkcji w poleceniach. Polecenia, które są odstające (liczba jest mała) zasługują na szczegółowy wygląd.

| select(PUNCT(command, 64, false), cnt:count(*),uniq_commands:ARRAY_LEN(ARRAY_UNIQ(ARRAY_AGG(command))),commands_array:ARRAY_UNIQ(ARRAY_AGG(command)))
| group(@1)
| sort(cnt)
| limit(100)

podsumowanie

mimo, że logi transkrypcji PowerShell nie są łatwe do odczytania dla maszyn, zawarte w nich informacje są wyczerpujące i warte analizy. W końcu PowerShell jest narzędziem do automatyzacji i konfigurowania prawie każdego zadania w systemie Windows-To „pierścień do rządzenia nimi wszystkimi”. Skupienie się na statystykach PowerShell, poleceniach i ich wyjściach jest dobrym sposobem na upewnienie się, że pierścień nie jest w niewłaściwych rękach lub nie jest używany bezmyślnie.
podziękowania
Dziękuję Taavi @ Transkrypcje z kursu Hunt The Hacker były świetnym punktem wyjścia do tego artykułu.

powrót do artykułów

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.