Author: Mounica S Goodala
Date: 06 August 2026
🎯 Introduction
Security Operations Centers rely on SIEM systems to correlate logs and detect malicious activity. This tutorial walks through building three custom correlation rules in the ELK Stack (Elasticsearch + Kibana) to detect:
- Credential Stuffing (T1110.004) — Attackers using stolen credentials to target multiple accounts.
- DNS Tunneling (T1071.004) — Attackers abusing DNS to exfiltrate data.
- PowerShell Exploitation (T1059.001) — Attackers abusing PowerShell to execute malicious scripts.
The goal is to build a complete detection pipeline—from log injection to alert generation—using open-source tools.
🛠️ 1. Lab Environment Setup
The ELK Stack was deployed locally using Elastic's official one-liner, which spins up two Docker containers:
-
Elasticsearch on port
9200— the search and indexing engine. -
Kibana on port
5601— the visual interface for rule creation and alert monitoring.
curl -fsSL <https://elastic.co/start-local> | sh
Authentication is enabled by default. The credentials can be retrieved from the generated .env file:
cat elastic-start-local/.env | grep ELASTIC_PASSWORD
-
Username:
elastic -
Password: (from
.env)
This setup provides a lightweight, reproducible SIEM lab suitable for detection engineering.
📁 2. Data Views in Kibana
Before writing any rules, Data Views (index patterns) were created in Kibana to make indices searchable. Navigate to Stack Management → Data Views and create the following:
-
test-logs-all→ patternlogs-test* -
logs-dns→ patternlogs-dns* -
logs-powershell→ patternlogs-powershell*
All three use @timestamp as the timestamp field.
This step ensures that logs injected into Elasticsearch are discoverable in Kibana's Discover interface.
💉 3. Attack Telemetry Injection
To validate the rules, realistic attack telemetry was generated and injected into Elasticsearch using two methods:
-
Python scripts (with the
requestslibrary) for structured, repeatable injections. - CURL commands for quick, ad-hoc injections directly from the terminal.
All scripts were developed in Visual Studio Code and executed via the integrated terminal.
Here's a sample REST API call used for injection:
curl -X POST "<http://localhost:9200/logs-test/_doc>" \
-u elastic:YOUR_PASSWORD \
-d '{"@timestamp":"...", "source.ip":"203.0.113.45", ...}'
This approach provides full control over the telemetry data, enabling precise validation of detection logic.
🎯 4. Credential Stuffing (T1110.004)
What it is: Credential stuffing occurs when attackers use username/password pairs from data breaches and "spray" them across multiple accounts. The key signature is a single source IP targeting many distinct user accounts, typically with only 1–2 attempts per account.
How it was tested: A Python script injected 15 failed login attempts to 15 distinct users (alice, bob, ... oscar) from a single IP (203.0.113.45). Each injection received a "result":"created" response.
The detection logic: An ES|QL rule aggregates failed authentication attempts by source IP and counts the distinct target usernames using count_distinct(). If an IP targets more than 10 unique users, an alert is generated.
from logs-test*
| where event.category == "authentication" and event.type == "failure"
| eval attacker_ip = source.ip
| stats
targeted_accounts = count_distinct(user.name),
total_attempts = count(*),
example_users = values(user.name)
by attacker_ip
| where targeted_accounts > 10
Result: The rule triggered with targeted_accounts: 15 from IP 203.0.113.45, confirming successful detection of credential stuffing behavior.
🌐 5. DNS Tunneling (T1071.004)
What it is: DNS tunneling exploits the DNS protocol—which is rarely blocked by firewalls—to exfiltrate data or establish C2 channels. Attackers generate a high volume of queries to a single domain with abnormally long subdomains containing encoded payload data.
How it was tested: A Bash loop injected 20 DNS queries, each with a random 120-character subdomain pointing to malicious-tunnel.com. Each CURL request returned a successful "result":"created" response.
The detection logic: An ES|QL rule calculates the character length of the queried domain and aggregates the total count per source IP. Queries exceeding 100 characters are flagged, and any IP generating more than 10 such queries triggers an alert.
from logs-dns*
| where dns.question.name is not null
| eval attacker_ip = source.ip
| eval query_length = length(dns.question.name)
| where query_length > 100
| stats
total_queries = count(*),
sample_domains = values(dns.question.name)
by attacker_ip
| where total_queries > 10
Result: The rule flagged total_queries: 20 from IP 203.0.113.45, validating the detection of DNS tunneling activity.
💻 6. PowerShell Exploitation (T1059.001)
What it is: PowerShell is a legitimate Windows administration tool frequently abused by attackers to execute malicious scripts, download payloads, and evade detection. Common obfuscation techniques include -EncodedCommand, its shorthand -e, and WebClient.DownloadFile.
How it was tested: Three separate CURL commands injected PowerShell process events with suspicious argument patterns:
- One with
EncodedCommand - One with shorthand
e - One invoking
WebClient.DownloadFile
Each injection returned "result":"created".
The detection logic: An EQL rule inspects the command-line arguments of newly started powershell.exe processes, specifically looking for strings indicative of abuse.
process where event.type == "start"
and process.name : "powershell.exe"
and (
process.command_line : "*EncodedCommand*" or
process.command_line : "*-e *" or
process.command_line : "*-ec *" or
process.command_line : "*WebClient*" or
process.command_line : "*DownloadFile*" or
process.command_line : "*Reflection.Assembly*"
)
Result: Three separate high-severity alerts were generated, confirming the rule's ability to catch varied obfuscation techniques.
🧠 7. Key Learnings
Choosing the Right Rule Language:
- ES|QL excels at statistical aggregation across large datasets—counting distinct users, calculating query lengths, and grouping events.
- EQL is superior for parsing discrete process events and matching specific command-line strings with sequence awareness.
Threshold Tuning:
-
targeted_accounts > 10proved effective for credential stuffing. - Thresholds that are too low generate false positives; thresholds too high risk missing attacks.
- Production environments require baselining to determine optimal thresholds.
Layered Detection:
- Combining authentication logs, DNS queries, and PowerShell telemetry provides comprehensive visibility.
- No single rule is sufficient; a layered approach transforms raw logs into actionable intelligence.
📊 8. Results
After executing all three rules via "Run now", the Alerts dashboard displayed:
- 3 alerts for Credential Stuffing — each confirming 15 distinct users targeted from a single IP.
- 1 alert for DNS Tunneling — flagging 20 queries with domains exceeding 100 characters.
-
3 alerts for PowerShell Exploitation — detecting encoded commands and
WebClientinvocations.
Total: 7 alerts across all three techniques, validating the detection logic.
🛠️ 9. Tools Summary
- Docker provided a containerized, reproducible environment.
- Elasticsearch & Kibana (v9.5.0) served as the core SIEM platform.
- Visual Studio Code was used for developing Python injection scripts.
-
Python +
requestsinjected structured attack telemetry. - CURL enabled quick, ad-hoc log injection.
🚀 10. Explore Further
- Expand detection coverage to additional MITRE ATT&CK techniques.
- Integrate threat intelligence for alert enrichment.
- Implement automated response playbooks.
- Deploy Elastic Agents for real endpoint telemetry.
📚 11. References
- MITRE ATT&CK T1110.004
- MITRE ATT&CK T1071.004
- MITRE ATT&CK T1059.001
- Elastic Security Docs
- Elastic Docker Deployment
💬 Discussion
What MITRE ATT&CK techniques have you built detection rules for? Share your experiences below.





Top comments (0)