courses

SIEM, SOC, and Threat Detection

Seeing the whole attack, not one log line

Security Information and Event Management (SIEM) systems aggregate, correlate, and alert on security events from across an environment. A Security Operations Center (SOC) is the team and process structure that uses SIEM, IDS/IPS, and EDR tools to detect, investigate, and respond to threats. This page covers the tooling and concepts that underpin threat detection operations.

ℹ️ The whole point of a SIEM is correlation: a single failed login is noise, but a failed login followed by a successful one, a new process, and an outbound connection is an attack chain. The detections here feed the response process on the Incident Response page.

SIEM

A SIEM ingests log data from servers, network devices, applications, and cloud services, then applies correlation rules and analytics to identify suspicious patterns that no single log source would reveal alone.

SIEM core functions

Function Description
Log aggregation Collect logs from diverse sources into a central store
Normalization Parse different log formats into a common schema
Correlation Match events across sources to detect multi-stage attacks
Alerting Generate alerts when rules match
Retention Store logs for compliance and forensic investigation
Dashboards Operational views of security posture

Elastic Security (Elastic SIEM)

The Elastic Stack (Elasticsearch, Logstash, Kibana) is the most widely deployed open-source log management platform, and Elastic Security adds SIEM capabilities on top.

# Install Elasticsearch (single-node, for lab use)
curl -fsSL https://artifacts.elastic.co/GPG-KEY-elasticsearch \
    | sudo gpg --dearmor -o /usr/share/keyrings/elastic-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/elastic-keyring.gpg] \
    https://artifacts.elastic.co/packages/8.x/apt stable main" \
    | sudo tee /etc/apt/sources.list.d/elastic-8.x.list
sudo apt update && sudo apt install elasticsearch kibana

sudo systemctl enable --now elasticsearch kibana
# Filebeat: ship logs to Elasticsearch
# /etc/filebeat/filebeat.yml (key sections)
filebeat.inputs:
  - type: filestream
    id: syslog-input
    paths:
      - /var/log/syslog
      - /var/log/auth.log
    tags: ["syslog", "linux"]

  - type: filestream
    id: nginx-input
    paths:
      - /var/log/nginx/access.log
      - /var/log/nginx/error.log
    tags: ["nginx"]

output.elasticsearch:
  hosts: ["https://localhost:9200"]
  username: "filebeat_writer"
  password: "${FILEBEAT_PASSWORD}"
  ssl.certificate_authorities: ["/etc/elasticsearch/certs/http_ca.crt"]

setup.kibana:
  host: "localhost:5601"
# Enable Filebeat modules for common log formats
filebeat modules enable system nginx auditd
filebeat setup --dashboards    # load pre-built Kibana dashboards
systemctl restart filebeat
# Python: query Elasticsearch for security events
from elasticsearch import Elasticsearch
from datetime import datetime, timedelta

es = Elasticsearch(
    'https://localhost:9200',
    basic_auth=('elastic', 'password'),
    ca_certs='/etc/elasticsearch/certs/http_ca.crt',
)

# Find failed SSH logins in the last hour
query = {
    "bool": {
        "must": [
            {"match": {"event.action": "ssh_login"}},
            {"match": {"event.outcome": "failure"}},
            {"range": {
                "@timestamp": {
                    "gte": (datetime.utcnow() - timedelta(hours=1)).isoformat(),
                    "lte": "now"
                }
            }}
        ]
    }
}

result = es.search(index='filebeat-*', query=query, size=100)
for hit in result['hits']['hits']:
    src = hit['_source']
    print(f"{src.get('@timestamp')}: Failed SSH from {src.get('source', {}).get('ip')} "
          f"for user {src.get('user', {}).get('name')}")

Wazuh

Wazuh is an open-source security platform that combines SIEM, HIDS (Host-based Intrusion Detection), and compliance monitoring:

# Wazuh manager installation (single-node)
curl -sO https://packages.wazuh.com/4.9/wazuh-install.sh
sudo bash wazuh-install.sh -a

