analysera PowerShell-transkript

av Raido Karro och Liisa Tallinn
28 maj 2020

även om du inte använder PowerShell i dina Windows-maskiner är dina motståndare och penntestare. Varför använda anpassade hax0r-verktyg när varje Windows-maskin levereras med en inbyggd skriptmiljö? Powershell låter angriparen göra nästan vad som helst utan att lämna några spår på diskar. Det är ett misstag att inte älska PowerShell som en angripare och ett misstag att inte älska PowerShell-loggar som försvarare.

följande är en tolkning och frågehandledning med SpectX ’ free log analyzer för att få allmän statistik samt specifika insikter från PowerShell-transkriptloggar som är notoriskt svåra att tolka. Det finns inget behov av att importera eller inta filerna från deras nuvarande utdatakatalog – SpectX kör frågor direkt på raw-loggar. Att skapa en ren vy från de råa stockarna tar bara några minuter.

vi har laddat upp en liten uppsättning transkriptfiler till vårt offentliga S3 – Arkiv-Kör gärna frågorna nedan på denna exempeldata. Frågorna vi har ställt i frågorna syftar till att utforska baslinjen och upptäcka onormalt (potentiellt skadligt) beteende. Vilka var de bästa kommandona? När kördes de flesta kommandon? När kördes de för första gången? Vad var kommandoutgångarna som dök upp på konsolen när du körde kommandot – något ovanligt? Vilka är de bästa användarna? Alla användare som kör kommandon som de inte borde köra? Topp värd applikationer? Hur många kommandon per timme / dag / vecka? Vad sägs om obfuscated kommandon? Och så vidare-när du väl har fått tag på SpectX-frågor slutar uppföljningsfrågorna aldrig.

innehåll

om transkript
hur man aktiverar transkriptionsloggning
format för transkriptionsloggarna
läsa och analysera loggarna med SpectX
vem? Vad? När? Hur? – frågorna

transkript vet allt… eller nästan 2258 > det finns 3 typer av loggning som kan aktiveras för PowerShell: modulloggning, skriptblock och transkription. Eftersom de två första kan ses som Windows-händelser rekommenderas det ofta att du manuellt läser transkripttextfilerna endast när ett problem uppstår genom att övervaka de två första. Samtidigt är informationen i transkript den mest omfattande av de tre och de platta textfilerna är mycket mer lagringseffektiva än Windows-händelser som produceras av modul-och skriptblockloggning. Till exempel, kör en enkel write-host ’hello world’ eller i detta fall ’allt du behöver är loggar’ producerar 22 Windows händelser från modul och script blockera loggning men samma information plus kommandot utgång är också inloggad i denna 1kb Power transkript:

**********************
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
**********************

problemet är-transkriptionsloggar var historiskt utformade för felsökningsändamål, det vill säga för människor snarare än maskiner att läsa. Deras innehåll är nästan friform och notoriskt svårt att tolka. Gräva på webben kan du hitta några försök på webben för att ta in transkript i ett loggbehandlingsverktyg men ingen av dem uppnår extraherande kommandon såväl som kommandoutgångar i separata fält. Detta är synd eftersom kommandoutgångarna endast loggas till transkript och insikter om vad som faktiskt hände som ett resultat av PS-kommandon kan vara värdefulla.
Ange SpectX. Hoppa över intagningsfasen och använda byggstenar i tolkningsspråket det kan extrahera inte bara användar-och värd – /maskinfälten i prologen utan också kommandot starttider, kommandon och utgångar. Som SpectX ’ parser tillämpas på raw loggfiler under query runtime, betyder det också att du kan felsöka, förbättra och fixa parser med varje fråga om loggformatet råkar ändras. Och PowerShell transkriptionsloggar är verkligen flyktiga.
när vi började skriva det här inlägget trodde vi att PowerShell-transkript är allsmäktiga och registrerar allt. Men att leka med kommandon och utgångar visade sig att det finns ett undantag. När du kör ett PS-skript från en webbadress fångar transkriptet kommandot (inklusive webbadressen) och utdata men lämnar dig helt blind när det gäller innehållet i skriptet eller kommandon som körs av skriptet. Till exempel, för att lära dig vad det här skriptet kör från en url gjorde, måste du vända dig till Windows-händelser som produceras av modulloggning.

**********************
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
**********************

så här aktiverar du PowerShell – Transkriptloggning ∞

1. Öppna Start-menyn och skriv ’gpedit’ för att öppna ett lokalt Grupprincipredigeringsfönster

2. Navigera till Adminmallar > Windows-komponenter > Windows PowerShell

3. Klicka på ’Slå på PowerShell transkription’

4. Välj ’Enabled’ och ange sökvägen till utmatningskatalogen. Viktigt! Markera rutan för att aktivera anropshuvuden. Detta registrerar varje kommandokörning med en Kommandostarttid.

5. Klicka på OK
6. Öppna ett PowerShell-fönster för att testa om loggningen fungerar. Skriv in ett kommando, t.ex. en enkel skrivvärd:’ allt du behöver är loggar ’följt av’avsluta’.

7. Kontrollera om utmatningskatalogen du angav i steg 4 innehåller ett transkript med tidsstämplar och åtgärder i steg 6.

