detection-rules icon indicating copy to clipboard operation
detection-rules copied to clipboard

[Rule Tuning] Web Server Potential Spike in Error Response Codes

Open vx-sec opened this issue 2 months ago • 2 comments

Link to Rule

https://github.com/elastic/detection-rules/blob/main/rules/cross-platform/reconnaissance_web_server_unusual_spike_in_error_response_codes.toml

Rule Tuning Type

Data Quality - Ensuring integrity and quality of data used by detection rules.

Description

The rule mentioned above, as well as these rules below fail for Nginx integration (possibly other's too that use uri_parts in ingest pipeline to dissect the url), with the following error.

verification_exception
	Root causes:
		verification_exception: Found 1 problem
line 3:34: Unknown column [url.full]

Issue is that url.full is not a field that gets defined and parsed by uri_parts ingest processor and so the is not null checks on it fail.

Web Server Potential Command Injection Request Web Server Suspicious User Agent Requests Web Server Discovery or Fuzzing Activity

Example Data

This is what the nginx integration for example indexes.

{
    "@timestamp": "2022-12-09T10:39:23.000Z",
    "_tmp": {},
    "agent": {
        "ephemeral_id": "<redacted>",
        "id": "<redacted>",
        "name": "docker-fleet-agent",
        "type": "filebeat",
        "version": "8.5.0"
    },
    "data_stream": {
        "dataset": "nginx.access",
        "namespace": "ep",
        "type": "logs"
    },
    "ecs": {
        "version": "8.11.0"
    },
    "elastic_agent": {
        "id": "<redacted>",
        "snapshot": false,
        "version": "8.5.0"
    },
    "event": {
        "agent_id_status": "verified",
        "category": [
            "web"
        ],
        "created": "2022-12-09T10:39:38.896Z",
        "dataset": "nginx.access",
        "ingested": "2022-12-09T10:39:40Z",
        "kind": "event",
        "outcome": "success",
        "timezone": "+00:00",
        "type": [
            "access"
        ]
    },
    "host": {
        "architecture": "x86_64",
        "containerized": false,
        "hostname": "docker-fleet-agent",
        "id": "<redacted>",
        "ip": [
            "<redacted>"
        ],
        "mac": [
            "02-42-AC-12-00-07"
        ],
        "name": "docker-fleet-agent",
        "os": {
            "codename": "focal",
            "family": "debian",
            "kernel": "5.15.49-linuxkit",
            "name": "Ubuntu",
            "platform": "ubuntu",
            "type": "linux",
            "version": "20.04.5 LTS (Focal Fossa)"
        }
    },
    "http": {
        "request": {
            "method": "GET"
        },
        "response": {
            "body": {
                "bytes": 97
            },
            "status_code": 200
        },
        "version": "1.1"
    },
    "input": {
        "type": "log"
    },
    "log": {
        "file": {
            "path": "/tmp/service_logs/access.log"
        },
        "offset": 0
    },
    "nginx": {
        "access": {
            "remote_ip_list": [
                "127.0.0.1"
            ]
        }
    },
    "related": {
        "ip": [
            "127.0.0.1"
        ]
    },
    "source": {
        "address": "127.0.0.1",
        "ip": "127.0.0.1"
    },
    "tags": [
        "nginx-access"
    ],
    "url": {
        "original": "/server-status",
        "path": "/server-status"
    },
    "user_agent": {
        "device": {
            "name": "Other"
        },
        "name": "curl",
        "original": "curl/7.64.0",
        "version": "7.64.0"
    }
}

vx-sec avatar Nov 28 '25 10:11 vx-sec

Hi @vx-sec thank you for bringing this to our attention! It indeed looks like the issue is related to not having data from both access logs and network packet capture logs available, thus the is not null check on a non-existent field fails. I will see what the best solution is for these rules. I will get back to you with the outcome + tuning PR once it's created.

Aegrah avatar Nov 28 '25 16:11 Aegrah

@vx-sec, again, thank you for bringing this to our attention. Elasticsearch ES|QL validates all referenced fields against the combined mappings of every index in a multi-index FROM clause. Because some indices do not define url.full, any ES|QL expression that references this field (even inside CASE, COALESCE, or FORK) fails at compile time with Unknown column, making it impossible to implement query logic that conditionally selects between fields from two different integration categories in a single query. As a result, the query cannot be fixed without schema changes or separate rules, and we will explore raising this limitation with the ES|QL development team to determine whether it can be improved.

For now, I added a tuning PR to fully remove NPC compatibility to these web rules, which should fix the issue for now. We will revisit to see if we can make a change in the future to be able to combine the different integration categories.

Tuning PR:

  • [ ] https://github.com/elastic/detection-rules/pull/5384

Feel free to close the issue if this helps! You can already grab the updated rules from the PRs if you want.

Aegrah avatar Dec 01 '25 13:12 Aegrah