# Deploy Wazuh agent on Linux hosts
curl -sO https://packages.wazuh.com/4.9/wazuh-agent-linux-install.sh
WAZUH_MANAGER='wazuh.example.com' sudo bash wazuh-agent-linux-install.sh
sudo systemctl enable --now wazuh-agent

# Check agent connection status
sudo /var/ossec/bin/agent_control -l

Intrusion Detection and Prevention

IDS vs IPS

Aspect IDS (Detection) IPS (Prevention)
Position Out-of-band (mirror/tap) Inline (traffic passes through)
Response Alert only Alert and block
Risk No impact on traffic if fails Can disrupt traffic if misconfigured
Use case Monitoring, forensics Active blocking of known threats

Snort / Suricata (network IDS/IPS)

Suricata is the modern successor to Snort, supporting multi-threading and both IDS and IPS modes:

# Install Suricata
sudo apt install suricata

# Update rules (Emerging Threats open ruleset)
sudo suricata-update

# Run in IDS mode on an interface
sudo suricata -c /etc/suricata/suricata.yaml -i eth0

# Run in IPS mode (inline, drops matching packets)
sudo suricata --af-packet -c /etc/suricata/suricata.yaml

# Test configuration
sudo suricata -T -c /etc/suricata/suricata.yaml
# /etc/suricata/suricata.yaml key sections
vars:
  address-groups:
    HOME_NET: "[192.168.0.0/16,10.0.0.0/8]"
    EXTERNAL_NET: "!$HOME_NET"

default-log-dir: /var/log/suricata/

outputs:
  - eve-log:
      enabled: yes
      filetype: regular
      filename: eve.json
      types:
        - alert
        - http
        - dns
        - tls
        - ssh
# Parse Suricata EVE JSON logs
import json

def parse_suricata_alerts(logfile: str):
    with open(logfile) as f:
        for line in f:
            event = json.loads(line)
            if event.get('event_type') == 'alert':
                alert = event['alert']
                print(
                    f"{event['timestamp']} "
                    f"[{alert['severity']}] {alert['signature']} "
                    f"({event.get('src_ip')}:{event.get('src_port')} → "
                    f"{event.get('dest_ip')}:{event.get('dest_port')})"
                )

parse_suricata_alerts('/var/log/suricata/eve.json')

Falco (runtime container security)

Falco monitors system calls at runtime to detect anomalous behavior inside containers and on Linux hosts. It is the standard tool for Kubernetes runtime security.

# Install Falco
curl -fsSL https://falco.org/repo/falcosecurity-packages.asc \
    | sudo gpg --dearmor -o /usr/share/keyrings/falco-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/falco-archive-keyring.gpg] \
    https://download.falco.org/packages/deb stable main" \
    | sudo tee /etc/apt/sources.list.d/falcosecurity.list
sudo apt update && sudo apt install falco

sudo systemctl enable --now falco

# View alerts in real time
sudo journalctl -fu falco
# Custom Falco rule: alert on shell spawned inside a container
- rule: Shell Spawned in Container
  desc: A shell was spawned inside a container — possible container escape or interactive backdoor
  condition: >
    spawned_process
    and container
    and proc.name in (shell_binaries)
    and not proc.pname in (shell_binaries)
  output: >
    Shell spawned in container
    (user=%user.name container=%container.name image=%container.image.repository
    shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline)
  priority: WARNING
  tags: [container, shell, T1059]

- rule: Sensitive File Read
  desc: A non-privileged process read a sensitive file
  condition: >
    open_read
    and fd.name in (sensitive_files)
    and not proc.name in (trusted_readers)
  output: >
    Sensitive file read (user=%user.name file=%fd.name proc=%proc.name)
  priority: ERROR
# Falco in Kubernetes (DaemonSet)
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm install falco falcosecurity/falco \
    --namespace falco --create-namespace \
    --set falco.grpc.enabled=true \
    --set falco.grpc_output.enabled=true

Log Analysis

Effective security monitoring depends on collecting the right logs, retaining them long enough, and being able to search them efficiently.