på lång sikt är det bra att centralisera insamlingen av PowerShell-transkript för att analysera dem i stor skala, t. ex. kontrollera denna handledning av @dan_franciscus i 4sysops-bloggen.

Transkriptionsloggformat 2258>

några ord om loggformatet och tolkningslogiken. Om du hellre vill fråga och inte är så intresserad av loggfilernas och tolkarens anatomi, Hoppa till nästa avsnitt. Här är ett urval av en raw PS v. 5.1 transkriptlogg:

**********************
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
**********************

en transkriptfil skapas med varje PowerShell-session. Den första delen av transkriptet är en prolog som innehåller sessionsspecifika fält som sessionsstarttid, användare, PowerShell-version etc. Sedan, efter en rad asterisker, körs samlingen av kommandon och utgångar under denna session. Slutligen en valfri epilogavsnitt i slutet av filen med sessionens sluttid men bara om sessionen avslutades med ett exit-kommando (och inte genom att stänga fönstret).

antalet kommandon mellan prologen och epilogen varierar. Det är därför vi har tagit en tvåstegsmetod: först analysera prologen, epilog och kommandon-utgångar i bulk; sedan extrahera kommandon och utgångar i separata fält i frågelagret.

hur man läser och tolka de transkript Avteckningen

SpectX läser data direkt från raw loggfiler och tolkar dem vid körning. I mönstret antar vi att du har aktiverat anropshuvuden, det vill säga varje PowerShell-kommando spelas in med ett kommando starttid. För att se transkripten som en ren tabell:

1. Ladda ner och installera gratis SpectX.

2. Kopiera denna basfråga (Github) till frågefönstret

3. Ändra sökvägen på rad 47 för att matcha utdatakatalogen för dina transkriptloggfiler. Ändra inte tidsvariablerna i sökvägen-detta gör det möjligt att filtrera loggar baserat på tidsstämplar i sökvägen. Till exempel, om sökvägen till en av dina transkriptfiler är

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

Då URI i SpectX-frågan som pekar på alla loggfiler med en liknande sökväg i C:\Logs\powershell mapp skulle vara:

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

4. Ändra antalet dagar i init-skriptet i början av skriptet (rader 2-4) om du vill titta på äldre/nyare loggar.

5. Tryck på Kör. Resultaten ska se ut som detta:

vem? Vad? När? Hur? Frågorna

när du ställer frågor från loggarna letar du antingen efter det kända eller det okända. Att leta efter det kända är enkelt – filtrera bara de data du behöver. Till exempel:

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

ger dig alla kommandon som innehåller strängen ’fel’ i utgången.

om du vill titta på en viss tidsperiod, ändra init-blocket som innehåller tidsstämplar i början av basfrågeskriptet.

det blir mer intressant om du letar efter det okända och vill borra ner till något ovanligt. Det första steget här är att fastställa baslinjen – det vanliga och sedan filtrera ut som något du inte är intresserad av. Ett snyggt trick är till exempel att titta på när ett kommando först kördes och sedan fokusera på kommandon som först sågs senare än andra (se exempelfråga #2 nedan).
kopiera och klistra in dessa frågor en efter en till slutet av basfrågan. Dubbelklicka på en post för att se allt innehåll, högerklicka på ett fält för att tillämpa (negativa) filter.

insikter i kommandon och kommandoutgångar

1. Toppkommandon

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

2. När var första gången ett kommando kördes?

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

3. Översta kommando-utgångspar

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

4. Antal kommandon per timme

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

5. Kommandon som förmodligen skrivits manuellt, dvs kommandon som börjar med ’ c:\\’

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

6. Analysera utmatningsfältet igen för att upptäcka IP-adresser i commandText

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

7. Hitta strängen ’ladda ner’ inuti command_output även om den är förvrängd (ta bort skiljetecken). Till exempel, om invoke-kommandot såg ut så här:

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

generiska statistik

8. Hur många PowerShell-sessioner per timme?

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

9. Topp 100 användarnamn

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

10. Hur många poster genererade en användare per maskin?

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

11. Top Host Applications-lista över program som Kör PowerShell, inklusive ytterligare kommandoparametrar.

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

12. Topp 100 Värdapplikationer per användare

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

13. Ta en närmare titt på skiljetecken i kommandon. Kommandon som är avvikande (räkningen är liten) förtjänar ett detaljerat utseende.

| 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)

slutsats

även om PowerShell-transkriptloggar inte är lätta att läsa för maskiner, är informationen de innehåller omfattande och värt att analysera. När allt kommer omkring är PowerShell ett verktyg för att automatisera och konfigurera nästan alla uppgifter i Windows – det är en ’ring för att styra dem alla’. Att ta en fokuserad titt på PowerShell-statistik, kommandon och deras utgångar är ett bra sätt att se till att ringen inte är i fel händer eller används cluelessly.
bekräftelser
tack Taavi @ förtydligad säkerhet. Transkript från Hunt The Hacker-kursen var en bra utgångspunkt för den här artikeln.

tillbaka till artiklar

Lämna ett svar

Din e-postadress kommer inte publiceras.