NOWOŚĆ! Szkolenie AI w pracy admina

Konferencja Mega Sekurak Hacking Party w Krakowie – 26-27 października!

 

Windows w praktyce: szukanie sekretów w systemie z użyciem PowerShell

11 września 2026, 18:51 | Aktualności, Narzędzia | 0 komentarzy

Wstęp

Rok 2026 przyzwyczaił nas do tego, że zagrożeniem bywa nie tylko złośliwe oprogramowanie tworzone przez atakujących, ale i narzędzia, którym ufamy na co dzień. Naruszenia łańcucha dostaw w kolejnych produktach, o których regularnie czytamy w mediach branżowych, pokazują, że skrypt czy pakiet o ugruntowanej renomie potrafi z dnia na dzień otrzymać złośliwą aktualizację. Warto przenieść tę lekcję na własne podwórko i zadać sobie pytanie, na ile świadomie korzystamy z narzędzi, które sami uruchamiamy na systemach klientów.

Podczas testów penetracyjnych systemów Windows, po uzyskaniu dostępu do stacji roboczej lub serwera, jednym z pierwszych odruchów jest uruchomienie narzędzia do lokalnej enumeracji. WinPEAS (https://github.com/peass-ng/PEASS-ng/tree/master/winPEAS), bo o nim najczęściej mowa, to prawdopodobnie najpopularniejszy skrypt tego typu. Uruchamiając narzędzie (pobrane z repozytorium twórców w postaci skryptu PowerShell, pakietu .exe czy projektu C# do samodzielnej kompilacji), w kilka minut przeszukuje system i zwraca długą listę potencjalnych sekretów: hasła zapisane w plikach, klucze do sieci Wi-Fi, poświadczenia w rejestrze, certyfikaty i dziesiątki innych rzeczy, które mogą posłużyć do eskalacji uprawnień lub poszerzenia obecności w sieci (rysunek 1).

Wprowadzenie do PowerShell od sekuraka

Wpadajcie na naszą bezpłatną mini serię szkoleniową (3 x 2 h), w czasie której zaprezentujemy możliwości PowerShella – od absolutnych podstaw, przez automatyzację środowiska Windows i Active Directory, aż po zaawansowane wykorzystanie ofensywne, detekcję oraz utwardzanie systemu 🛠️ 🛡️💪

➡️Bezpłatne zapisy

Rysunek 1. Fragment wyniku uruchomionego skryptu WinPEAS.ps1

Narzędzie to stanowi podstawę pracy wielu pentesterów i analityków bezpieczeństwa. Wykonując jednak komercyjne testy penetracyjne, warto zadać sobie pytanie: czy uruchamianie podobnych skryptów pobranych z Internetu, chociażby o najlepszej renomie, jest uzasadnione w środowisku produkcyjnym? Opisano olbrzymią liczbę przypadków, w których znane narzędzia lub zależności otrzymywały złośliwe aktualizacje bądź atakujący, podszywając się pod nie, dystrybuowali złośliwe oprogramowanie. W samym roku 2026 na sekuraku opisywaliśmy chociażby przypadek Bitwarden, pakietów serwowanych w npm czy naruszenie łańcucha dostaw Notepad++. Nie bez powodu również ataki polegające na naruszeniu łańcucha dostaw wylądowały na trzecim miejscu dokumentu OWASP Top 10 2025.

Bardzo często podobne narzędzia traktowane są jak czarna skrzynka – uruchamiający zakłada, że działają one zgodnie z opisem twórcy i nie próbuje dowiedzieć się, jak funkcjonują one „pod spodem”.

Zapoznając się głębiej z działaniem skryptów podobnych do WinPEAS, można zaobserwować, że w praktyce z użyciem natywnych mechanizmów Windows wykonują one proste operacje, odczytujące sekrety znajdujące się jawnie w różnych miejscach systemu: plikach, rejestrach, magazynie certyfikatów czy historii powłoki.

WinPEAS w gruncie rzeczy jest wygodnym opakowaniem na zestaw odczytów, które każdy, kto zna PowerShella, wykona samodzielnie. Skoro tak, to podczas audytu, zamiast uruchamiać obcy skrypt, można w kilka chwil złożyć własne, celowane rozpoznanie, zrozumiałe i w pełni przez nas kontrolowane.

Warto dodać, że niniejszy artykuł nie jest próbą ponownego przepisania narzędzia WinPEAS, i nie powinien być tak traktowany. Pokazany zostaje w nim proces działania – czyli gdzie w systemie leżą najczęściej spotykane sekrety i jak sięgnąć po nie za pomocą zgrabnego, czytelnego polecenia.

Załóżmy, że w wyniku wcześniejszego ataku – na przykład przechwycenia i relayowania NetNTLM (o którym pisałem w artykułach o problemach NTLM) – uzyskaliśmy powłokę administracyjną na stacji roboczej użytkownika. Poniżej znajduje się kilka przykładów technik, które z tej perspektywy pozwalają na zebranie szeregu informacji potencjalnie istotnych dla bezpiecznika.

Hasła zapisane w plikach

Pierwszym i chyba najczęstszym problemem pojawiającym się w organizacjach są hasła zapisane w postaci jawnej – czy to w historii powłoki, w lokalnych plikach na systemie, czy na współdzielonych w organizacji zasobach SMB – w praktyce na palcach jednej ręki można policzyć pentesty, w których w podobny sposób nie udaje się zdobyć istotnych poświadczeń.

Do procesu można podejść w sposób manualny lub też tworząc ad hoc proste polecenie z wykorzystaniem PowerShella. Poniższe polecenie przeszukuje profile użytkowników oraz typowe katalogi aplikacyjne, ograniczając się do rozszerzeń, w których takie sekrety pojawiają się najczęściej (listing 1).

PS C:\Users\ksiegowosc> 
$sciezki = "C:\Users", "C:\inetpub", "C:\xampp", "$env:ProgramData"
$wzorce  = 'password|passwd|hasło|pwd\s*=|connectionString|secret|apikey'
$sciezki = "C:\Users", "C:\inetpub", "$env:ProgramData" 

PS C:\Users\ksiegowosc>
Get-ChildItem -Path $sciezki -Recurse -File -ErrorAction SilentlyContinue -Include *.txt, *.ini, *.config, *.xml, *.ps1, *.bat, *.cmd, *.log |
Select-String -Pattern $wzorce -List | 
Select-Object Path, LineNumber, Line
    
    
Path LineNumber Line                                                               ---------- ----     
C:\Users\ksiegowosc\Documents\PowerShell\Modules\Microsoft.WinGet.Client\1.29.280\Microsoft.WinGet.Client.Cmdlets.dll-Help.xml                   318         `GH_TOKEN` takes precedence over `GITHUB_TOKEN`, matching GitHub CLI behavior (...

C:\Users\ksiegowosc\Downloads\2.txt  1 CONNECTED: -- Now chatting with Hal Pline -You: test  Hal Pline: I don't know. I can tell...                                                                                                       

Listing 1. Przeszukanie typowych lokalizacji w poszukiwaniu plików zawierających hasła

Widoczny powyżej zestaw poleceń wykonuje bardzo proste operacje: z wykorzystaniem cmdlet Get-ChildItem przeszukuje ścieżki zdefiniowane w zmiennej, Select-String wyszukuje w zawartości zwróconych wcześniej plików interesującej treści, a Select-Object – zwraca wyłącznie interesujące wartości, które pasują do wcześniejszych filtrów.

Warto zwrócić uwagę na przełącznik -List w Select-String – sprawia on, że z każdego pliku zwracane jest tylko pierwsze trafienie, dzięki czemu wynik pozostaje czytelny nawet przy dużych logach. Jeżeli interesuje nas pełny kontekst danego znaleziska, wystarczy ten sam plik przejrzeć jeszcze raz, tym razem bez tego przełącznika.

W praktyce najczęstsze trafienia to pliki web.config z ciągiem połączenia do bazy (connectionString), skrypty wdrożeniowe z zaszytym hasłem konta usługowego czy eksporty z menedżerów haseł, których ktoś nie usunął po imporcie. Osobną, wdzięczną kategorią są pliki *.kdbx (bazy KeePass) oraz *.ovpn (konfiguracje VPN) – tych nie przeszukujemy pod kątem treści, a jedynie lokalizujemy ich obecność (listing 2).

PS C:\Users\ksiegowosc> 
Get-ChildItem C:\Users -Recurse -File -Include *.kdbx, *.ovpn, *.ppk, *.rdp -ErrorAction SilentlyContinue | Select-Object FullName, Length, LastWriteTime                                                                                            

FullName                                            Length LastWriteTime           
--------                                            ------ -------------                                                                                              

C:\Users\ksiegowosc\Documents\baza\Keepass\Haselka.kdbx   6554 1.09.2026 14:46:35

Listing 2. Lokalizacja plików, które same w sobie stanowią lub zawierają poświadczenia

Klucze do sieci Wi-Fi

Kolejnym łatwym celem są klucze do zapisanych sieci bezprzewodowych. Windows przechowuje je lokalnie i – co kluczowe – potrafi zwrócić je w postaci jawnej użytkownikowi z uprawnieniami administracyjnymi. To jeden z tych przypadków, w których sekret nie jest w żaden sposób chroniony przed lokalnym adminem, bo z założenia ma być dla niego odczytywalny.

Najkrótsza droga to natywny netsh (listing 3).

PS C:\Users\ksiegowosc> netsh wlan show profiles

Profiles on interface Wi-Fi:

Group policy profiles (read only)
---------------------------------
    <None>

User profiles
-------------
    All User Profile     : Parter
    All User Profile     : Corpex-Air
    All User Profile     : Guests
    
PS C:\Users\ksiegowosc> netsh wlan show profile name="Corpex-Air" key=clear
[...]
Security settings                                                                  
-----------------                                                                  
    Authentication         : WPA3-Personal                                         
    Cipher                 : GCMP-256                                              
    Authentication         : WPA3-Personal                                         
    Cipher                 : GCMP                                                  
    Authentication         : WPA3-Personal                                         
    Cipher                 : CCMP                                                  
    Security key           : Present                                               
    Key Content            : Hahahayougotmebro

Listing 3. Wylistowanie zapisanych profili Wi-Fi i wyświetlenie klucza w postaci jawnej

Klucz pojawi się w sekcji Key Content (lub Zawartość klucza na polskiej wersji systemu). I tu właśnie tkwi haczyk, o którym trzeba pamiętać, budując własne narzędzie – nazwy pól zwracanych przez netsh zależą od języka systemu. Oznacza to, że wyszukiwanie pola po angielskiej nazwie nie zadziała na polskiej wersji Windows. Dlatego zamiast wyłuskiwać klucz z tekstu, alternatywnie można wyeksportować profile do plików .xml, w których nazwy pól są stałe niezależnie od języka systemu, i odczytać je jako obiekty (listing 4).

PS C:\Users\training\Downloads> netsh wlan export profile key=clear

Interface profile "Parter" is saved in file ".\Parter.xml" successfully.

Interface profile "Corpex-Air" is saved in file ".\Corpex-Air.xml" successfully.

Interface profile "Guests" is saved in file ".\Wi-Fi-Guests.xml" successfully.                     
                                      
PS C:\Users\ksiegowosc\Downloads> 
>> Get-ChildItem *.xml | ForEach-Object {
>> [xml]$xml = Get-Content $_.FullName
>> [PSCustomObject]@{
>> SSID = $xml.WLANProfile.SSIDConfig.SSID.name
>> Kluczyk = $xml.WLANProfile.MSM.security.sharedKey.keyMaterial
>> }
>> }

SSID    Kluczyk
----    -------
Parter  Niewejdziesztutaj
Corpex-Air Hahahayougotmebro

Listing 4. Odczyt kluczy Wi-Fi w sposób niezależny od języka systemu, poprzez eksport profili do .xml

Warto zwrócić uwagę na drugą część powyższego listingu. W pierwszej kolejności przeszukane zostały pliki .xml (Get-ChildItem). Następnie, dzięki zastosowaniu rzutowania [xml], zawartość pliku tekstowego została zamieniona na obiekt XML. Dzięki temu można odwoływać się do poszczególnych elementów za pomocą kropki (.).

W tym przypadku pozwoliło to precyzyjnie wyciągnąć nazwę sieci Wi-Fi (SSID) za pomocą: $xml.WLANProfile.SSIDConfig.SSID.name. Na tej podstawie zbudowano nowy, własny obiekt PowerShell ([PSCustomObject]), z polami “SSID” i “Kluczyk”, co pozwoliło wygodnie wyciągnąć tylko interesujące nas informacje.

Historia powłoki

Historia poleceń to miejsce które potrafi być prawdziwą kopalnią wiedzy. Użytkownicy i administratorzy regularnie wklejają hasła wprost w linię poleceń – przy mapowaniu dysków, tworzeniu obiektów poświadczeń czy uruchamianiu skryptów z parametrem. Co ciekawe, PowerShell (a konkretnie – moduł PSReadLine) domyślnie zapisuje historię do pliku na dysku, per użytkownik, i nie kasuje jej między sesjami.

Poniższy fragment (listing 5) pozwala na przypisanie ścieżki, w której znajduje się transkrypt historii wykonanych poleceń, do zmiennej – a następnie przeszukanie jej pod kątem interesujących poświadczeń.

PS C:\Users\ksiegowosc\Downloads> 
$historia = (Get-PSReadLineOption).HistorySavePath

PS C:\Users\ksiegowosc\Downloads> 
Get-Content $historia |                            
Select-String -Pattern 'password|passwd|-AsPlainText|ConvertTo-SecureString|net use|token|apikey'     
                      
net use Z: \\fakturki\private /user:ksiegowosc bardzobardzogrubefakturki

Listing 5. Przeszukanie historii poleceń PowerShell pod kątem wklejonych sekretów

Warto pamiętać, że plik historii jest przypisany do konkretnego profilu użytkownika – dysponując uprawnieniami lokalnego administratora, można zajrzeć do historii wszystkich profili w katalogu C:\Users, a nie tylko własnej.

Analogiczne miejsca istnieją dla innych powłok i klientów – warto po zdobyciu dostępu rzucić okiem chociażby na historię klienta MySQL (.mysql_history) czy pliki sesji PuTTY zapisane w rejestrze użytkownika.

Zapisane poświadczenia i automatyczne logowanie

Windows udostępnia kilka mechanizmów przechowywania poświadczeń „na później”, które w czasie pentestu warto sprawdzić w pierwszej kolejności. Najprostszy z nich to menedżer poświadczeń. Nie ma możliwości pobrania z niego poświadczeń w postaci jawnej, a wyłącznie listę zapisanych wpisów – ta informacja sama w sobie lista może wiele powiedzieć o tym, do jakich zasobów i na jakich kontach loguje się dany użytkownik (listing 6).

PS C:\Users\ksiegowosc\Downloads> cmdkey /list                                     
Currently stored credentials:  
                                                    
    Target: MicrosoftAccount:target=SSO_POP_Device                                 
    Type: Generic                                                                  
    User: 02hdgmjbahneclps                                                         
    Saved for this logon only                                                                                                                                         
    Target: LegacyGeneric:target=git:http://refresh_token.10.22.0.1           
    Type: Generic                                                                  
    User: OAUTH_USER                                                               
    Local machine persistence
    
    Target: LegacyGeneric:target=fakturex:url=https://api.fakturexcorp.com         
    Type: Generic                                                                  
    User: Bearer                                                                   
    Local machine persistence

Listing 6. Wylistowanie poświadczeń zapisanych w menedżerze poświadczeń Windows

Innym interesującym celem jest konfiguracja automatycznego logowania. Jeżeli ktoś skonfigurował stację tak, aby logowała się sama (co spotyka się zwłaszcza na maszynach typu kiosk, terminalach czy stanowiskach produkcyjnych), to hasło użytkownika przechowywane jest w rejestrze w postaci jawnej, w gałęzi Winlogon (listing 7).

$winlogon = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
Get-ItemProperty $winlogon |
    Select-Object AutoAdminLogon, DefaultDomainName, DefaultUserName, DefaultPassword

Listing 7. Odczyt konfiguracji automatycznego logowania wraz z hasłem w postaci jawnej

Jeżeli w polu AutoAdminLogon widnieje wartość 1, a DefaultPassword nie jest puste, to właśnie znaleźliśmy hasło zapisane otwartym tekstem – i to takie, które da się odczytać z poziomu zwykłego użytkownika, bo ta gałąź rejestru jest domyślnie odczytywalna dla wszystkich.

W kontekście PowerShella i przeglądaniu rejestru systemu warto wspomnieć o ciekawej alternatywie wobec klasycznej aplikacji RegEdit (Edytora rejestru). PowerShell udostępnia rejestr w formie dysku, po którym można się poruszać dokładnie tak samo, jak po zwykłych katalogach na dysku C . Główne gałęzie rejestru są tu widoczne jako „napędy”, na przykład HKLM: (odpowiednik HKEY_LOCAL_MACHINE) czy HKCU: (HKEY_CURRENT_USER), a klucze rejestru zachowują się jak foldery, po których można wygodnie nawigować (listing 8).

PS C:\> cd HKLM:\SOFTWARE\Microsoft\Windows                                        
PS HKLM:\SOFTWARE\Microsoft\Windows> Get-ChildItem
                                 
Hive: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
                            
Name                           Property                                            
----                           --------                                            
AssignedAccessConfiguration                                                        
AssignedAccessCsp                                                                  
Autopilot                                                                          
ClickNote
[...]

Listing 8. Nawigacja w rejestrze z użyciem PowerShella

Do wchodzenia w kolejne klucze służy więc znane cd (a właściwie rozwinięcie aliasu, czyli Set-Location), do wylistowania ich zawartości Get-ChildItem, a do odczytu samych wartości Get-ItemProperty – te same polecenia, które używane są do pracy z plikami. Dzięki temu przeszukiwanie rejestru można zautomatyzować i oskryptować – zamiast klikać po drzewie w graficznym Edytorze rejestru.

Certyfikaty i ich klucze prywatne

Na końcu niniejszego przeglądu technik warto przyjrzeć się certyfikatom – to obszar często pomijany, a potrafiący dać bardzo wymierne korzyści – zwłaszcza w środowiskach korzystających z AD CS, o których pisałem przy okazji artykułu dotyczącego zjawiska korozji domeny. Certyfikat z kluczem prywatnym możliwym do wyeksportowania to często poświadczenie, którym można się podszyć pod użytkownika, a którego reset hasła w żaden sposób nie unieważnia.

Co ciekawe, w PowerShellu do certyfikatów można uzyskać dostęp dokładnie w ten sam sposób, opisany w akapicie powyżej – przy omówieniu rejestrów. Magazyn certyfikatów również udostępniony jest jako dysk Cert:, po którym poruszać się można tymi samymi poleceniami, co po katalogach i po gałęziach rejestru. Interesujące są przede wszystkim certyfikaty, które mają dołączony klucz prywatny oraz nadają się do uwierzytelniania. Realizacją wyszukania takich certyfikatów zajmuje się poniższy krótki skrypt (listing 9).

Get-ChildItem Cert:\CurrentUser\My, Cert:\LocalMachine\My |
    Where-Object { $_.HasPrivateKey } |
    Select-Object Subject, Issuer, NotAfter, HasPrivateKey

Listing 9. Wylistowanie certyfikatów z kluczem prywatnym, wraz z ich przeznaczeniem

Widać tu tę samą filozofię, co wcześniej – Get-ChildItem wyświetla zawartość Cert: tak samo, jak we wcześniejszych przykładach – pliki czy klucze rejestru. Wynik polecenia filtrowany jest z użyciem Where-Object po interesującej nas właściwości. Dostęp do magazynu Cert:\LocalMachine wymaga uprawnień administracyjnych, natomiast do Cert:\CurrentUser zajrzeć może dowolny użytkownik. Jeżeli w polu przeznaczenia (EKU) obecne jest Client Authentication lub Smart Card Logon , a certyfikat został wystawiony przez firmowy urząd certyfikacji, może on być przeznaczony do uwierzytelniania użytkownika lub komputera. Nie oznacza to jednak automatycznie, że certyfikat umożliwi uwierzytelnienie w domenie – zależy to również od konfiguracji PKI, sposobu mapowania certyfikatu oraz dostępności odpowiedniego klucza prywatnego. Kolejnym krokiem może być sprawdzenie, czy powiązany z certyfikatem klucz prywatny jest eksportowalny – a jeśli tak, to będzie on mógł być wykorzystany do dalszych ofensywnych operacji.

Wskazówki dla administratorów

Wszystkie opisane wyżej znaleziska łączy jedna cecha – są one wynikiem jedynie tego, co użytkownicy i administratorzy zostawili po sobie w systemie. Wykonywanie skanów bezpieczeństwa ani obecność zaawansowanego oprogramowania EDR nie przyniesie efektów w wykrywaniu podobnych miskonfiguracji. Obrona sprowadza się więc do higieny korzystania z komputera i decyzji konfiguracyjnych:

  1. Nie należy przechowywać haseł w plikach, skryptach ani zmiennych środowiskowych. Tam, gdzie skrypt musi się uwierzytelnić, korzystajmy z kont zarządzanych (gMSA) lub bezpiecznego magazynu poświadczeń, zamiast ukrywać hasło w treści.
  2. Bezpieczniej jest zrezygnować z automatycznego logowania wszędzie tam, gdzie nie jest ono absolutnie konieczne. Jeżeli już musi być włączone, taka stacja powinna być z założenia traktowana jako niezaufana – i odpowiednio odizolowana.
  3. Należy wdrożyć LAPS do zarządzania hasłami lokalnych administratorów, aby jedno przejęte hasło nie umożliwiało dostępu do kolejnych maszyn w sieci.
  4. Należy oznaczać klucze prywatne istotnych certyfikatów jako niemożliwe do wyeksportowania, a tam, gdzie to możliwe, przechowywać je w oparciu o moduł TPM. Warto włączyć również audyt wystawiania certyfikatów na urzędzie certyfikacji.
  5. Przede wszystkim – warto edukować użytkowników oraz (a może przede wszystkim?) administratorów w zakresie poprawnej higieny korzystania z poświadczeń i ich bezpiecznego przechowywania.

Warto też zauważyć rzecz z perspektywy defensywnej mniej oczywistą – odczyt klucza rejestru, przeszukanie plików czy wylistowanie certyfikatów to operacje nieodróżnialne od normalnej pracy systemu – i dlatego istnieje nikła szansa na to, że podobne zachowania zostaną wykryte przy manualnej enumeracji zamiast wykorzystywania automatycznego narzędzia, takiego jak WinPEAS. Jedyną skuteczną obroną jest niepozostawianie sekretów tam, gdzie da się je odczytać.

Podsumowanie

Sekrety wyszukiwane przez WinPEAS oraz inne podobne narzędzia w zdecydowanej większości leżą w plikach, rejestrze i magazynie certyfikatów, gotowe do odczytania natywnymi mechanizmami systemu.

PowerShella warto się uczyć, nawet jeśli na co dzień zajmujemy się czymś innym niż administracja Windowsami. Jego znajomość to dziś jedna z podstawowych umiejętności w warsztacie bezpiecznika i administratora, a umożliwia ona dokładne zrozumienie systemu oraz tego, co dzieje się w jego poszczególnych zakamarkach. Dobrze opanowany PowerShell pozwala w czasie audytu w kilka chwil złożyć własne, precyzyjne narzędzie, dopasowane do konkretnej sytuacji i zrozumiałe dla osoby, która je uruchamia.

~Marek Rzepecki, etyczny hacker i trener w Securitum

Spodobał Ci się wpis? Podziel się nim ze znajomymi:



Komentarze

Odpowiedz