What to log

Source Key log types
Authentication Login success/failure, MFA events, password changes, privilege escalation
Network Firewall accepts/denies, DNS queries, proxy requests, VPN connections
Application API access (method, path, status, user), errors, configuration changes
System Package installations, cron job execution, kernel messages, service start/stop
Container Image pulls, container start/stop, exec into container
Cloud IAM API calls (CloudTrail), config changes (AWS Config), console logins

Structured logging for security

Applications should emit structured (JSON) logs that are easily parsed by SIEM systems:

import logging
import json
import time

class SecurityLogger:
    """Emit structured security events to stdout (collected by log aggregator)."""

    def __init__(self, service_name: str):
        self.service = service_name

    def _emit(self, level: str, event_type: str, **fields):
        record = {
            "timestamp": time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),
            "level": level,
            "service": self.service,
            "event_type": event_type,
            **fields,
        }
        print(json.dumps(record), flush=True)

    def auth_success(self, user_id: str, ip: str, method: str):
        self._emit("INFO", "auth.success",
                   user_id=user_id, source_ip=ip, auth_method=method)

    def auth_failure(self, username: str, ip: str, reason: str):
        self._emit("WARN", "auth.failure",
                   username=username, source_ip=ip, reason=reason)

    def privilege_escalation(self, user_id: str, from_role: str, to_role: str):
        self._emit("WARN", "authz.privilege_change",
                   user_id=user_id, from_role=from_role, to_role=to_role)

    def data_access(self, user_id: str, resource: str, action: str, outcome: str):
        self._emit("INFO", "data.access",
                   user_id=user_id, resource=resource, action=action, outcome=outcome)

logger = SecurityLogger("payment-api")
logger.auth_failure("alice", "203.0.113.42", "invalid_password")
# Output: {"timestamp": "...", "level": "WARN", "service": "payment-api",
#           "event_type": "auth.failure", "username": "alice",
#           "source_ip": "203.0.113.42", "reason": "invalid_password"}

Log retention requirements

Regulation / Standard Minimum retention
PCI DSS 1 year (3 months immediately available)
HIPAA 6 years
SOC 2 1 year (common practice)
NIST SP 800-53 3 years (federal systems)
GDPR Varies by data category

Endpoint Detection and Response (EDR)

EDR tools provide continuous monitoring of endpoint activity — processes, network connections, file changes, registry modifications — and enable real-time response to threats.

EDR capabilities

Capability Description
Process monitoring Record all process executions with parent-child relationships
Network monitoring Log all outbound connections (IP, port, process)
File integrity monitoring Alert on changes to critical system files
Memory analysis Detect process injection, shellcode execution
Remote containment Isolate a compromised host from the network
Forensic collection Collect artifacts (memory dump, process list, network state)

Auditd (Linux auditing framework)

Auditd is the Linux kernel audit subsystem. It records security-relevant system calls to a tamper-evident log.

# Install and enable
sudo apt install auditd audispd-plugins
sudo systemctl enable --now auditd

# View audit log
sudo ausearch -i                         # human-readable format
sudo ausearch -m LOGIN --start today     # login events today
sudo ausearch -f /etc/passwd             # access to /etc/passwd
sudo ausearch -x /bin/su                 # execution of su

# Generate a report
sudo aureport --summary
sudo aureport --auth                     # authentication report
sudo aureport --failed                   # failed events
# Audit rules: /etc/audit/rules.d/security.rules
# Monitor writes to /etc/passwd and /etc/shadow
-w /etc/passwd -p wa -k identity-files
-w /etc/shadow -p wa -k identity-files
-w /etc/sudoers -p wa -k privilege-escalation

# Monitor execution of su and sudo
-w /bin/su -p x -k privilege-escalation
-w /usr/bin/sudo -p x -k privilege-escalation

# Monitor network configuration changes
-w /etc/network/ -p wa -k network-config
-w /etc/hosts -p wa -k network-config

# Monitor all executions (high volume — use carefully)
-a always,exit -F arch=b64 -S execve -k exec-all

