Upgrading My Home Lab: Adding a SIEM Stack on a Budget

29 July 2023 | justruss.tech

This covers the build-out of a functional threat hunting and DFIR lab running on a single repurposed server. The focus is on realistic log volume, proper network segmentation, and having the right tools available for each phase of an
investigation.

Hardware baseline

The lab runs on a Dell PowerEdge R730 (2x Xeon E5-2640v4, 128GB RAM, 4x 1TB SAS in RAID10). A minimum viable setup for this work is 32GB RAM — enough to run 4-5 VMs simultaneously without constant swapping. The storage minimum is approximately
500GB to hold OS images, snapshots, and log data without constant cleanup.

Network topology

Internet
    |
[Home Router - 192.168.1.0/24]
    |
[Lab Switch - VLAN aware]
    |
    +-- VLAN 10 (172.16.10.0/24) -- Management
    |     - Velociraptor server
    |     - SIEM (Elastic)
    |     - Zeek sensor
    |
    +-- VLAN 20 (172.16.20.0/24) -- Attack
    |     - Kali Linux
    |
    +-- VLAN 30 (172.16.30.0/24) -- Targets
          - Windows 10 (patched)
          - Windows 10 (vulnerable - no EDR)
          - Windows Server 2019 (DC)
          - Ubuntu 22.04 (web target)

VLAN 20 (Attack) can reach VLAN 30 (Targets). VLAN 10 (Management) can reach both. Internet access from VLAN 20 routes through a Zeek tap so all attack tool downloads and C2 callbacks are logged. Targets have no direct internet access.

SIEM stack — Docker Compose

version: "3"
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.11.0
    environment:
      - discovery.type=single-node
      - ES_JAVA_OPTS=-Xms4g -Xmx4g
      - xpack.security.enabled=true
      - ELASTIC_PASSWORD=changeme
    volumes:
      - esdata:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"

  kibana:
    image: docker.elastic.co/kibana/kibana:8.11.0
    environment:
      - ELASTICSEARCH_URL=http://elasticsearch:9200
      - ELASTICSEARCH_USERNAME=kibana_system
      - ELASTICSEARCH_PASSWORD=changeme
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch

  fleet-server:
    image: docker.elastic.co/beats/elastic-agent:8.11.0
    environment:
      - FLEET_SERVER_ENABLE=true
      - FLEET_SERVER_ELASTICSEARCH_HOST=http://elasticsearch:9200
      - FLEET_SERVER_SERVICE_TOKEN=<generate_via_kibana>
    ports:
      - "8220:8220"

volumes:
  esdata:

Start with docker compose up -d. Kibana is available at port 5601. First login: create the kibana_system password via the elasticsearch container:

docker exec -it elastic_elasticsearch_1 \
  bin/elasticsearch-reset-password -u kibana_system

Sysmon configuration

The SwiftOnSecurity config is a solid starting point but needs additions for a lab:

# Download base config
Invoke-WebRequest -Uri https://raw.githubusercontent.com/SwiftOnSecurity/sysmon-config/master/sysmonconfig-export.xml -OutFile sysmon.xml

# Install Sysmon with config
.\Sysmon64.exe -accepteula -i sysmon.xml

# Verify
Get-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" -MaxEvents 5 | Select TimeCreated, Id, Message

Additional rules to add for the lab (add inside the appropriate EventFiltering sections):

<!-- Log all LSASS access regardless of source -->
<ProcessAccess onmatch="include">
  <TargetImage condition="is">C:\Windows\System32\lsass.exe</TargetImage>
</ProcessAccess>

<!-- Log all DNS queries -->
<DnsQuery onmatch="exclude">
  <QueryName condition="end with">.microsoft.com</QueryName>
  <QueryName condition="end with">.windows.com</QueryName>
</DnsQuery>

Elastic Agent deployment to Windows targets

# In Kibana: Fleet > Agent Policies > Create policy "Lab Windows"
# Add integrations: Windows (event logs), Sysmon

# On Windows target - download the agent from Fleet UI
# Then install:
.\elastic-agent.exe install --url=https://172.16.10.10:8220 `
  --enrollment-token=<token_from_fleet_ui> `
  --insecure  # lab only - use proper certs in production

After enrollment, events appear in Kibana under Discover within about 30 seconds. The Sysmon integration auto-parses all field mappings — process names, hashes, network connections — without manual index template configuration.

Zeek on the network tap

# Interface ens4 is the span/tap port receiving all lab traffic
zeekctl deploy
zeekctl status

# Verify logs are writing
tail -f /opt/zeek/logs/current/conn.log | python3 -m json.tool