01 Where Wazuh keeps your logs
The Wazuh dashboard stores two different things, and analysts confuse them constantly. Alerts are events that matched a rule at level 3 or higher; they live in the wazuh-alerts-* index and are what you see in Threat Hunting. Archives are every event the agent ever sent, matched or not, in wazuh-archives-*; they are off by default and you turn them on in ossec.conf with <logall_json>yes</logall_json>.
For day-to-day analysis you work in Threat Hunting → Events (older builds call it Discover). It gives you a search bar, a time picker, and a table of documents you can expand field by field. Everything below happens there.
The single most common mistake is a query that returns nothing because the time picker is stuck on "Last 15 minutes". Widen it to "Today" or "Last 24 hours" before you troubleshoot a query that looks empty.
This walkthrough assumes you have the Wazuh SOC home lab running with a Windows agent reporting. If you want the meaning of each event ID you filter on, keep the event ID reference open alongside.
02 Your first query: fields and DQL
The search bar uses DQL, Dashboards Query Language: field: value, combined with and, or and not. Wazuh nests Windows fields under data.win. The four you will type most:
| Field | What it holds | Example value |
|---|---|---|
data.win.system.eventID | The Windows event ID | "4625" |
data.win.system.channel | Which log the event came from | "Security", "System" |
data.win.eventdata.targetUserName | The account the event is about | "administrator" |
data.win.eventdata.ipAddress | Source IP, on logon events | "10.0.0.5" |
rule.id | The Wazuh rule that fired | "60117" |
rule.level | Alert severity 0–15 | >= 10 |
rule.description | Human-readable rule text | *logon failure* |
agent.name | Which monitored host | "Windows-Lab" |
Type a field name and the bar autocompletes both the field and its known values. Start simple, then stack conditions:
data.win.system.eventID: "4625" and data.win.eventdata.ipAddress: "10.0.0.5"
Click any row to expand it. The left column is every parsed field; hover one and hit the magnifier to add it as a filter without typing.
03 Eleven queries every analyst runs
These eleven cover most of what a SOC analyst types in a shift. Paste one into the search bar, set the time range, and read the results. Each links back to an event ID explained in the reference.
| Goal | Query |
|---|---|
| All failed logons | data.win.system.eventID: "4625" |
| A brute force in progress | rule.id: "60204" (multiple logon failures) |
| New user account created | data.win.system.eventID: "4720" |
| Someone added to a local admin group | data.win.system.eventID: "4732" |
| A new service installed (PsExec-style) | data.win.system.eventID: "7045" |
| Scheduled task created for persistence | data.win.system.eventID: "4698" |
| Security log cleared (anti-forensics) | rule.id: "60117" |
| Encoded PowerShell | data.win.eventdata.scriptBlockText: *FromBase64String* |
| Everything high severity | rule.level >= 10 |
| One host only | agent.name: "Windows-Lab" and rule.level >= 5 |
| Map to a MITRE technique | rule.mitre.id: "T1059.001" (PowerShell) |
Run a hydra brute force from Kali against the Windows host, then query data.win.system.eventID: "4625" and watch the count climb. Add and data.win.eventdata.targetUserName: "administrator" to isolate the account under attack. That loop, attack then hunt, is the whole skill.
04 From a query to a saved detection
A query you run twice deserves to be saved. Wazuh (built on OpenSearch Dashboards) gives you three levels of permanence:
- Saved search. Refine a query and its columns, then Save. It reappears in one click and can back a visualization.
- Visualization. Turn "count of 4625 over time" into a line chart, or "top source IPs" into a data table. Build from a saved search so the filter travels with it.
- Dashboard. Arrange several visualizations on one screen: failed logons, new accounts, high-severity alerts, per-agent volume. This is your shift view.
When a query reliably finds something bad, promote it from a manual hunt to an automatic rule. Add a local_rules.xml entry that inherits the built-in rule with <if_sid> and raises the level, or write a frequency rule that fires when the same source trips a rule N times in a window. That is how the brute-force rollup rule 60204 itself is built.
05 Reading a Wazuh alert
Every alert is a JSON document. Learn its anatomy once and you can read any of them. The fields that matter, top to bottom:
| Field | What it tells you |
|---|---|
rule.description | The plain-English summary. Read this first. |
rule.level | How much to care, 0 to 15. |
rule.id | The exact rule, so you can tune or mute it. |
rule.mitre.id, rule.mitre.technique | The ATT&CK technique, if mapped. |
agent.name, agent.ip | Which host produced it. |
data.win.system.eventID | The underlying Windows event. |
data.win.eventdata.* | The specifics: user, IP, process, command line. |
full_log | The raw event, for when the parsed fields are not enough. |
timestamp | When Wazuh received it (not always when it happened). |
The analyst's question is always the same: is this expected? A 4625 at 3am from an external IP against the administrator account reads very differently from one at 9am from a user who fat-fingered their password. The fields above are how you tell the two apart.
06 Wazuh log analysis FAQ
How do I search for a specific event ID in Wazuh?
In Threat Hunting or Discover, type data.win.system.eventID: "4625" in the search bar and set the time range. Combine conditions with and, for example data.win.system.eventID: "4625" and data.win.eventdata.targetUserName: "administrator".
What is the difference between Wazuh alerts and archives?
Alerts are events that matched a rule at level 3 or higher and live in the wazuh-alerts-* index. Archives are every event ever received, matched or not, in wazuh-archives-*. Archives are disabled by default; enable them with <logall_json>yes</logall_json> in ossec.conf.
Why is my Wazuh search returning no results?
Almost always the time picker. Widen it to Today or Last 24 hours. If it is still empty, confirm the agent is Active under Agents and that you are querying the right index pattern (wazuh-alerts vs wazuh-archives).
What query language does the Wazuh dashboard use?
DQL, Dashboards Query Language, because Wazuh is built on OpenSearch Dashboards. The syntax is field: value with and, or, not, ranges like rule.level >= 10, and wildcards like *FromBase64String*.
How do I turn a search into a saved detection?
Save the search, optionally build a visualization and dashboard from it, and when it reliably finds something malicious, add a rule to local_rules.xml that inherits the built-in rule with <if_sid> and raises the level or adds a frequency threshold.
Do I need to know a query language to use Wazuh?
Not to start. You can click a field value in any expanded event to filter by it, and click again to exclude it. DQL just lets you do the same thing faster and combine conditions the point-and-click filters cannot.