Repository navigation
Problem Domain
Why "find events by IP" is a deceptively hard problem β and what a proper IP-centric investigation toolkit must solve.
- The investigation that starts with an IP
- Anatomy of an IP-centric attack
- Seven ways "grep the log by IP" fails
- The evidence doctrine: absence of evidence β evidence of absence
- Case study: what the legacy script missed
- Requirements β features traceability
- Data sources landscape
Most Windows intrusion investigations begin the same way: a firewall alert, a lockout storm, an EDR network detection, or a threat-intel hit produces one artifact β an IP address. From that single address the responder must answer, under time pressure and often under audit:
Important
- Scope β which hosts, accounts, sessions, and time window did this IP touch?
- Outcome β did anything succeed? Is there an active foothold right now?
- Intent β brute force? spraying? lateral movement? exfil channel? beaconing?
- Provenance β external attacker, compromised internal host, NAT'd traffic, or a scanner?
- Provability β can the logs prove the answers, or are they wrapped/disabled/unaudited/cleared?
Question 5 is the one that separates tooling from testimony. An incident report that says "no events found" without a completeness proof is worth nothing in a post-incident review, a regulator conversation, or a courtroom.
A single source IP typically produces a multi-stage, multi-channel footprint. No single log tells the story:
flowchart LR
A["π Recon<br/>(scans, 5157 blocks)"] --> B["π Credential attack<br/>4625 Β· 4771 Β· 4776 Β· RCM 1148"]
B --> C{"Success?"}
C -- "no" --> D["π Lockouts<br/>4740 on target host"]
C -- "yes" --> E["πͺ Logon<br/>4624 Β· RCM 1149 Β· LSM 21"]
E --> F["π Privilege<br/>4672 special privileges"]
F --> G["π Lateral movement<br/>4648 Β· 5140/5145 Β· 7045 Β· Sysmon 3"]
G --> H["π Persistence<br/>4697/4698 Β· 4720/4732"]
H --> I["π§Ή Anti-forensics<br/>1102/104 Β· 4719 Β· 5025-5035"]
style C fill:#ffb347,color:#000
style I fill:#ff5d5d,color:#fff
style E fill:#41d99b,color:#000
Each stage lands in a different channel with a different field layout:
| Stage | Where the IP actually lives |
|---|---|
| Logon failures (4625/4771) |
EventData/Data[@Name='IpAddress'] β sometimes as ::ffff:a.b.c.d
|
| NTLM validation (4776) | nowhere β only a workstation name; correlate by time/account |
| RDP pre-auth (RCM 1149/1148) |
UserData/EventXML/Param3 β a different XML subtree entirely |
| RDP sessions (LSM 21β25) | UserData/EventXML/Address |
| Firewall (5156/5157) |
SourceAddress/DestAddress + %%14592-encoded direction |
| Sysmon network (EID 3) |
SourceIp/DestinationIp + process context |
| Post-exploitation (4688, 4697, 4698, 7045) |
inside strings: net use \\203.0.113.7\share, service ImagePath, task XML |
A tool that searches one field in one log answers question 1 for ~30% of the story.
The legacy script applied -MaxEvents inside the query and the time window
afterwards:
# legacy behavior (v5.0.2) β silently wrong under load
$rawEvents = Get-WinEvent -FilterXml $q -MaxEvents 1000 # newest 1000β¦
$rawEvents = $rawEvents | Where-Object { $_.TimeCreated -ge $start } # β¦then filteredOn a busy domain controller the newest 1000 events may cover 20 minutes. The
7-day window you asked for quietly became 20 minutes, with no warning.
WinSecHunter pushes the time window into the XPath query
(TimeCreated[@SystemTime>=β¦ and @SystemTime<=β¦]), so -MaxEvents bounds the
window you actually requested.
The same IPv4 address appears in logs as 203.0.113.7, ::ffff:203.0.113.7
(SChannel, RDP stacks), and occasionally ::ffff:cb00:7107 (hex-mapped).
IPv6 alternates between compressed (2001:db8::1) and expanded
(2001:0db8:0000:β¦:0001) forms. Exact-string matching finds one rendering
and misses the rest. WinSecHunter queries all textual variants server-side
and verifies client-side with boundary-aware regex β 203.0.113.7 must not
match 203.0.113.70, but must match inside ::ffff:203.0.113.7 and
203.0.113.7:55123.
Event Log XPath queries against EventData never see UserData. RDP's most
valuable events (1149 β network-level authentication success, fired before
4624) store the client IP in UserData/EventXML/Param3. A query shaped for the
Security log is blind on the RDP channel even when it "supports" it.
Hunting 4624/4625 only (the legacy default) misses Kerberos pre-auth failures (4771 β the domain view of the same brute force), NTLM validation (4776), RDP reconnects (4778/LSM 25 β attackers love abandoned sessions), lockouts (4740 β which name the victim host), share access (5140/5145), service and task installs (7045/4697/4698), and anti-forensics (1102/104/4719). The WinSecHunter catalog spans 156 IDs across 6 channels, ATT&CK-mapped, with contextual events (no IP field) deliberately included β a lockout during a brute-force window is evidence even though the IP never appears in it.
EventLogRecord.TimeCreated is the source machine's local time. Sweep 200
hosts across regions and your "chronological" timeline is confetti. WinSecHunter
computes UTC on the source side for every record, sorts, buckets, bookmarks
and detects on TimeUtc, and keeps TimeCreated only for display.
A 200-host sweep where 12 hosts are unreachable, 40 don't have Sysmon, and 3
deny the Security log is not "done" β it's 55 holes in your evidence. Legacy
tooling printed one error and continued, or worse, stayed quiet. WinSecHunter
emits a structured WinSecHostResult per target (Completed / NoEvents /
Failed / Skipped) so the report can state exactly what was and wasn't
observed.
Raw event lists don't answer "did they get in?" That requires stateful
analysis: failures grouped into sliding-window bursts per (source, account),
spraying across accounts, stuffing across sources, and β the money question β
a success for the same account/source within minutes after the failures.
WinSecHunter's Test-WinSecBruteForce escalates exactly that pattern to
BruteForceWithSuccess / Critical: assume compromise.
Warning
"No events found" is a conclusion, and conclusions require premises. Before writing it into a report, prove three things:
flowchart TD
Q["'No events for IP X<br/>in window W'"] --> C1{"Channel coverage<br/>β was the log retained<br/>across all of W?"}
C1 -- "Get-WinSecLogCoverage<br/>-CoveringFrom W" --> C2{"Audit coverage<br/>β would the events even<br/>have been recorded?"}
C2 -- "Test-WinSecAuditPolicy" --> C3{"Integrity<br/>β was the log cleared<br/>(1102/104), auditing<br/>changed (4719), or the<br/>firewall stopped (5025+)?"}
C3 -- "Profile DefenseEvasion" --> V["β
Now you may say:<br/>'no activity, provably'"]
style V fill:#41d99b,color:#000
WinSecHunter ships a cmdlet for each premise β a design choice, not an
afterthought. Logs wrap (default Security log is 20 MB β an RDP brute-force
storm can evict a day of history in hours), channels are disabled by default
(Firewall log, Sysmon), and audit policies vary wildly across an estate
(Credential Validation off β no 4776 β NTLM attacks invisible).
Real-world walkthrough β RDP brute force against VPN01, October 2026:
| Evidence | Legacy Get-SecurityEventsByIP.ps1 v5.0.2 |
WinSecHunter |
|---|---|---|
| 4625 type-10 failures with source IP | β (Security log only) | β |
RCM 1148/1149 pre-auth results (UserData IP) |
β never queried | β
profile Rdp
|
| LSM 25 session reconnect from the IP | β | β |
| The single 4624 success at 03:41 β compromise verdict | β no correlation | β
BruteForceWithSuccess Critical |
Session chain: LogonId β 4672 (admin!) β 4648 pivot to SRV2
|
β | β
Get-WinSecLogonSession
|
4740 lockouts on DC01 naming VPN01 as trigger |
β (ID not queried) | β contextual pass-through |
| 1102 "audit log cleared" on VPN01 at 04:02 | β | β
Critical, profile DefenseEvasion
|
| Was the 03:00β04:00 window even retained? | β unknowable | β
Get-WinSecLogCoverage
|
| Multi-host sweep of the VPN tier | β local only | β parallel WinRM + host statuses |
| Defensible export for the case file | CSV/HTML without hashes | β SHA-256 manifest, case notes |
| # | Investigator requirement | WinSecHunter feature |
|---|---|---|
| R1 | Find every trace of an IP/CIDR, any rendering, any IP-bearing field | 3-layer query engine, -DeepScan
|
| R2 | Cover all IP-relevant channels incl. RDP ops, firewall, Sysmon | 156-event catalog, 14 profiles |
| R3 | Scale to the estate, account for every host | parallel WinRM, -PassHostStatus, retry |
| R4 | Work on acquired images, air-gapped |
-Path *.evtx, offline analysis cmdlets |
| R5 | Answer "did they get in?" | success-after-failure, session reconstruction |
| R6 | Correct, decoded, classified output | NTSTATUS/Kerberos/%% decoders, ATT&CK tags |
| R7 | Prove evidence completeness | log coverage + audit-policy gap analysis |
| R8 | Court/handoff-grade artifacts | case bundles, SHA-256 manifest, self-contained HTML |
| R9 | Live monitoring during active incidents |
Trace-WinSecIp bookmarked tail |
| R10 | Context without leaking secrets | offline-first attribution, env-only API keys |
| Channel | Default state | IP-incident value |
|---|---|---|
Security |
β enabled (Win10+/2016+), 20 MB default | Core: auth, Kerberos, account mgmt, anti-forensics |
System |
β enabled | 7045 remote services, 104 log clears, 6008 dirty shutdowns |
TerminalServices-RemoteConnectionManager/Operational |
β enabled since Win8/2012 | 1149/1148: RDP auth with client IP, pre-NLA |
TerminalServices-LocalSessionManager/Operational |
β enabled | 21β25: session lifecycle with source IP |
Windows Firewall With Advanced Security/Firewall |
2004β2006 rule changes (5152-level packet logs are noisy) | |
Sysmon/Operational |
β separate install | EID 3: process β IP with direction β richest hunting source |
Tip
Enable what you're missing before the next incident: Audit Policy Guide.
Next: Getting Started β Β· Related: Architecture Β· Detection & Analysis
WinSecHunter v2.1.0 Β· PolyForm Noncommercial 1.0.0 Β· derivative of Get-SecurityEventsByIP.ps1 by Mikhail Deynekin
Repository Β· Changelog Β· Security policy Β· Contributing
π Home
π― Problem Domain π Getting Started π§ Architecture
π Cmdlet Reference π Detection and Analysis π Remote Collection π°οΈ Threat Intel and Attribution π‘οΈ Audit Policy Guide
π Reporting and Abuse π§Ύ Evidence and Reporting π Reference Tables
π§ Configuration π©Ί Troubleshooting and FAQ π§βπ» Development πΊοΈ Roadmap