Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions extensions/sysmon/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Sysmon extension

- Extension Name: sysmon
- Description: Deploy Sysmon with olafhartong modular config to all Windows domain machines
- Machine name: none (agent-only extension)
- Compatible with labs: *

## What it does

- Installs **Sysmon64** on every Windows machine in the `domain` group
- Uses **[olafhartong's sysmon-modular config](https://github.com/olafhartong/sysmon-modular)** for comprehensive detection coverage
- Covers: process creation, network connections, file creation, registry events, DNS queries, pipe events, WMI events, and more
- If Sysmon is already installed, updates the config in-place

## No prerequisites

No new VM is provisioned. This extension is agent-only.

## Install

```
instance_id> install_extension sysmon
```

## Purple team value

Sysmon events complement Windows Security event logs and are essential for detecting:
- Lateral movement (PtH, PtT, WMI, PSExec)
- Credential dumping (LSASS access)
- Persistence (registry, scheduled tasks, WMI subscriptions)
- C2 beaconing (DNS, network connections)
- LOLBins and living-off-the-land techniques

Pairs well with the **elk** and **wazuh** extensions for log ingestion.

## Credits
- [olafhartong/sysmon-modular](https://github.com/olafhartong/sysmon-modular)
- Sysinternals Sysmon: https://docs.microsoft.com/en-us/sysinternals/downloads/sysmon
4 changes: 4 additions & 0 deletions extensions/sysmon/ansible/install.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- name: Deploy Sysmon to all Windows domain machines
hosts: sysmon_targets
roles:
- { role: 'sysmon_windows', tags: 'sysmon' }
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Sysmon binary - downloaded from Sysinternals
sysmon_download_url: "https://download.sysinternals.com/files/Sysmon.zip"
sysmon_install_location: "c:\\sysmon"

# olafhartong modular sysmon config (comprehensive detection coverage)
sysmon_config_url: "https://raw.githubusercontent.com/olafhartong/sysmon-modular/master/sysmonconfig.xml"
sysmon_config_file: "sysmonconfig.xml"

sysmon_service_name: "sysmon64"
57 changes: 57 additions & 0 deletions extensions/sysmon/ansible/roles/sysmon_windows/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
- name: Check if Sysmon service exists
win_service:
name: "{{ sysmon_service_name }}"
register: sysmon_service
failed_when: false

- name: Create Sysmon install directory
ansible.windows.win_file:
path: "{{ sysmon_install_location }}"
state: directory

- name: Download Sysmon zip
win_get_url:
url: "{{ sysmon_download_url }}"
dest: "{{ sysmon_install_location }}\\Sysmon.zip"
register: sysmon_download
until: sysmon_download is succeeded
retries: 3
delay: 5
when: not sysmon_service.exists

- name: Unzip Sysmon
community.windows.win_unzip:
src: "{{ sysmon_install_location }}\\Sysmon.zip"
dest: "{{ sysmon_install_location }}"
when: not sysmon_service.exists

- name: Download olafhartong modular sysmon config
win_get_url:
url: "{{ sysmon_config_url }}"
dest: "{{ sysmon_install_location }}\\{{ sysmon_config_file }}"
register: sysmon_config_download
until: sysmon_config_download is succeeded
retries: 3
delay: 5

- name: Install Sysmon with modular config
win_command: >
{{ sysmon_install_location }}\Sysmon64.exe -accepteula -i
{{ sysmon_install_location }}\{{ sysmon_config_file }}
args:
chdir: "{{ sysmon_install_location }}"
when: not sysmon_service.exists

- name: Update Sysmon config if already installed
win_command: >
{{ sysmon_install_location }}\Sysmon64.exe -c
{{ sysmon_install_location }}\{{ sysmon_config_file }}
args:
chdir: "{{ sysmon_install_location }}"
when: sysmon_service.exists

- name: Ensure Sysmon service is running
win_service:
name: "{{ sysmon_service_name }}"
state: started
start_mode: auto
9 changes: 9 additions & 0 deletions extensions/sysmon/extension.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "sysmon",
"description": "Deploy Sysmon with olafhartong modular config to all Windows domain machines",
"machines": [],
"compatibility": [
"*"
],
"impact": "installs Sysmon64 on all Windows domain machines with a modular detection-focused configuration"
}
5 changes: 5 additions & 0 deletions extensions/sysmon/inventory
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
; EXTENSION : SYSMON ------------------------------------------
; No new machine - agents only

[sysmon_targets:children]
domain
77 changes: 77 additions & 0 deletions extensions/velociraptor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Velociraptor extension

- Extension Name: velociraptor
- Description: Add Velociraptor DFIR platform - server + agents on all Windows domain machines
- Machine name: `{{lab_name}}-VELO`
- IP: `{{ip_range}}.54`
- Compatible with labs: *

## What it does

- Spins up an **Ubuntu 22.04** VM running the **Velociraptor** server
- Generates server config and auto-repackages the Windows agent MSI with embedded certs
- Deploys the **Velociraptor agent** to every Windows machine in the `domain` group
- Exposes the **Velociraptor GUI** on port `8889`

## Prerequisites

On ludus prepare template:
```
ludus templates add -d ubuntu-22.04-x64-server
ludus templates build
```

## Install

```
instance_id> install_extension velociraptor
```

## Access

After installation, access the web UI at:
```
https://<ip_range>.54:8889
Username: admin
Password: Velo@GOAD2024!
```

> Note: The cert is self-signed — accept the browser warning.

## Useful VQL hunts for purple teaming

```sql
-- Find all processes with LSASS handles (credential dumping)
SELECT Pid, Name, CommandLine FROM pslist()
WHERE Name =~ "lsass"

-- Hunt for scheduled tasks (persistence)
SELECT * FROM Artifact.Windows.System.ScheduledTasks()

-- Find lateral movement via WMI
SELECT * FROM Artifact.Windows.EventLogs.EvtxHunter(
EvtxGlob="**\\Security.evtx",
IdFilter="4648"
)

-- Detect Kerberoasting (TGS requests for service accounts)
SELECT * FROM Artifact.Windows.EventLogs.EvtxHunter(
EvtxGlob="**\\Security.evtx",
IdFilter="4769"
)
WHERE TicketEncryptionType = "0x17"
```

## Purple team value

Velociraptor is a **live forensics and endpoint hunting** platform:
- **Incident response**: Live memory, process, registry, filesystem triage
- **Threat hunting**: VQL queries across the entire fleet simultaneously
- **Detection validation**: Confirm whether attacks were actually executed and what artifacts they left
- **Timeline reconstruction**: Correlate artifacts across multiple machines

Pairs well with **sysmon** (for enriched Windows events) and **zeek** (for network context).

## Credits
- https://github.com/Velocidex/velociraptor
- https://docs.velociraptor.app/
12 changes: 12 additions & 0 deletions extensions/velociraptor/ansible/install.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
- name: Install Velociraptor server
hosts: velociraptor_server
become: yes
roles:
- { role: 'velociraptor_server', tags: 'velociraptor_server' }

- name: Deploy Velociraptor agent to Windows machines
hosts: velociraptor_agents
roles:
- { role: 'velociraptor_agent', tags: 'velociraptor_agent' }
vars:
velociraptor_server_host: "{{ hostvars['velociraptor']['ansible_host'] }}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
velociraptor_agent_install_location: "c:\\tmp"
velociraptor_agent_msi_name: "velociraptor-agent.msi"
velociraptor_agent_service_name: "Velociraptor"
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
- name: Check if Velociraptor agent service exists
win_service:
name: "{{ velociraptor_agent_service_name }}"
register: velo_agent_service
failed_when: false

- name: Create agent install directory
ansible.windows.win_file:
path: "{{ velociraptor_agent_install_location }}"
state: directory

# Fetch the repacked MSI from the Velociraptor server via SSH/fetch
- name: Fetch repacked Velociraptor agent MSI from server
ansible.builtin.fetch:
src: "/opt/velociraptor/velociraptor-agent.msi"
dest: "/tmp/velociraptor-agent.msi"
flat: yes
delegate_to: "{{ velociraptor_server_host }}"
become: yes
run_once: true
when: not velo_agent_service.exists

- name: Copy Velociraptor agent MSI to Windows machine
win_copy:
src: "/tmp/velociraptor-agent.msi"
dest: "{{ velociraptor_agent_install_location }}\\{{ velociraptor_agent_msi_name }}"
when: not velo_agent_service.exists

- name: Install Velociraptor agent MSI
win_command: >
msiexec.exe /i "{{ velociraptor_agent_install_location }}\{{ velociraptor_agent_msi_name }}" /qn
when: not velo_agent_service.exists

- name: Ensure Velociraptor agent service is running
win_service:
name: "{{ velociraptor_agent_service_name }}"
state: started
start_mode: auto
when: not velo_agent_service.exists
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Velociraptor version - check https://github.com/Velocidex/velociraptor/releases
velociraptor_version: "0.72.4"

velociraptor_linux_url: "https://github.com/Velocidex/velociraptor/releases/download/v{{ velociraptor_version }}/velociraptor-v{{ velociraptor_version }}-linux-amd64"
velociraptor_windows_url: "https://github.com/Velocidex/velociraptor/releases/download/v{{ velociraptor_version }}/velociraptor-v{{ velociraptor_version }}-windows-amd64.exe"
velociraptor_windows_msi_url: "https://github.com/Velocidex/velociraptor/releases/download/v{{ velociraptor_version }}/velociraptor-v{{ velociraptor_version }}-windows-amd64.msi"

velociraptor_install_dir: "/opt/velociraptor"
velociraptor_config_dir: "/etc/velociraptor"
velociraptor_binary: "/usr/local/bin/velociraptor"

# Web UI / API
velociraptor_gui_port: 8889
velociraptor_frontend_port: 8000

# Admin credentials for the web UI
velociraptor_admin_user: "admin"
velociraptor_admin_password: "Velo@GOAD2024!"
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
- name: Check Velociraptor service facts
ansible.builtin.service_facts:

- name: Create Velociraptor directories
ansible.builtin.file:
path: "{{ item }}"
state: directory
mode: '0750'
loop:
- "{{ velociraptor_install_dir }}"
- "{{ velociraptor_config_dir }}"

- name: Download Velociraptor binary
ansible.builtin.get_url:
url: "{{ velociraptor_linux_url }}"
dest: "{{ velociraptor_binary }}"
mode: '0755'
when: not ansible_facts.services['velociraptor.service'] is defined

# Generate server config non-interactively using --merge to set hostname/ports
- name: Generate Velociraptor server config
ansible.builtin.shell: |
{{ velociraptor_binary }} config generate \
--merge '{"Frontend":{"hostname":"{{ ansible_host }}","bind_address":"0.0.0.0","bind_port":{{ velociraptor_frontend_port }}},"GUI":{"bind_address":"0.0.0.0","bind_port":{{ velociraptor_gui_port }}},"Client":{"server_urls":["https://{{ ansible_host }}:{{ velociraptor_frontend_port }}/"]},"logging":{"output_directory":"/opt/velociraptor/logs","separate_logs_per_component":true}}' \
> {{ velociraptor_config_dir }}/server.config.yaml
args:
creates: "{{ velociraptor_config_dir }}/server.config.yaml"

- name: Secure server config
ansible.builtin.file:
path: "{{ velociraptor_config_dir }}/server.config.yaml"
mode: '0600'

# Extract client config from server config for agent packaging
- name: Extract client config
ansible.builtin.shell: |
{{ velociraptor_binary }} \
--config {{ velociraptor_config_dir }}/server.config.yaml \
config client > {{ velociraptor_config_dir }}/client.config.yaml
args:
creates: "{{ velociraptor_config_dir }}/client.config.yaml"

# Download Windows MSI for repack
- name: Download Windows MSI
ansible.builtin.get_url:
url: "{{ velociraptor_windows_msi_url }}"
dest: "{{ velociraptor_install_dir }}/velociraptor-windows-amd64.msi"
when: not ansible_facts.services['velociraptor.service'] is defined

# Repack the MSI with the embedded client config
- name: Repack Windows agent MSI with client config
ansible.builtin.shell: |
{{ velociraptor_binary }} config repack \
--exe {{ velociraptor_install_dir }}/velociraptor-windows-amd64.msi \
{{ velociraptor_config_dir }}/client.config.yaml \
{{ velociraptor_install_dir }}/velociraptor-agent.msi
args:
creates: "{{ velociraptor_install_dir }}/velociraptor-agent.msi"

# Add admin user
- name: Add Velociraptor admin user
ansible.builtin.shell: |
echo "{{ velociraptor_admin_password }}" | \
{{ velociraptor_binary }} \
--config {{ velociraptor_config_dir }}/server.config.yaml \
user add {{ velociraptor_admin_user }} --role=administrator
register: user_add
failed_when: user_add.rc != 0 and 'already exists' not in user_add.stderr
changed_when: "'already exists' not in user_add.stderr"

# Create systemd service
- name: Install Velociraptor systemd service
ansible.builtin.copy:
dest: /etc/systemd/system/velociraptor.service
content: |
[Unit]
Description=Velociraptor DFIR Platform
After=network.target

[Service]
Type=simple
ExecStart={{ velociraptor_binary }} --config {{ velociraptor_config_dir }}/server.config.yaml frontend -v
Restart=on-failure
RestartSec=10
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
owner: root
group: root
mode: '0644'

- name: Enable and start Velociraptor service
ansible.builtin.systemd:
name: velociraptor
state: started
enabled: yes
daemon_reload: yes

- name: Display Velociraptor access info
ansible.builtin.debug:
msg:
- "Velociraptor GUI : https://{{ ansible_host }}:{{ velociraptor_gui_port }}"
- "Username : {{ velociraptor_admin_user }}"
- "Password : {{ velociraptor_admin_password }}"
- "Agent MSI : {{ velociraptor_install_dir }}/velociraptor-agent.msi"
Loading