Blue Team Lesson 01 — The foundation of defensive security operations: seeing everything, understanding what matters, and responding before damage is done.
Log sources, SIEM concepts, AI-enhanced detection, alert pipeline design, and prompt engineering for threat hunting.
Identify all malicious activity hidden within noisy production log streams using AI-powered analysis.
Log monitoring techniques and detection rules are demonstrated for defensive security training and CTF competitions. Always ensure proper authorization before accessing system logs.
All examples in this lesson use synthetic or sanitized log data. In production environments, log access is governed by strict access controls, data retention policies, and privacy regulations (GDPR, HIPAA, SOC 2).
Every action on a system leaves a trace. Logs are the single source of truth for what actually happened — not what was supposed to happen.
"If it's not logged, it didn't happen. If it's logged but nobody reads it, it might as well not have happened."
Modern enterprises generate millions of log events per day. The challenge is not collection — it is making sense of the flood.
| Challenge | Scale |
|---|---|
| Average enterprise log volume | 1–10 TB/day |
| Median time to detect a breach (without monitoring) | 197 days |
| Median time to detect (with active monitoring) | ~70 days |
| Typical false positive rate (rule-based SIEM) | 40–60% |
| SOC analyst alert fatigue threshold | ~500 alerts/day |
This is exactly where AI changes the game — processing volume that no human team can handle, while learning to distinguish signal from noise.
Syslog is the backbone of Linux/Unix logging. Most security-relevant events flow through /var/log/.
| Log File | Contents |
|---|---|
/var/log/auth.log | Authentication events — logins, sudo, SSH |
/var/log/syslog | General system messages |
/var/log/kern.log | Kernel messages — hardware, drivers, firewall |
/var/log/apache2/access.log | HTTP requests to web server |
/var/log/audit/audit.log | auditd — fine-grained syscall logging |
<priority>timestamp hostname process[pid]: message
Priority encodes both facility (auth, kern, daemon) and severity (emerg, alert, crit, err, warning, notice, info, debug).
This is what an SSH brute force attack actually looks like in the logs:
Mar 15 03:14:07 websvr01 sshd[28341]: Failed password for root from 198.51.100.23 port 44821 ssh2
Mar 15 03:14:08 websvr01 sshd[28343]: Failed password for root from 198.51.100.23 port 44822 ssh2
Mar 15 03:14:08 websvr01 sshd[28345]: Failed password for root from 198.51.100.23 port 44823 ssh2
Mar 15 03:14:09 websvr01 sshd[28347]: Failed password for invalid user admin from 198.51.100.23 port 44824 ssh2
Mar 15 03:14:09 websvr01 sshd[28349]: Failed password for invalid user test from 198.51.100.23 port 44825 ssh2
Mar 15 03:14:10 websvr01 sshd[28351]: Failed password for invalid user ubuntu from 198.51.100.23 port 44826 ssh2
Mar 15 03:14:11 websvr01 sshd[28353]: Accepted password for deploy from 198.51.100.23 port 44827 ssh2
Mar 15 03:14:11 websvr01 sshd[28353]: pam_unix(sshd:session): session opened for user deploy
Rapid succession of failures from the same IP, username enumeration (root, admin, test, ubuntu), followed by a successful login — the attacker found valid credentials for deploy.
Windows uses a structured binary event log system accessible via Event Viewer or wevtutil. Security-relevant logs live in dedicated channels.
| Event ID | Channel | Meaning |
|---|---|---|
| 4624 | Security | Successful logon |
| 4625 | Security | Failed logon attempt |
| 4648 | Security | Logon using explicit credentials (pass-the-hash) |
| 4672 | Security | Special privileges assigned (admin logon) |
| 4688 | Security | New process created |
| 4720 | Security | User account created |
| 7045 | System | New service installed |
| 1102 | Security | Audit log cleared (anti-forensics!) |
A sequence of Event 4625 followed by Event 4624 from the same source is a classic brute-force-then-compromise pattern:
<!-- Event 4625: Failed Logon -->
<Event>
<System>
<EventID>4625</EventID>
<TimeCreated SystemTime="2025-03-15T03:14:07.123Z"/>
</System>
<EventData>
<Data Name="TargetUserName">Administrator</Data>
<Data Name="LogonType">10</Data>
<Data Name="IpAddress">203.0.113.45</Data>
<Data Name="FailureReason">%%2313</Data>
<Data Name="SubStatus">0xC000006A</Data>
</EventData>
</Event>
<!-- Event 4624: Successful Logon (4 minutes later) -->
<Event>
<System>
<EventID>4624</EventID>
<TimeCreated SystemTime="2025-03-15T03:18:42.456Z"/>
</System>
<EventData>
<Data Name="TargetUserName">svc_backup</Data>
<Data Name="LogonType">10</Data>
<Data Name="IpAddress">203.0.113.45</Data>
</EventData>
</Event>
LogonType 10 = Remote Desktop (RDP). The attacker failed against Administrator, then succeeded with svc_backup — a service account often left with weak passwords.
Application logs capture business-logic events. Web server access logs are a goldmine for detecting attacks at the HTTP layer.
198.51.100.77 - - [15/Mar/2025:04:22:11 +0000] "GET /admin/login HTTP/1.1" 200 3420 "-" "Mozilla/5.0"
198.51.100.77 - - [15/Mar/2025:04:22:12 +0000] "POST /admin/login HTTP/1.1" 401 182 "-" "python-requests/2.28"
198.51.100.77 - - [15/Mar/2025:04:22:12 +0000] "POST /admin/login HTTP/1.1" 401 182 "-" "python-requests/2.28"
198.51.100.77 - - [15/Mar/2025:04:22:13 +0000] "POST /admin/login HTTP/1.1" 200 8841 "-" "python-requests/2.28"
198.51.100.77 - - [15/Mar/2025:04:22:14 +0000] "GET /admin/users/export?fmt=csv HTTP/1.1" 200 194820 "-" "python-requests/2.28"
Automated credential stuffing (python-requests user agent, rapid POST to /admin/login), followed by immediate data exfiltration (export of user database). The 200 response on login + large response on export confirms success.
Cloud providers generate rich audit logs for every API call. These are critical for detecting misconfigurations, unauthorized access, and data exposure.
ConsoleLogin, AssumeRole, PutBucketPolicySecurity Information and Event Management (SIEM) platforms collect, normalize, correlate, and alert on logs from across the entire environment.
Splunk (enterprise leader) | Elastic/ELK Stack (open-source) | Microsoft Sentinel (cloud-native) | Grafana Loki (lightweight) | Chronicle (Google) | QRadar (IBM)
| Function | Traditional Approach | AI-Enhanced Approach |
|---|---|---|
| Aggregation | Regex parsers, manual format mapping, grok patterns | LLMs auto-parse unknown log formats, extract fields from unstructured text, normalize schemas |
| Correlation | Static correlation rules (if X then Y within Z minutes) | ML models learn normal behavior baselines and detect multi-stage attacks that no single rule catches |
| Alerting | Threshold-based rules, high false-positive rates | AI classifies alert severity, suppresses false positives, enriches alerts with context and recommended actions |
Traditional SIEM detects known threats via signatures. AI detects unknown threats via anomaly detection — the behavioral patterns that no rule anticipated.
Writing effective detection rules requires deep knowledge of log formats, attack techniques, and query languages. LLMs can accelerate this process dramatically.
Never deploy AI-generated detection rules to production without testing. LLMs can produce syntactically valid but logically flawed rules that either miss threats or generate thousands of false positives.
Sigma is the universal, platform-agnostic format for detection rules. Write once, convert to Splunk SPL, Elastic KQL, QRadar, and more.
title: SSH Brute Force Attempt
id: 5a3b4c2d-1e2f-4a5b-8c7d-9e0f1a2b3c4d
status: experimental
description: Detects multiple failed SSH login attempts from a single source
author: Blue Team AI Assistant
date: 2025/03/15
logsource:
product: linux
service: auth
detection:
selection:
syslog_message|contains: 'Failed password'
timeframe: 5m
condition: selection | count(src_ip) > 10
falsepositives:
- Legitimate users with mistyped passwords
- Automated monitoring tools
level: medium
tags:
- attack.credential_access
- attack.t1110.001
Splunk SPL is the most widely used SIEM query language in enterprise environments.
index=linux_auth sourcetype=syslog "Failed password"
| stats count as fail_count dc(user) as users_tried
values(user) as usernames
earliest(_time) as first_attempt
latest(_time) as last_attempt
by src_ip
| where fail_count > 10 AND users_tried > 3
| eval duration_sec = last_attempt - first_attempt
| where duration_sec < 300
| sort - fail_count
| table src_ip fail_count users_tried usernames duration_sec
index=linux_auth sourcetype=syslog
| eval status=if(searchmatch("Failed password"), "fail",
if(searchmatch("Accepted"), "success", "other"))
| where status!="other"
| stats count(eval(status="fail")) as failures
count(eval(status="success")) as successes by src_ip
| where failures > 10 AND successes > 0
| table src_ip failures successes
The Elastic Stack (Elasticsearch + Kibana) uses KQL for ad-hoc queries and EQL for event correlation.
event.action: "ssh_login" AND event.outcome: "failure" AND source.ip: *
sequence by source.ip with maxspan=5m
[authentication where event.outcome == "failure"] with runs=10
[authentication where event.outcome == "success"]
{
"query": {
"bool": {
"must": [
{ "match": { "event.action": "ssh_login" }},
{ "match": { "event.outcome": "failure" }},
{ "range": { "@timestamp": { "gte": "now-5m" }}}
]
}
},
"aggs": {
"by_source": {
"terms": { "field": "source.ip", "min_doc_count": 10 }
}
}
}
YARA rules are traditionally used for malware detection, but they are also powerful for scanning log files for specific patterns and indicators.
rule Webshell_Access_In_Logs {
meta:
description = "Detects web shell access patterns in web server logs"
author = "Blue Team CTF"
severity = "high"
mitre_attack = "T1505.003"
strings:
$shell1 = /GET\s+\/[^\s]*\.(php|asp|aspx|jsp)\?cmd=/ nocase
$shell2 = /POST\s+\/[^\s]*(upload|shell|backdoor|c99|r57)/ nocase
$shell3 = /eval\(base64_decode\(/ nocase
$exec1 = /cmd\.exe|\/bin\/(sh|bash)|powershell/ nocase
$b64cmd = /[A-Za-z0-9+\/]{40,}={0,2}/
condition:
any of ($shell*) or ($exec1 and $b64cmd)
}
Run against access logs: yara webshell_rules.yar /var/log/apache2/access.log
Rule-based detection catches known patterns. Anomaly detection catches what rules cannot — the novel, the subtle, the "never seen before."
| Technique | Best For | Example |
|---|---|---|
| Statistical (Z-score) | Volume-based anomalies | Login count 4 standard deviations above mean |
| Isolation Forest | Multi-dimensional outliers | Unusual combination of time + source + action |
| LSTM / Sequence Models | Temporal sequence anomalies | Unusual command sequence after SSH login |
| Clustering (DBSCAN) | Grouping similar events | Identifying coordinated scanning from a botnet |
| LLM-based Analysis | Unstructured log understanding | Explaining why a log sequence is suspicious |
LLMs can explain why something is anomalous in plain English — "This login is suspicious because the user has never connected from this ASN before, and the session immediately ran whoami followed by net user, which is consistent with credential compromise reconnaissance."
Can you spot the attacks hidden in normal traffic?
10.0.0.5 - - [15/Mar/2025:10:22:01 +0000] "GET / HTTP/1.1" 200 5124
10.0.0.5 - - [15/Mar/2025:10:22:02 +0000] "GET /style.css HTTP/1.1" 200 1842
192.168.1.100 - - [15/Mar/2025:10:22:03 +0000] "GET /api/users HTTP/1.1" 200 940
198.51.100.44 - - [15/Mar/2025:10:22:05 +0000] "GET /../../../../etc/passwd HTTP/1.1" 400 226
198.51.100.44 - - [15/Mar/2025:10:22:05 +0000] "GET /cgi-bin/../../etc/shadow HTTP/1.1" 403 199
10.0.0.5 - - [15/Mar/2025:10:22:06 +0000] "GET /images/logo.png HTTP/1.1" 200 14320
203.0.113.88 - - [15/Mar/2025:10:22:07 +0000] "GET /search?q=<script>alert(1)</script> HTTP/1.1" 200 3200
203.0.113.88 - - [15/Mar/2025:10:22:08 +0000] "GET /search?q=' OR 1=1-- HTTP/1.1" 200 3200
192.168.1.100 - - [15/Mar/2025:10:22:09 +0000] "POST /api/orders HTTP/1.1" 201 340
198.51.100.44 - - [15/Mar/2025:10:22:10 +0000] "POST /admin/upload.php HTTP/1.1" 200 89
198.51.100.44: Path traversal (../../../../etc/passwd), web shell upload (upload.php). 203.0.113.88: XSS probe (<script>alert(1)</script>), SQL injection (' OR 1=1--). Normal traffic from 10.0.0.5 and 192.168.1.100 provides camouflage.
Raw detection rules generate too many alerts. An effective pipeline enriches, deduplicates, classifies, and routes alerts before they reach an analyst.
Alert fatigue is the number one reason SOC analysts miss real threats. AI classification can reduce false positive volume by 60–80%.
Effective prompts for log analysis follow a structured pattern. Here is a template that consistently produces high-quality results:
You are a senior SOC analyst performing threat hunting.
CONTEXT:
- Environment: Production web application (Ubuntu 22.04, Apache 2.4, PostgreSQL 15)
- Time window: Last 24 hours
- Alert trigger: Anomalous outbound traffic volume from web-server-03
TASK:
Analyze the following log entries and:
1. Identify all suspicious or malicious activity
2. Classify each finding by MITRE ATT&CK technique
3. Assess severity (Critical / High / Medium / Low)
4. Recommend immediate response actions
5. Identify any indicators of compromise (IOCs)
LOG DATA:
[paste log entries here]
OUTPUT FORMAT:
For each finding, provide:
- Summary (one line)
- Evidence (specific log lines)
- ATT&CK Mapping
- Severity + Confidence
- Recommended Action
"Compare these logs against the normal baseline for this system. Flag anything that deviates by more than 2 standard deviations in frequency, timing, or source."
"Map these events to the Cyber Kill Chain. Identify which stage(s) are represented and whether a complete attack sequence is present."
"Extract all indicators of compromise: IP addresses, domains, file hashes, user agents, URLs, email addresses. Deduplicate and rate confidence."
"Reconstruct a minute-by-minute timeline of attacker activity. Correlate events across auth, web, and system logs."
Include 1–2 examples of previous log analysis findings in your prompt. This dramatically improves the quality and consistency of LLM output for security analysis.
Splunk is the enterprise SIEM market leader. Its Search Processing Language (SPL) is the query language every SOC analyst must know.
Prompt: "Show me all successful logins that occurred within
5 minutes of 10+ failed attempts from the same IP"
Generated SPL:
index=auth sourcetype=linux_secure
| transaction src_ip maxspan=5m
| where eventcount > 10
| search "Accepted password"
| table _time src_ip user eventcount duration
Elasticsearch + Logstash + Kibana — the open-source SIEM alternative powering thousands of SOCs worldwide.
| Component | Role | AI Integration |
|---|---|---|
| Elasticsearch | Search & storage engine | ML nodes for anomaly detection jobs, inference endpoints for LLM integration |
| Logstash | Log ingestion & parsing | LLM-assisted grok pattern generation for unknown log formats |
| Kibana | Visualization & dashboards | AI-powered alert explanations, natural language query bar |
| Elastic Agent | Endpoint data collection | Local ML models for endpoint anomaly detection |
{
"analysis_config": {
"bucket_span": "15m",
"detectors": [{
"function": "high_count",
"partition_field_name": "source.ip",
"over_field_name": "destination.port"
}]
},
"data_description": { "time_field": "@timestamp" }
}
Loki is a lightweight, cost-effective log aggregation system by Grafana Labs. It indexes only metadata (labels), not full text — making it dramatically cheaper to operate at scale.
# Count failed SSH logins per source IP in the last hour
{job="syslog", host="websvr01"} |= "Failed password"
| pattern `Failed password for from port `
| count_over_time({src_ip!=""}[1h]) by (src_ip)
| sort desc
| Feature | Splunk | ELK Stack | Grafana Loki |
|---|---|---|---|
| License | Commercial | Open Source / Commercial | Open Source |
| Query Language | SPL | KQL / EQL / Lucene | LogQL |
| Indexing | Full text | Full text (inverted index) | Labels only |
| Cost at Scale | High (GB/day pricing) | Medium (self-managed infra) | Low (minimal indexing) |
| Built-in ML | MLTK, Adaptive Thresholds | ML nodes, Anomaly Jobs | Grafana ML plugin |
| LLM Integration | Splunk AI Assistant | Elastic AI Assistant | Grafana AI features |
| Best For | Enterprise SOC | Mid-size / flexible | Cloud-native, cost-sensitive |
Putting it all together — from raw log to analyst action:
+-------------------+
| Log Sources |
| syslog, WinEvent, |
| cloud audit, apps |
+---------+---------+
|
+---------v---------+
| Collection & |
| Normalization |
| (Logstash/Fluentd)|
+---------+---------+
|
+---------v---------+
| SIEM / Search |
| (Splunk/Elastic/ |
| Loki) |
+---------+---------+
|
+------------+------------+
| |
+---------v---------+ +-----------v-----------+
| Rule-Based | | AI Anomaly |
| Detection | | Detection |
| (Sigma/SPL/KQL) | | (ML models / LLM) |
+---------+---------+ +-----------+-----------+
| |
+------------+------------+
|
+---------v---------+
| AI Triage & |
| Classification |
| (LLM enrichment) |
+---------+---------+
|
+---------v---------+
| Alert Routing |
| & Response |
+-------------------+
Here is a minimal Python script that uses Claude to analyze log entries for security threats:
import anthropic
client = anthropic.Anthropic()
SYSTEM_PROMPT = """You are a senior SOC analyst. Analyze log entries for:
1. Security threats (classify by MITRE ATT&CK)
2. Anomalous patterns
3. Indicators of compromise (IOCs)
Respond with structured JSON."""
def analyze_logs(log_entries: str) -> str:
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=2048,
system=SYSTEM_PROMPT,
messages=[{
"role": "user",
"content": f"Analyze these logs:\n\n{log_entries}"
}]
)
return response.content[0].text
# Example usage
logs = """
Mar 15 03:14:07 websvr01 sshd[28341]: Failed password for root from 198.51.100.23 port 44821 ssh2
Mar 15 03:14:08 websvr01 sshd[28343]: Failed password for root from 198.51.100.23 port 44822 ssh2
Mar 15 03:14:11 websvr01 sshd[28353]: Accepted password for deploy from 198.51.100.23 port 44827 ssh2
"""
findings = analyze_logs(logs)
print(findings)
For production environments, you need to process logs as a continuous stream rather than in batches:
import json
import time
from collections import defaultdict
class LogStreamAnalyzer:
"""Lightweight streaming log analyzer with AI escalation."""
def __init__(self, threshold=10, window_sec=300):
self.threshold = threshold
self.window = window_sec
self.failed_logins = defaultdict(list) # src_ip -> [timestamps]
def process_line(self, line: str):
"""Process a single log line. Returns alert dict or None."""
if "Failed password" in line:
src_ip = self._extract_ip(line)
ts = time.time()
self.failed_logins[src_ip].append(ts)
# Prune old entries outside the window
self.failed_logins[src_ip] = [
t for t in self.failed_logins[src_ip]
if ts - t < self.window
]
if len(self.failed_logins[src_ip]) >= self.threshold:
return self._create_alert(src_ip, line)
elif "Accepted password" in line:
src_ip = self._extract_ip(line)
if src_ip in self.failed_logins:
return self._escalate_to_ai(src_ip, line)
return None
def _escalate_to_ai(self, src_ip, line):
"""Send to LLM for deeper analysis when brute force succeeds."""
return {
"severity": "CRITICAL",
"type": "brute_force_success",
"src_ip": src_ip,
"action": "escalate_to_llm_triage"
}
Common mistakes that undermine your log monitoring program:
A mature detection engineering practice uses AI at every stage:
MTTD (Mean Time to Detect) | MTTR (Mean Time to Respond) | TP Rate (True Positive %) | Coverage (% of ATT&CK techniques with at least one detection rule)
Every detection rule should map to at least one ATT&CK technique. Here are the techniques most commonly detected through log analysis:
| Technique | ID | Log Source |
|---|---|---|
| Brute Force | T1110 | auth.log, Windows 4625 |
| Valid Accounts | T1078 | auth.log, Windows 4624 |
| Remote Services (RDP) | T1021.001 | Windows 4624 (Type 10) |
| Web Shell | T1505.003 | Web access logs, process logs |
| Command & Scripting Interpreter | T1059 | Windows 4688, auditd |
| Indicator Removal (Log Clear) | T1070.001 | Windows 1102 |
| Exfiltration Over Web | T1041 | Proxy logs, DNS logs |
| Account Creation | T1136 | Windows 4720, auth.log |
You are a SOC analyst at Acme Corp. Your SIEM has ingested 24 hours of logs from a web server, authentication service, and cloud audit trail. Somewhere in the noise, an attacker has compromised the environment.
Hidden in the log data you will find these attack stages:
Lesson 02 dives into network traffic analysis — packet captures, flow data, and using AI to detect command-and-control channels hiding in encrypted traffic.