IDS vs IPS — DETECTION vs PREVENTION
IDS, IPS, and Their Role in NGFW
OVERVIEWAn IDS (Intrusion Detection System) observes network traffic and generates alerts when suspicious patterns are found — it does not block. An IPS (Intrusion Prevention System) sits inline and can drop, reset, or redirect traffic in real time. Modern NGFWs incorporate IPS as a feature — the same engine that does conntrack and NAT also applies IPS rules inline.
IDS (Detection Only)
- Passive tap or SPAN port — not in traffic path
- No impact on network performance or availability
- Cannot block — only alert
- False positives: annoying but not disruptive
- Use: visibility and logging, SOC analytics
- Tools: Zeek (Bro), Suricata in IDS mode
IPS (Prevention Inline)
- Inline in traffic path — all packets traverse it
- Can block, reset connections, quarantine
- False positives = blocking legitimate traffic (critical)
- False negatives = missed attacks (also critical)
- Performance matters: adds latency if slow
- Tools: Snort 3, Suricata in IPS mode, NGFW built-in IPS
Detection Methods — Complementary Approaches
| Method | Detects | Misses | False Positive Rate |
|---|---|---|---|
| Signature-based | Known malware, known exploits, known C2 protocols | Zero-day, novel variants, obfuscated/encrypted threats | Low (if signatures well-maintained) |
| Anomaly-based | Novel attacks that deviate from baseline behaviour | Attacks that mimic normal traffic patterns | High (requires careful tuning) |
| Heuristic / behavioural | Patterns of suspicious behaviour: port scans, beacons, lateral movement | Slow/stealthy attackers that stay under thresholds | Medium |
| Threat intelligence (IoC) | Known bad IPs, domains, hashes, URLs | New IoCs not yet in feeds, fast-flux infrastructure | Very low (IoCs are highly specific) |
SNORT/SURICATA RULE SYNTAX
Rule Anatomy and Key Options
RULES/* Snort/Suricata rule structure */ /* action proto src_ip src_port direction dst_ip dst_port (options) */alert tcp HOME_NET 22 ( msg:“ET SCAN SSH Brute Force”; flow:established,to_server; threshold:type both,track by_src,count 5,seconds 60; sid:2001219; rev:7; classtype:attempted-admin; )
/* Rule header fields */ action: alert|drop|pass|reject|rejectsrc|rejectdst|rejectboth proto: tcp|udp|icmp|ip|http|dns|tls|smb|dcerpc direction: -> (one way) | <> (both directions) src/dst: IP/CIDR, negation with !, list [1.1.1.1, 2.2.2.2], variables: EXTERNAL_NET, SMTP_SERVERS
/* Critical options */
/* Content matching / content:“malware.exe”; / match literal bytes / content:“|48 65 6c 6c 6f|”; / hex bytes / content:“SELECT”;nocase; / case-insensitive / content:“UNION”; distance:0; within:10; / relative to last match / pcre:“/SELECT.{0,10}FROM/is”; / PCRE regex */
/* Flow control / flow:established,to_server; / only on established, client→server / flow:established,to_client; / server→client replies / flow:stateless; / match even on non-established */
/* HTTP-specific options (Suricata HTTP engine) / http.method; content:“POST”; / match HTTP method / http.uri; content:“/admin”; / match URI path / http.host; content:“evil.example”; / match Host header / http.user_agent; content:“sqlmap”; / match User-Agent / http.stat_code; content:“200”; / match status code / http.response_body; content:“error”; / match response body */
/* TLS options / tls.sni; content:“evil.onion”; / match SNI / tls.subject; content:“CN=Meterpreter”; / match cert subject / tls.issuerdn; content:“CN=evil-ca”; / match cert issuer / tls.fingerprint; content:“ab:cd:ef:…”; / match cert fingerprint / ja3_hash; content:“51c64c77e60f3980eea90869b68c58a8”; / JA3 / ja3s_hash; content:”…”; / JA3S */
/* Thresholds and suppression / threshold:type limit,track by_src,count 1,seconds 60; / Only alert once per source IP per 60s (suppress noisy alerts) / threshold:type both,track by_src,count 10,seconds 1; / Alert if >10 in 1s (rate-based detection: port scan, brute force) / threshold:type threshold,track by_src,count 5,seconds 10; / Alert every 5th occurrence per source per 10s */
/* Reference and classification / reference:url,attack.mitre.org/techniques/T1021/; classtype:attempted-user; / trojan-activity, attempted-recon, etc. / priority:1; / 1=high, 2=medium, 3=low / sid:2100001; / unique rule ID / rev:3; / revision number */
SURICATA — MULTI-THREADED IDS/IPS ENGINE
Suricata Architecture
ARCHITECTURE/* Suricata thread model */Receive threads (RX): Read packets from NIC (AF_PACKET, AF_XDP, DPDK, PCAP) Decode: Ethernet → IP → TCP/UDP → application headers Distribute to worker threads (via flow hash for ordering)
Worker threads (decode + detect): Each thread handles a subset of flows Per-flow state: conntrack + app-layer parsers + detect engine Hyperscan/AC for payload inspection Produces: alert events, flow records, file extracts
Output threads: Write alerts: EVE JSON, Unified2 (for Snort-compatible output) Write flow records: NetFlow-like summaries Write extracted files: malware samples, documents from HTTP/SMTP
/* Suricata packet flow */ Packet → RX Thread → Flow Hash → Worker Thread:
- IP defragmentation (reassemble fragments)
- Stream tracking (TCP segment reassembly)
- App-layer detection (HTTP, TLS, DNS, SMTP, SMB parsers)
- Rule detection (Hyperscan + keyword matching)
- Action (alert/drop/pass)
- Logging (EVE JSON)
/* Suricata AF_XDP mode (high performance) */ suricata: af-xdp: interface: eth0 threads: 4 xdp-mode: driver use-mmap: yes ring-size: 2048
/* Suricata IPS mode (inline with NFQUEUE or AF_PACKET) */
NFQUEUE mode: Netfilter sends packets to Suricata for verdict
iptables -A FORWARD -j NFQUEUE —queue-num 0
suricata: nfq: mode: accept fail-open: yes /* pass traffic if Suricata crashes */
AF_PACKET IPS mode (bypass when possible)
suricata: af-packet: - interface: eth0 cluster-id: 99 cluster-type: cluster_flow copy-mode: ips copy-iface: eth1 /* forward to eth1 if not dropped */
/* Suricata EVE JSON output — structured logging */ { “timestamp”: “2024-01-15T10:23:45.123456+0000”, “flow_id”: 123456789, “event_type”: “alert”, “src_ip”: “192.168.1.50”, “src_port”: 54321, “dest_ip”: “198.51.100.5”, “dest_port”: 443, “proto”: “TCP”, “alert”: { “action”: “blocked”, “gid”: 1, “signature_id”: 2019401, “rev”: 4, “signature”: “ET CNC Feodo Tracker Reported C2 in Use”, “category”: “A Network Trojan was Detected”, “severity”: 1 }, “tls”: { “sni”: “malicious.example.com”, “version”: “TLS 1.3”, “ja3”: { “hash”: “51c64c77e60f3980eea90869b68c58a8” } }, “app_proto”: “tls” }
ANOMALY DETECTION — STATISTICAL BASELINES AND DEVIATIONS
Network Anomaly Detection Techniques
ANOMALY DETECTION/* Anomaly detection: build a model of "normal" and alert on deviations *//* 1. Port scan detection / / Normal: one source contacts a few services / / Anomaly: one source contacts many distinct ports */
typedef struct { uint32_t src_ip; uint16_t ports_contacted[1024]; /* bitmap of dst_ports in last 60s */ uint32_t unique_ports; uint64_t window_start_ns; } portscan_tracker_t;
void portscan_update(portscan_tracker_t t, uint16_t dst_port, uint64_t now_ns) { / Reset window if expired / if (now_ns - t->window_start_ns > 60e9) { memset(t->ports_contacted, 0, sizeof(t->ports_contacted)); t->unique_ports = 0; t->window_start_ns = now_ns; } / Add this port to bitmap / uint16_t b = dst_port / 8, bi = dst_port % 8; if (!(t->ports_contacted[b] & (1 << bi))) { t->ports_contacted[b] |= (1 << bi); t->unique_ports++; } if (t->unique_ports > 100) / threshold */ alert(PORTSCAN, t->src_ip); }
/* 2. DDoS detection — per-destination traffic volume / / Track bytes/packets to each destination per second / / Alert when rate exceeds N × average (N=10 for 10x normal) */
/* 3. DNS anomaly — high query rate or long labels (tunnelling) / / Normal DNS: 10–100 queries/minute from a host / / DNS tunnelling: hundreds/sec; query labels contain base32/hex data */
typedef struct { uint32_t src_ip; uint32_t queries_in_window; uint64_t window_start_ns; float avg_label_length; /* exponential moving average / float label_entropy; / Shannon entropy of label chars */ } dns_tracker_t;
float shannon_entropy(const char label, int len) { int freq[256] = {0}; for (int i = 0; i < len; i++) freq[(unsigned char)label[i]]++; float h = 0; for (int i = 0; i < 256; i++) { if (freq[i]) { float p = (float)freq[i] / len; h -= p * log2f(p); } } return h; } / DNS label entropy: normal words ~3.5 bits/char / / Base32 encoded data: ~4.7 bits/char (higher — more uniform distribution) / / Threshold: label entropy > 4.0 in labels > 15 chars → suspicious */
/* 4. Connection profile anomaly / / Build per-host baseline: typical ports, destinations, bytes/hour / / Alert when deviation exceeds Z-score threshold / / Implemented as exponential moving average + standard deviation */
float ewma_update(float prev_avg, float new_val, float alpha) { return alpha * new_val + (1 - alpha) * prev_avg; } /* alpha = 0.1 → slow learning (stable baseline) / / Z-score = (current - mean) / stddev; alert if > 3.0 */
BEACON DETECTION — FINDING C2 COMMUNICATION
Detecting Periodic C2 Callbacks
BEACON DETECTIONModern malware (Cobalt Strike, Metasploit, many RATs) uses periodic "beaconing" — the implant calls home to the C2 server on a fixed schedule. A Cobalt Strike beacon with a 60-second sleep plus 30% jitter will call home every 42–78 seconds. This regularity is detectable statistically.
/* Beacon detection algorithm */ /* For each (src_ip, dst_ip, dst_port) tuple that has multiple connections: */ /* Compute the inter-arrival times (IAT) between connection attempts */ /* A beacon has low variance in IAT (periodic) */typedef struct { uint32_t src_ip; uint32_t dst_ip; uint16_t dst_port; uint64_t timestamps[64]; /* last 64 connection timestamps (ns) */ uint32_t count; } beacon_tracker_t;
typedef struct { float period; /* estimated beacon period in seconds / float jitter; / standard deviation as fraction of period / float score; / 0.0 = random, 1.0 = perfect beacon */ } beacon_result_t;
beacon_result_t detect_beacon(beacon_tracker_t t) { if (t->count < 8) return (beacon_result_t){0}; / not enough data */
/* Compute inter-arrival times */ float iats[63]; int n = MIN(t->count - 1, 63); for (int i = 0; i < n; i++) iats[i] = (t->timestamps[i+1] - t->timestamps[i]) / 1e9; /* seconds */ /* Mean and standard deviation of IAT */ float mean = 0, variance = 0; for (int i = 0; i < n; i++) mean += iats[i]; mean /= n; for (int i = 0; i < n; i++) variance += (iats[i] - mean) * (iats[i] - mean); variance /= n; float stddev = sqrtf(variance); /* Coefficient of variation: stddev / mean */ /* Perfect beacon: CV = 0 */ /* Cobalt Strike with 30% jitter: CV ≈ 0.17 */ /* Random HTTP browsing: CV ≈ 0.8–2.0 */ float cv = stddev / mean; beacon_result_t r = { .period = mean, .jitter = cv, .score = MAX(0.0f, 1.0f - (cv / 0.5f)) /* 1.0 if CV=0, 0 if CV>0.5 */ }; /* Alert thresholds */ if (r.score > 0.7 && mean > 10.0f && mean < 3600.0f) alert_beacon(t->src_ip, t->dst_ip, t->dst_port, &r); return r;}
/* Cobalt Strike beacon periods to watch for / / Default sleep: 60s / / Common configs: 5s, 30s, 60s, 300s, 3600s / / Jitter: 10–50% (controlled randomisation) */
/* HTTPS beacon evasion — how beacons hide / / Malleable C2 profiles: beacon looks like legitimate browser traffic / / User-Agent: Mozilla/5.0 (matching current Chrome) / / URIs: /jquery-3.3.1.min.js, /jquery.min.map, etc. / / Headers: matching legitimate CDN patterns / / Countermeasure: JA3 fingerprint + certificate check + timing analysis */
THREAT INTELLIGENCE — IOC CORRELATION
IoC Types, Sources, and Integration
THREAT INTEL/* IoC types */ IP addresses: Known C2 servers, malware infrastructure, botnets Domains: Malware domains, DGA domains, phishing domains URLs: Specific malicious URLs (drive-by download, phishing pages) File hashes: MD5/SHA256 of known malware binaries JA3 hashes: Malware TLS fingerprints Certificate: Fingerprints of rogue/malware certificates Email headers: From addresses, subject patterns for phishing User-Agents: Known malware/scanner User-Agent strings/* Threat intel feed sources */ Open source: Feodo Tracker: https://feodotracker.abuse.ch/ (Emotet, TrickBot C2) Abuse.ch URLHAUS: malware download URLs MalwareBazaar: file hashes of known malware MISP: community threat sharing platform AlienVault OTX: open threat exchange IoCs EmergingThreats: Suricata/Snort rule feed
Commercial: Recorded Future, CrowdStrike Intelligence, FireEye iSIGHT, IBM X-Force Exchange, VirusTotal Intelligence
/* Integration architecture / typedef struct { / IP blacklist — hash set for O(1) lookup */ rte_hash_t bad_ips; / uint32_t → threat_info_t */
/* Domain blacklist — trie for fast prefix/suffix matching */ domain_trie_t *bad_domains; /* "evil.com" → threat_info_t */ /* URL blacklist — hash of full URLs */ rte_hash_t *bad_urls; /* JA3 blacklist — hash set */ rte_hash_t *bad_ja3; /* Metadata */ uint64_t last_update_ns; uint32_t total_entries;} threat_intel_db_t;
typedef struct { uint8_t threat_type; /* MALWARE_C2, PHISHING, BOTNET, SCANNER… / uint8_t confidence; / 0–100 confidence score / uint32_t first_seen; / unix timestamp */ uint32_t last_seen; char malware_family[32]; } threat_info_t;
/* Inline check in NGFW forwarding path */ int check_threat_intel(session_t *s, threat_intel_db_t *db) { threat_info_t *ti;
/* Check destination IP */ if (rte_hash_lookup_data(db->bad_ips, &s->key.dst_ip, (void **)&ti) >= 0) { session_set_threat(s, ti); return 1; /* block or alert */ } /* Check JA3 (populated by TLS parser) */ if (s->ja3[0] && rte_hash_lookup_data(db->bad_ja3, s->ja3, (void **)&ti) >= 0) { session_set_threat(s, ti); return 1; } return 0;}
/* Feed update — live reload without restart / / Double-buffered: build new table in background, atomic swap */ void threat_intel_update(threat_intel_db_t **live, const char *feed_url) { threat_intel_db_t *new_db = download_and_parse_feed(feed_url); threat_intel_db_t old_db = atomic_exchange(live, new_db); / Wait for in-flight lookups to complete, then free old_db / rte_delay_us(1000); / 1ms grace period */ threat_intel_db_free(old_db); }
DNS THREAT DETECTION — DGA, TUNNELLING, FAST-FLUX
DNS as Both an Attack Vector and Detection Goldmine
DNS THREATS/* DNS provides unique visibility: malware must resolve C2 domains */ /* Every DNS query is visible (unless DoH or encrypted DNS) *//* 1. Domain Generation Algorithm (DGA) detection / / Malware generates hundreds of random domains per day / / Tries each until one resolves (C2 server registered one of them) / / Human-unreadable: “x7kqp2mntb.com”, “ajwhfksdfh.net” */
/* DGA detection signals: / / - Domain > 15 chars in SLD (second-level domain) / / - High consonant-to-vowel ratio (no pronounceable words) / / - High character entropy (random character distribution) / / - Domain never seen before (no historical resolution) / / - Multiple NXDOMAIN responses in sequence */
/* Feature extraction for DGA classification / typedef struct { char domain[256]; int sld_length; / length of just the SLD (no TLD) / float vowel_ratio; / vowels / total chars / float entropy; / Shannon entropy of SLD characters / float digit_ratio; / digits / total chars / int unique_chars; / distinct characters used / int max_run; / longest run of same character class */ } domain_features_t;
int is_dga(const domain_features_t f) { / Simple heuristic classifier / int score = 0; if (f->sld_length > 12) score += 2; if (f->entropy > 3.8) score += 3; / high randomness / if (f->vowel_ratio < 0.25) score += 2; / few vowels / if (f->digit_ratio > 0.3) score += 1; / many digits / if (f->unique_chars < 8) score -= 1; / might be normal / return score >= 5; / threshold / / For production: use ML model (random forest) trained on labelled data */ }
/* 2. DNS tunnelling detection / / Data exfiltration or C2 via DNS TXT/NULL queries / / Payload encoded in subdomain: c29tZWRhdGE.evil.com */
/* DNS tunnelling signals: / / - Long FQDN (>50 chars including subdomain) / / - High-entropy subdomain (base32/hex encoded data) / / - TXT/NULL query types (not just A/AAAA) / / - High query rate to the same parent domain / / - DNS responses contain large TXT records / / - Asymmetric traffic: many queries, large responses */
void detect_dns_tunnel(dns_info_t *di, dns_tracker_t *t) { float label_h = shannon_entropy(di->subdomain, strlen(di->subdomain));
/* Score this query */ int score = 0; if (strlen(di->fqdn) > 50) score += 3; if (label_h > 4.0) score += 3; /* high entropy label */ if (di->qtype == DNS_TXT) score += 2; if (di->qtype == DNS_NULL) score += 3; if (t->queries_in_window > 60) score += 2; /* high rate */ if (score >= 6) alert(DNS_TUNNEL, di, score);}
/* 3. Fast-flux DNS detection / / Botnet hides C2: domain has many A records, all short TTL, all IPs change / / Detection: multiple A records returned, TTL < 60s, IPs span many ASNs */
/* 4. DNS over HTTPS (DoH) bypass detection / / Clients send DNS queries to port 443 (HTTPS) to bypass DNS monitoring / / Detection: block well-known DoH resolvers (1.1.1.1:443/dns-query, 8.8.8.8:443) / / Force internal DNS: block outbound DNS except to corporate resolver / / Or: use SSL inspection to see DoH queries */
ALERT TUNING — MANAGING FALSE POSITIVES IN PRODUCTION
False Positive Management and Rule Tuning
TUNING/* The false positive problem */ /* A well-tuned IPS might have 0.01% false positive rate */ /* At 10 Gbps with 64-byte packets: 19.5 Mpps */ /* 0.01% = 1950 false blocks per second → completely unusable */ /* Tuning is as important as detection capability *//* Step 1: Profile your traffic before enabling IPS / / Run in IDS mode for 2 weeks. Collect EVE JSON. Analyse alerts. / / Key question: which rules fire most? Are those FPs or TPs? */
/* Alert classification / / TP (True Positive): Real attack. Alert is correct. / / FP (False Positive): Legitimate traffic wrongly alerted. / / FN (False Negative): Real attack missed (no alert). / / TN (True Negative): Legitimate traffic, no alert. */
/* Tuning approaches */
Threshold tuning: /* Rule fires every packet — add threshold to reduce noise / alert:threshold:type limit,track by_src,count 1,seconds 300; / Only alert once per source per 5 minutes */
Suppress rules for known-good sources: suppress gen_id 1, sig_id 2001219, track by_src, ip 10.1.0.0/24; /* Suppress SSH brute force rule for internal hosts */
Pass rules (whitelist before detect): pass tcp HOME_NET any /* Vulnerability scanner — don’t alert on its port scans */
Score-based alerting: /* Don’t block on single rule match / / Accumulate score across multiple correlated events / / Block only when score > threshold */
typedef struct { uint32_t src_ip; uint32_t score; /* accumulated threat score / uint64_t reset_time_ns; / when to reset score / char events[16][64]; / last 16 contributing events */ } threat_score_t;
void threat_score_update(threat_score_t *ts, const char sig, uint32_t weight) { ts->score += weight; / Log contributing event */ snprintf(ts->events[ts->score % 16], 64, “%s”, sig);
if (ts->score >= 100) { quarantine_host(ts->src_ip); /* automatic response */ ts->score = 0; }}
/* Score weights / / JA3 matches known malware: 30 points / / DNS query to known-bad domain: 40 points / / Port scan (>50 ports/min): 20 points / / Connection to C2 IP: 70 points / / Lateral movement (SMB spray): 50 points */
/* 5. Exception list maintenance / / Keep a structured exception database / / Every exception needs: justification, owner, expiry date / / Exceptions without expiry become permanent security holes */
/* 6. Rule set management / / Emerging Threats Pro rules: ~40,000 rules / / Typical production deployment: enable 20% of rules / / Categories to always enable: malware, c2, exploit / / Categories to carefully evaluate: policy, info, dos */
Suricata IDS/IPS Deployment and Tuning
Objective: Deploy Suricata in IDS mode, then IPS mode. Write custom rules. Tune false positives using real traffic.
sudo apt install suricata. Configure to listen on your network interface in AF_PACKET mode. Enable EVE JSON logging to /var/log/suricata/eve.json. Download Emerging Threats Community rules: sudo suricata-update. Start in IDS mode: sudo suricata -i eth0 --af-packet -D.tail -f /var/log/suricata/eve.json | jq 'select(.event_type=="alert")'. Count alerts per rule category. Identify which rules fired: are they true positives (the tools triggered them) or false positives?/etc/suricata/rules/custom.rules. Test each works.iptables -A FORWARD -j NFQUEUE --queue-num 0. Restart Suricata with -q 0. Set one rule to "drop" instead of "alert". Verify traffic is blocked: curl to the blocked destination should fail. Verify legitimate traffic still flows. Observe latency impact: ping RTT before vs after enabling IPS.Beacon Detection Engine
Objective: Build a beacon detection engine that can identify Cobalt Strike default beacons in captured traffic, and test it against both real and simulated beacon traffic.
Threat Intelligence Pipeline
Objective: Build an automated threat intel ingestion pipeline. Ingest IoCs from multiple feeds, deduplicate, and integrate with your session table for real-time checking.
M25 MASTERY CHECKLIST
- Know IDS vs IPS: IDS passive/alert-only; IPS inline/can-block; false positives have different consequences (annoying vs disruptive)
- Know 4 detection methods: signature (known threats), anomaly (statistical deviation), heuristic/behavioural (patterns over time), threat intel/IoC (known-bad indicators)
- Know Snort/Suricata rule structure: action proto src_ip src_port direction dst_ip dst_port (options)
- Know content matching options: content, nocase, distance/within, pcre; hex bytes with pipes
- Know flow options: established,to_server; established,to_client; stateless
- Know HTTP-specific keywords: http.method, http.uri, http.host, http.user_agent, http.stat_code
- Know TLS keywords: tls.sni, tls.subject, tls.issuerdn, ja3_hash, ja3s_hash
- Know threshold options: type limit/both/threshold; track by_src/by_dst; count; seconds
- Know Suricata thread model: RX threads → worker threads (decode+detect) → output threads
- Know Suricata output modes: EVE JSON, Unified2; key EVE fields: flow_id, alert section, app_proto
- Know Suricata IPS modes: NFQUEUE (verdict-based), AF_PACKET IPS with copy-mode (bypass)
- Know port scan detection: count unique dst_ports per src_ip per window; alert when > threshold
- Know DNS anomaly signals: high query rate, high label entropy, TXT/NULL queries, long FQDNs
- Know Shannon entropy formula and typical values: random data ~8 bits/byte, English text ~4, base32 ~4.7
- Know DGA detection features: SLD length, vowel ratio, entropy, digit ratio, NXDOMAIN sequences
- Know beacon detection: IAT (inter-arrival time) statistics; coefficient of variation; CV < 0.3 = likely beacon
- Know Cobalt Strike default beacon period (60s) and jitter (30%) and resulting CV (~0.17)
- Know Malleable C2 profiles: beacons mimic legitimate browser traffic; JA3 + certificate + timing still detects
- Know IoC types: IP, domain, URL, file hash, JA3 hash, certificate fingerprint, User-Agent
- Know threat intel sources: Feodo Tracker, URLhaus, Emerging Threats, MISP, AlienVault OTX
- Know live feed update architecture: double-buffered tables, atomic pointer swap, grace period
- Know DNS tunnelling signals: long FQDNs, high-entropy subdomains, TXT/NULL types, high rate to same parent
- Know DoH bypass and countermeasures: block known DoH resolvers, force internal DNS, SSL inspection
- Know alert tuning approaches: threshold rules, suppress by source, pass rules for trusted hosts, score-based blocking
- Know false positive rate math: even 0.01% FP rate is catastrophic at NGFW line rates
- Know score-based blocking: accumulate points from multiple signals before taking action; prevents single-rule overblocking
- Completed Lab 1: Suricata IDS+IPS deployment; custom rules; false positive tuning to <100 alerts/hour
- Completed Lab 2: beacon detector with IAT statistics; tested against simulated and real Cobalt Strike traffic
- Completed Lab 3: multi-feed threat intel pipeline with live update and session table integration
✅ When complete: Move to M26 - Policy Engine and Capstone — the final module bringing together all Phase 6 subsystems into a complete NGFW architecture, plus a capstone project designing your team's NGFW.