external/anthropic-cybersecurity-skills/skills/detecting-network-anomalies-with-zeek/SKILL.md
Deploys and configures Zeek (formerly Bro) network security monitor to passively analyze network traffic, generate structured logs, detect anomalous behavior, and create custom detection scripts for threat hunting and incident response.
npx skillsauth add seikaikyo/dash-skills detecting-network-anomalies-with-zeekInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Do not use as a replacement for inline IDS/IPS that can actively block traffic, for monitoring encrypted payloads without TLS inspection, or on endpoints where host-based agents are more appropriate.
zeek --version)# Install Zeek on Ubuntu/Debian
sudo apt install -y zeek
# Or install from source for latest version
git clone --recursive https://github.com/zeek/zeek
cd zeek && ./configure --prefix=/opt/zeek && make -j$(nproc) && sudo make install
export PATH=/opt/zeek/bin:$PATH
# Configure the monitoring interface
sudo vi /opt/zeek/etc/node.cfg
# /opt/zeek/etc/node.cfg
[zeek]
type=standalone
host=localhost
interface=eth1
# Configure local network definitions
sudo vi /opt/zeek/etc/networks.cfg
# /opt/zeek/etc/networks.cfg
10.0.0.0/8 Internal
172.16.0.0/12 Internal
192.168.0.0/16 Internal
# Disable NIC offloading for accurate packet capture
sudo ethtool -K eth1 rx off tx off gro off lro off tso off gso off
# Deploy Zeek
sudo zeekctl deploy
# Verify Zeek is running
sudo zeekctl status
# Zeek generates structured log files in /opt/zeek/logs/current/
ls /opt/zeek/logs/current/
# Key log files:
# conn.log - All network connections (TCP, UDP, ICMP)
# dns.log - DNS queries and responses
# http.log - HTTP requests and responses
# ssl.log - SSL/TLS handshake details
# files.log - File transfers observed on the network
# notice.log - Alerts from Zeek detection scripts
# weird.log - Protocol anomalies and errors
# x509.log - X.509 certificate details
# smtp.log - SMTP email transactions
# ssh.log - SSH connection details
# View connection log with zeek-cut for column selection
cat /opt/zeek/logs/current/conn.log | zeek-cut ts id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes
# View DNS log
cat /opt/zeek/logs/current/dns.log | zeek-cut ts id.orig_h query qtype_name answers
# View HTTP log
cat /opt/zeek/logs/current/http.log | zeek-cut ts id.orig_h host uri method status_code user_agent
# Create a custom detection script directory
sudo mkdir -p /opt/zeek/share/zeek/site/custom-detections
Create a script for detecting DNS tunneling:
# /opt/zeek/share/zeek/site/custom-detections/dns-tunneling.zeek
@load base/frameworks/notice
module DNSTunneling;
export {
redef enum Notice::Type += {
DNS_Tunneling_Detected,
DNS_Long_Query
};
# Threshold: number of unique queries per source in time window
const query_threshold: count = 200 &redef;
const time_window: interval = 5min &redef;
const max_query_length: count = 50 &redef;
}
# Track query counts per source IP
global dns_query_counts: table[addr] of count &create_expire=5min &default=0;
event dns_request(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count)
{
local src = c$id$orig_h;
# Check for unusually long domain queries (base64-encoded data)
if ( |query| > max_query_length )
{
NOTICE([
$note=DNS_Long_Query,
$msg=fmt("Unusually long DNS query from %s: %s (%d chars)", src, query, |query|),
$src=src,
$identifier=cat(src, query)
]);
}
# Track query volume per source
dns_query_counts[src] += 1;
if ( dns_query_counts[src] == query_threshold )
{
NOTICE([
$note=DNS_Tunneling_Detected,
$msg=fmt("Possible DNS tunneling: %s sent %d queries in %s", src, query_threshold, time_window),
$src=src,
$identifier=cat(src)
]);
}
}
Create a script for detecting beaconing:
# /opt/zeek/share/zeek/site/custom-detections/beacon-detection.zeek
@load base/frameworks/notice
@load base/frameworks/sumstats
module BeaconDetection;
export {
redef enum Notice::Type += {
Possible_Beaconing
};
const beacon_threshold: count = 50 &redef;
const observation_window: interval = 1hr &redef;
}
event zeek_init()
{
local r1 = SumStats::Reducer(
$stream="beacon.connections",
$apply=set(SumStats::SUM)
);
SumStats::create([
$name="detect-beaconing",
$epoch=observation_window,
$reducers=set(r1),
$threshold_val(key: SumStats::Key, result: SumStats::Result) = {
return result["beacon.connections"]$sum;
},
$threshold=beacon_threshold + 0.0,
$threshold_crossed(key: SumStats::Key, result: SumStats::Result) = {
NOTICE([
$note=Possible_Beaconing,
$msg=fmt("Possible beaconing: %s made %d connections in %s",
key$str, result["beacon.connections"]$sum, observation_window),
$identifier=key$str
]);
}
]);
}
event connection_state_remove(c: connection)
{
if ( c$id$resp_h !in Site::local_nets )
{
local key = fmt("%s->%s:%d", c$id$orig_h, c$id$resp_h, c$id$resp_p);
SumStats::observe("beacon.connections", [$str=key], [$num=1]);
}
}
# Add custom scripts to local.zeek
sudo tee -a /opt/zeek/share/zeek/site/local.zeek << 'EOF'
# Custom detection scripts
@load custom-detections/dns-tunneling.zeek
@load custom-detections/beacon-detection.zeek
# Enable additional protocol analyzers
@load protocols/ftp/software
@load protocols/http/software
@load protocols/smtp/software
@load protocols/ssh/detect-bruteforcing
@load protocols/ssl/validate-certs
@load protocols/ssl/log-hostcerts-only
@load protocols/dns/detect-external-names
# Enable file extraction
@load frameworks/files/extract-all-files
# Enable Intel framework for threat intelligence
@load frameworks/intel/seen
@load frameworks/intel/do_notice
EOF
# Reload Zeek configuration
sudo zeekctl deploy
# Verify scripts loaded without errors
sudo zeekctl diag
# Find long-duration connections (possible C2)
cat /opt/zeek/logs/current/conn.log | zeek-cut ts id.orig_h id.resp_h id.resp_p duration | \
awk '$5 > 3600 {print $0}' | sort -t$'\t' -k5 -rn | head -20
# Find connections with high data transfer volumes
cat /opt/zeek/logs/current/conn.log | zeek-cut ts id.orig_h id.resp_h orig_bytes resp_bytes | \
awk '$4 > 100000000 || $5 > 100000000 {print $0}'
# Identify rare user agents (potential malware)
cat /opt/zeek/logs/current/http.log | zeek-cut user_agent | sort | uniq -c | sort -n | head -20
# Find self-signed or expired certificates
cat /opt/zeek/logs/current/ssl.log | zeek-cut ts id.orig_h id.resp_h server_name validation_status | \
grep -v "ok"
# Detect DNS queries to newly registered domains (DGA patterns)
cat /opt/zeek/logs/current/dns.log | zeek-cut ts id.orig_h query | \
awk -F'\t' '{n=split($3,a,"."); if(length(a[n-1]) > 10) print $0}'
# Find SSH brute force attempts
cat /opt/zeek/logs/current/ssh.log | zeek-cut ts id.orig_h id.resp_h auth_success | \
grep "F" | awk '{print $2}' | sort | uniq -c | sort -rn | head -10
# Identify unusual port usage
cat /opt/zeek/logs/current/conn.log | zeek-cut id.resp_p proto service | \
sort | uniq -c | sort -rn | head -50
# Configure JSON log output for SIEM ingestion
sudo tee /opt/zeek/share/zeek/site/json-logs.zeek << 'EOF'
@load policy/tuning/json-logs.zeek
redef LogAscii::use_json = T;
EOF
# Forward logs to Elastic via Filebeat
# /etc/filebeat/filebeat.yml
sudo tee /etc/filebeat/filebeat.yml << 'EOF'
filebeat.inputs:
- type: log
enabled: true
paths:
- /opt/zeek/logs/current/*.log
json.keys_under_root: true
json.add_error_key: true
fields:
source: zeek
fields_under_root: true
output.elasticsearch:
hosts: ["https://elastic-siem:9200"]
index: "zeek-%{+yyyy.MM.dd}"
username: "elastic"
password: "${ES_PASSWORD}"
EOF
sudo systemctl enable --now filebeat
# Set up log rotation
sudo tee /etc/cron.d/zeek-logrotate << 'EOF'
0 0 * * * root /opt/zeek/bin/zeekctl cron
EOF
# Monitor Zeek health
sudo zeekctl status
sudo zeekctl netstats
| Term | Definition | |------|------------| | Network Security Monitor | Passive analysis tool that observes network traffic and generates structured metadata logs without altering or blocking traffic flow | | Zeek Script | Event-driven scripts written in Zeek's domain-specific language that process network events and generate notices, logs, and metrics | | Connection Log (conn.log) | Core Zeek log recording every observed connection with source/destination IPs, ports, protocol, duration, and byte counts | | Notice Framework | Zeek subsystem for generating alerts when detection scripts identify suspicious activity, outputting to notice.log | | SumStats Framework | Statistical analysis framework in Zeek for tracking metrics over time windows, enabling threshold-based detection of anomalies | | Intel Framework | Zeek module for matching observed network indicators against threat intelligence feeds and generating alerts on matches |
Context: A threat intelligence report indicates that a specific threat actor uses HTTPS beaconing with 60-second intervals to compromised hosts. The SOC team needs to analyze Zeek logs to identify any hosts exhibiting this pattern across the enterprise network carrying 2 Gbps of traffic.
Approach:
Pitfalls:
## Zeek Network Anomaly Detection Report
**Sensor**: zeek-sensor-01 (10.10.1.250)
**Monitoring Interface**: eth1 (span port from Core-SW1)
**Analysis Period**: 2024-03-15 00:00 to 2024-03-16 00:00 UTC
**Total Connections Logged**: 2,847,392
### Anomalies Detected
| Notice Type | Source | Destination | Details |
|-------------|--------|-------------|---------|
| DNS_Tunneling_Detected | 10.10.3.45 | 8.8.8.8 | 847 queries to suspect-domain.xyz in 5 min |
| Possible_Beaconing | 10.10.5.12 | 203.0.113.50:443 | 62 connections with 59.8s avg interval |
| SSL::Invalid_Server_Cert | 10.10.8.22 | 198.51.100.33:443 | Self-signed cert, CN=localhost |
| SSH::Password_Guessing | 45.33.32.156 | 10.10.20.11:22 | 487 failed attempts in 30 min |
### Recommendations
1. Isolate 10.10.3.45 and investigate for DNS tunneling malware
2. Block 203.0.113.50 at firewall and forensically image 10.10.5.12
3. Investigate self-signed TLS certificate on 198.51.100.33
4. Block 45.33.32.156 and enforce SSH key-only authentication
development
拋棄式 HTML mockup 比稿:產出 2 到 3 個設計立場不同的變體(密度 / 版式 / 強調軸,不是換色),各附取捨說明,最後給有立場的對比結論。適用:「畫個草圖」「比較 A 版 B 版」「先看方向再做」「給我看幾種做法」。要 production 元件或設計已定案時不適用。
tools
需求不明時的意圖萃取訪談:一次一題、每題附上自己的猜測、聽出「真正想要 vs 覺得應該要」,直到能預測使用者反應(約 95% 信心)才動工。適用:需求缺少對象 / 動機 / 成功標準 / 約束,或使用者點名「訪談我」「先確認一下」「我們確定嗎」。明確自足的指示、純資訊查詢、機械性操作不適用。
development
對非平凡決策啟動新鮮 context 對抗審查(找碴不背書),在修正還便宜的時候抓出錯誤方向。適用:高風險改動(production、資安敏感邏輯、不可逆操作)、不熟的程式碼、要宣稱「這樣是安全的 / 可行的」之前。機械性操作與一行修改不適用。
testing
Reference for writing and editing agent skills well — the vocabulary and principles that make a skill predictable. Consult when authoring, reviewing, or pruning a SKILL.md.