# Load rules
sudo augenrules --load
sudo auditctl -l                         # list active rules

SOAR (Security Orchestration, Automation, and Response)

SOAR platforms automate the repetitive tasks in security operations: enriching alerts, correlating data, assigning tickets, and executing response actions.

SOAR concepts

A SOAR playbook is an automated workflow triggered by a security event:

Alert: Failed SSH login from 203.0.113.42 (10 times in 5 minutes)
    │
    ▼
Enrich: Look up IP in threat intelligence feeds
    │
    ├── IP is in threat feed → Auto-block at firewall, create P1 ticket
    │
    └── IP not in threat feed
        │
        ▼
    Check: Is this a known developer IP?
        │
        ├── Yes → Notify developer, close alert
        │
        └── No → Block temporarily, alert SOC analyst for review

Python-based SOAR automation

# Simple SOAR playbook: respond to failed SSH brute force
import requests
import subprocess
import json
from datetime import datetime

THREAT_INTEL_API = 'https://api.abuseipdb.com/api/v2/check'
ABUSEIPDB_KEY = 'your-api-key'          # load from OpenBao in production

def check_threat_intel(ip: str) -> dict:
    """Check an IP against AbuseIPDB threat intelligence."""
    resp = requests.get(
        THREAT_INTEL_API,
        headers={'Key': ABUSEIPDB_KEY, 'Accept': 'application/json'},
        params={'ipAddress': ip, 'maxAgeInDays': 90},
    )
    return resp.json().get('data', {})

def block_ip_firewall(ip: str):
    """Add a firewall rule to block the IP."""
    subprocess.run(
        ['iptables', '-A', 'INPUT', '-s', ip, '-j', 'DROP'],
        check=True
    )
    print(f"[{datetime.now()}] Blocked {ip} at firewall")

def create_ticket(ip: str, abuse_score: int, event_count: int):
    """Create a ticket in the ticketing system (example: plain log)."""
    ticket = {
        'timestamp': datetime.now().isoformat(),
        'title': f'SSH brute force from {ip}',
        'priority': 'P1' if abuse_score > 50 else 'P2',
        'details': {
            'source_ip': ip,
            'abuse_confidence_score': abuse_score,
            'failed_logins': event_count,
        }
    }
    print(f"TICKET: {json.dumps(ticket, indent=2)}")

def handle_ssh_brute_force(source_ip: str, event_count: int):
    """Main playbook: investigate and respond to SSH brute force."""
    intel = check_threat_intel(source_ip)
    abuse_score = intel.get('abuseConfidenceScore', 0)
    is_known_attacker = abuse_score > 25

    if is_known_attacker:
        block_ip_firewall(source_ip)
        create_ticket(source_ip, abuse_score, event_count)
    elif event_count > 50:
        # High volume even from unknown IP — block temporarily
        block_ip_firewall(source_ip)
        create_ticket(source_ip, abuse_score, event_count)
    else:
        print(f"[INFO] {source_ip}: {event_count} failures, score {abuse_score} — monitoring")

# Trigger from SIEM alert
handle_ssh_brute_force('203.0.113.42', event_count=75)

Alert types and severity

Severity Response time Examples
Critical (P1) Immediate (minutes) Active ransomware, data exfiltration in progress, root compromise
High (P2) Within 1 hour Confirmed malware, credential stuffing success, lateral movement
Medium (P3) Within 4 hours Repeated failed logins, policy violation, suspicious reconnaissance
Low (P4) Within 24 hours Informational anomaly, single failed login, configuration drift

Key takeaways

References


Related course pages: Suricata IDS/IPS · Incident Response · Vulnerability Management

🛠️ Maintenance note: versions in the install snippets move — Elastic is on the 8.x APT repo (9.x exists), Wazuh paths here pin 4.9, and Falco’s repo/keyring URLs change. NIST SP 800-92 is under revision (a draft Rev. 1 is in progress). Re-verify the package repos, agent install scripts, and retention figures against current sources each term.