W firmach to nie tylko firewalle i antywirusy decydują o bezpieczeństwie. Równie ważne są śledzenie zmian i rozliczalność: kto, kiedy i z jakiego stanowiska wprowadził konkretną zmianę. Jednym z najczęstszych i krytycznych przykładów jest zmiana hasła użytkownika lokalnego. Poniżej pokazujemy, jak włączyć audyt, jak wyciągnąć z logów Security „kto to zrobił” oraz dajemy gotowy skrypt PowerShell, który zrzuca ostatnie zmiany haseł.
Dlaczego to ważne?
- Rozliczalność (accountability) – jasno wskazujemy sprawcę operacji (konto, domena, Logon ID).
- Forensyka – łączymy zmianę hasła z logowaniem (4624) i źródłem (komp/IP).
- Zgodność – spełniamy wymogi audytowe (np. ISO 27001, polityki haseł).
- Szybka reakcja – wykrycie nieautoryzowanych zmian i możliwość natychmiastowego działania.
Krok 1: Włącz audyt zmian kont
Na stacjach roboczych/serwerach lokalnych:
- Otwórz Local Security Policy → Advanced Audit Policy Configuration → Account Management.
- Włącz Audit User Account Management dla Success (i opcjonalnie Failure).
- W wierszu poleceń:
gpupdate /force.
Bez audytu nie będzie śladów w dzienniku Security – włącz go zawczasu!
Krok 2: Co loguje Windows?
W Event Viewer → Windows Logs → Security interesują nas m.in.:
- 4723 – próba zmiany hasła przez samego użytkownika (Change).
- 4724 – reset hasła przez inną osobę/konto (Reset).
- 4738 – zmiana właściwości konta (pozwala potwierdzić moment „Password Last Set”).
Dodatkowo do korelacji źródła: 4624 (udane logowanie – workstation/IP).
Krok 3: Skrypt PowerShell do wyłuskania „kto zmienił hasło”
Poniższy skrypt filtruje zdarzenia 4723/4724 z ostatnich 30 dni i zwraca listę z aktorem (ByUser/ByDomain) oraz kontem docelowym (TargetUser).
Zmień TARGETUSER na nazwę lokalnego konta, które chcesz prześledzić – albo usuń filtr, by zobaczyć wszystkie.
# Zakres: ostatnie 30 dni (zmień w razie potrzeby)
$ids = 4723,4724
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=$ids; StartTime=(Get-Date).AddDays(-30)} |
ForEach-Object {
$x = [xml]$_.ToXml()
[pscustomobject]@{
Time = $_.TimeCreated
EventId = $_.Id
Action = if ($_.Id -eq 4723) {'Change'} else {'Reset'}
ByUser = ($x.Event.EventData.Data | ? {$_.Name -eq 'SubjectUserName'}).'#text'
ByDomain = ($x.Event.EventData.Data | ? {$_.Name -eq 'SubjectDomainName'}).'#text'
TargetUser = ($x.Event.EventData.Data | ? {$_.Name -eq 'TargetUserName'}).'#text'
LogonId = ($x.Event.EventData.Data | ? {$_.Name -eq 'SubjectLogonId'}).'#text'
}
} | Where-Object { $_.TargetUser -ieq 'TARGETUSER' } | Sort-Object Time
Rozszerzenie: korelacja z 4624 (źródło operacji)
Weź LogonId z rekordu 4723/4724 i dopasuj do 4624, by znaleźć stanowisko/IP:
$logonId = '0x3e7' # wstaw z kolumny LogonId
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4624; StartTime=(Get-Date).AddDays(-30)} |
Where-Object { $_.Message -match [regex]::Escape($logonId) } |
Select-Object TimeCreated, Message
Tipy praktyczne
- SYSTEM / serwisy: jeśli hasła zmienia automaty narzędzia (np. LAPS/Intune/skrypty), aktorem będzie SYSTEM lub konto serwisowe – to też jest „kto”.
- Domena vs lokalnie: dla kont domenowych szukamy logów na kontrolerze domeny.
- Brak zdarzeń = brak audytu w momencie zdarzenia. Włącz teraz, by mieć ślady na przyszłość.
- Eksport do CSV:
... | Export-Csv .\ZmianyHasel.csv -NoTypeInformation -Encoding UTF8
Krok 4: Co dalej z wynikiem?
- Jeśli to nieautoryzowana zmiana – natychmiast wymuś reset hasła, unieważnij sesje, sprawdź członkostwa w grupach lokalnych.
- Zbierz artefakty: 4723/4724/4738 + 4624, zrzuty z
net localgroup administrators, harmonogram zadań, wpisy wTask Scheduler/Services. - Rozważ LAPS (Local Administrator Password Solution) do bezpiecznego i audytowalnego zarządzania hasłami lokalnych adminów.
Podsumowanie
Dobre cyberbezpieczeństwo to nie tylko blokowanie – to też widoczność i dowody. Włączenie audytu i szybki przegląd logów Security pozwala odpowiedzieć na kluczowe pytanie: kto zmienił hasło. A z podanym skryptem – zrobisz to w minutę.