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
112 changes: 112 additions & 0 deletions integrations/caddy_integration_wazuh_v5.0beta/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Caddy-Wazuh Integration

## Table of Contents

* [Introduction](#introduction)
* [Prerequisites](#prerequisites)
* [Installation and Configuration](#installation-and-configuration)
* [Installing Caddy](#installing-caddy)
* [Initial Caddy Configuration](#initial-caddy-configuration)
* [Installing Wazuh (if applicable)](#installing-wazuh-if-applicable)
* [Initial Wazuh Configuration (if applicable)](#initial-wazuh-configuration-if-applicable)
* [Using the Integration Files](#using-the-integration-files)
* [Integration Steps](#integration-steps)
* [Integration Testing](#integration-testing)
* [Sources](#sources)

---

### Introduction

Caddy (caddyserver.com) is a modern open source web server with automatic HTTPS. It writes structured JSON access logs by default with no extra configuration needed, and there was no coverage for it in the Wazuh ruleset. This integration adds a decoder and a set of Sigma format detection rules for Wazuh 5.0, parsing Caddy's JSON access logs into ECS fields and catching common web attacks and recon activity, things like path traversal, SQL injection, XSS, Log4Shell, credential file access, and dangerous file uploads.

A parallel version of this integration for Wazuh 4.x (XML decoder and rules) is available in a separate branch/PR of this repository.

---

### Prerequisites

* Wazuh manager 5.0 beta2 or later, the ruleset format described here is specific to the new engine introduced in 5.0
* Caddy web server configured to write JSON access logs

---

### Installation and Configuration

#### Installing Caddy

Follow the official installation guide at https://caddyserver.com/docs/install for your platform.

#### Initial Caddy Configuration

Caddy needs to be told to write JSON access logs. Add this to your Caddyfile:

```
{
log {
format json
}
}
```

A sample log line looks like this:

```json
{"level":"info","ts":1700000000.0,"logger":"http.log.access","msg":"handled request","request":{"remote_ip":"10.0.0.1","remote_port":"12345","proto":"HTTP/1.1","method":"GET","host":"example.com","uri":"/","headers":{"User-Agent":["Mozilla/5.0"]}},"status":200,"size":1024,"duration":0.002}
```

#### Installing Wazuh (if applicable)

A standard Wazuh 5.0 beta installation is assumed. See the beta documentation at https://documentation.wazuh.com/5.0-beta/getting-started/index.html.

#### Initial Wazuh Configuration (if applicable)

No special manager configuration is needed beyond registering the decoder and rules described below and pointing the agent at the Caddy log file.

#### Using the Integration Files

In 5.0, decoders and rules are authored as YAML assets rather than XML, and rules follow the Sigma rule specification (https://github.com/SigmaHQ/sigma-specification). The easiest way to add this integration is through the dashboard's Security Analytics section, under Normalization and Detection, both have a Create option with a YAML editor.

* `ruleset/decoders/decoder_caddy-access_0.yml`, paste into Normalization, Decoders, Create, YAML Editor. Set its parent integration to a new or existing `caddy` integration.
* `ruleset/rules/*.yml`, each file is one rule, paste into Detection, Rules, Create, YAML Editor, same `caddy` integration.

Once added, content should be promoted from the Draft space through Test and into Custom or Standard depending on your review process, so it is picked up by live detection.

---

### Integration Steps

Once Caddy is writing JSON logs and the agent is forwarding them, every request Caddy handles becomes a log event. The decoder recognizes the `http.log.access` logger field and maps the request into ECS fields (`source.ip`, `url.original`, `http.request.method`, `http.response.status_code`, `user_agent.original`, and so on). The rules then match against those ECS fields and raise an alert when a known attack or recon pattern is found.

A request like `GET /../../../../etc/passwd` gets caught by the path traversal rule, and a request containing `${jndi:ldap://...}` gets caught by the Log4Shell rule.

---

### Integration Testing

This was verified using the Wazuh 5.0 beta2 dashboard's Log test tool (Security Analytics, Log test). Custom content was authored in the Draft space and promoted to the Test space before running it against sample logs, since Draft content alone is not evaluated by Log test.

Running the path traversal sample log (`/../../../../etc/passwd`) through Log test produces a decoded event with all ECS fields populated correctly. The Detection tab reports 25 rules evaluated with 2 matches on that single log line, the path traversal rule (996003) and the suspicious filename rule (996020), both firing correctly against the same request.

The other 23 rules in `ruleset/rules/` were built the same way and follow the same pattern. 19 target `url.original`, 2 target `user_agent.original` (996010, 996028), and 2 target `http.request.method` (996011, 996027), each with a regex modifier. Across all 25 rules, 21 target `url.original` in total.

<img width="1716" height="687" alt="image" src="https://github.com/user-attachments/assets/6d090837-a63e-4877-9330-a871d861e6dd" />
<img width="1917" height="761" alt="image" src="https://github.com/user-attachments/assets/7a51a480-6e39-4b08-8115-ff1a33db66b0" />

Three rules from the original Wazuh 4.x ruleset (repeated auth endpoint hits, repeated sensitive path probes, repeated path traversal attempts) rely on frequency and correlation logic across multiple events rather than a single log line, and are not included here as Sigma rules. That kind of correlation looks like it belongs in the dashboard's Detectors feature instead, which is still to be worked out and would follow in a later update.

---

### Sources

* Caddy JSON access log format, https://caddyserver.com/docs/logging
* Sigma rule specification, https://github.com/SigmaHQ/sigma-specification
* MITRE ATT&CK, https://attack.mitre.org/

## Provenance and Maintenance

* Original source, ported from a Wazuh 4.x XML decoder and ruleset I wrote for the same Caddy log format, adapted to the 5.0 YAML and Sigma format.
* Adapted by, Anmol Vats (GitHub: NucleiAv)
* Tested versions, Wazuh 5.0.0 beta2, current Caddy JSON access log format as documented at caddyserver.com/docs/logging
* Maintainer, Anmol Vats (GitHub: NucleiAv)
* Support boundary, community maintained, provided as is, format may need updates as the 5.0 engine moves past beta
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: decoder/caddy-access/0
enabled: true
metadata:
title: Caddy Access Log Decoder
description: Decodes Caddy web server structured JSON access logs
author: Anmol Vats
references: []
documentation: 'https://caddyserver.com/docs/json/apps/http/servers/logs/'
supports: []

parents:
- decoder/core-wazuh-message/0

check: string_equal($_tmp_json.logger, "http.log.access")

normalize:
- map:
- event.kind: event
- event.category: array_append(web)
- event.type: array_append(access)
- event.action: http-request
- event.dataset: caddy-access
- service.type: caddy
- source.ip: $_tmp_json.request.remote_ip
- source.address: $_tmp_json.request.remote_ip
- http.request.method: $_tmp_json.request.method
- url.original: $_tmp_json.request.uri
- destination.domain: $_tmp_json.request.host
- http.response.status_code: $_tmp_json.status
- http.response.body.bytes: $_tmp_json.size
- network.protocol: http
- http.version: $_tmp_json.request.proto
- user_agent.original: $_tmp_json.request.headers.User-Agent.0
- check: int_less($http.response.status_code, 400)
map:
- event.outcome: success
- check: int_greater_or_equal($http.response.status_code, 400)
map:
- event.outcome: failure
- map:
- _tmp_json: delete()
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
id: '78c290a5-bc22-4691-9661-81db77125f54'
logsource:
product: caddy
tags:
- attack.discovery
- attack.t1083
falsepositives:
- Legitimate use of ../ in query parameters by specific applications
level: high
status: experimental
enabled: true
metadata:
title: Caddy Path Traversal Attempt
author: Anmol Vats
description: Detects path traversal attempts in Caddy access logs via ../ or its URL encoded variants in the request URI.
references:
- 'https://github.com/wazuh/wazuh/issues/37033'
documentation: ''
supports:
- '5.0'
detection:
selection:
url.original|re: '(?i)(\.\./|\.\.\\|%2e%2e|%252e%252e)'
condition: selection
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
id: '7f3a1c2e-4b6d-4e91-9a2f-1d8c6b3e0a17'
logsource:
product: caddy
tags:
- attack.initial-access
- attack.t1190
falsepositives:
- Legitimate content containing SQL-like keywords in search or content fields
level: high
status: experimental
enabled: true
metadata:
title: Caddy SQL Injection Attempt
author: Anmol Vats
description: Detects SQL injection patterns (UNION SELECT, OR 1=1, etc.) in the request URI.
references:
- 'https://github.com/wazuh/wazuh/issues/37033'
documentation: ''
supports:
- '5.0'
detection:
selection:
url.original|re: '(?i)(union.+select|select.+from|insert.+into|drop.+table|(%27|'')(\s|%20)*(or)(\s|%20)+|(\s|%20)(or)(\s|%20)+1(\s|%20)*(%3D|=)(\s|%20)*1)'
condition: selection
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
id: '2c9e4f1a-8b3d-4c72-b1e6-3f7a9d2c5e04'
logsource:
product: caddy
tags:
- attack.reconnaissance
- attack.t1595
falsepositives:
- Vulnerability scanning performed by authorized security teams
level: high
status: experimental
enabled: true
metadata:
title: Caddy Sensitive Path Probe
author: Anmol Vats
description: Detects probing of common sensitive paths such as .env, .git, wp-admin, phpmyadmin.
references:
- 'https://github.com/wazuh/wazuh/issues/37033'
documentation: ''
supports:
- '5.0'
detection:
selection:
url.original|re: '(?i)(\/\.env$|\/\.git|\/wp-admin|\/phpmyadmin|\/admin\.php|\/config\.php|\/backup)'
condition: selection
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
id: 'e6d2a4f8-1c3b-4a95-8e7d-2b6f9a1c3d58'
logsource:
product: caddy
tags:
- attack.execution
- attack.t1059.007
falsepositives:
- Legitimate pages containing script-related keywords in content
level: high
status: experimental
enabled: true
metadata:
title: Caddy XSS Attempt in URI
author: Anmol Vats
description: Detects cross-site scripting payloads in the request URI.
references:
- 'https://github.com/wazuh/wazuh/issues/37033'
documentation: ''
supports:
- '5.0'
detection:
selection:
url.original|re: '(?i)(%3Cscript|<script|javascript:|onerror=|onload=|alert\(|document\.cookie|eval\()'
condition: selection
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
id: '9a3f2e1d-6c4b-4d87-a1f3-5e8b2c9a6d17'
logsource:
product: caddy
tags:
- attack.execution
- attack.t1059
falsepositives:
- Rare, verify against legitimate application behavior
level: high
status: experimental
enabled: true
metadata:
title: Caddy Command Injection Attempt
author: Anmol Vats
description: Detects shell metacharacters combined with common OS commands in the request URI.
references:
- 'https://github.com/wazuh/wazuh/issues/37033'
documentation: ''
supports:
- '5.0'
detection:
selection:
url.original|re: '(?i)(%7C|%60|\||\`).*?(ls|id|whoami|cat\s|wget\s|curl\s|bash|/bin/sh|cmd\.exe)'
condition: selection
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
id: '4b7d1e9c-3a2f-4b65-9d8e-1c4a7f2e6b30'
logsource:
product: caddy
tags:
- attack.reconnaissance
- attack.t1595
falsepositives:
- Authorized penetration testing or vulnerability scanning
level: high
status: experimental
enabled: true
metadata:
title: Caddy Known Attack/Scanner Tool Detected
author: Anmol Vats
description: Detects User-Agent strings belonging to common attack/scanning tools.
references:
- 'https://github.com/wazuh/wazuh/issues/37033'
documentation: ''
supports:
- '5.0'
detection:
selection:
user_agent.original|re: '(?i)(sqlmap|nikto|nmap|masscan|nuclei|gobuster|dirbuster|wfuzz|acunetix|nessus|openvas|zgrab|whatweb)'
condition: selection
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
id: 'c1a9e3f2-7b5d-4c48-a2e6-9d3f1b8c4a56'
logsource:
product: caddy
tags:
- attack.initial-access
- attack.t1190
falsepositives:
- Rare, TRACE/TRACK are not commonly used legitimately
level: medium
status: experimental
enabled: true
metadata:
title: Caddy HTTP TRACE/TRACK Method
author: Anmol Vats
description: Detects HTTP TRACE or TRACK methods, potentially indicating a cross-site tracing attempt.
references:
- 'https://github.com/wazuh/wazuh/issues/37033'
documentation: ''
supports:
- '5.0'
detection:
selection:
http.request.method|re: '^(TRACE|TRACK)$'
condition: selection
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
id: '3e8f2a1c-9d4b-4e76-b1a3-6c2e9f5d8b04'
logsource:
product: caddy
tags:
- attack.initial-access
- attack.t1190
falsepositives:
- Very rare, this pattern is almost always malicious
level: critical
status: experimental
enabled: true
metadata:
title: Caddy Log4Shell JNDI Injection Attempt
author: Anmol Vats
description: Detects JNDI lookup patterns associated with Log4Shell (CVE-2021-44228) exploitation attempts.
references:
- 'https://github.com/wazuh/wazuh/issues/37033'
documentation: ''
supports:
- '5.0'
detection:
selection:
url.original|re: '(?i)(\$\{jndi:|%24%7Bjndi%3A|%24%7Bjndi:)'
condition: selection
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
id: '8d4c2f1e-6a3b-4d59-9e7a-2f1c8b4d3a67'
logsource:
product: caddy
tags:
- attack.discovery
- attack.t1083
falsepositives:
- Vulnerability scanning by authorized security teams
level: high
status: experimental
enabled: true
metadata:
title: Caddy Sensitive File Access Attempt
author: Anmol Vats
description: Detects access attempts to sensitive files such as xmlrpc.php, .htaccess, wp-config.php, /etc/shadow.
references:
- 'https://github.com/wazuh/wazuh/issues/37033'
documentation: ''
supports:
- '5.0'
detection:
selection:
url.original|re: '(?i)(\/xmlrpc\.php|\/\.htaccess|\/\.htpasswd|\/wp-config\.php|\/config\.php|\/backup|\/dump\.sql|\/proc\/self|\/etc\/shadow)'
condition: selection
Loading