NOWOŚĆ! Szkolenie AI w pracy admina
Konferencja Mega Sekurak Hacking Party w Krakowie – 26-27 października!
NOWOŚĆ! Szkolenie AI w pracy admina
Konferencja Mega Sekurak Hacking Party w Krakowie – 26-27 października!
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).
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 🛠️ 🛡️💪

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.
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
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 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.
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.
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.
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:
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ć.
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