Skip to main content

Chapter 2.2 Quiz - IDS/IPS: Signatures, Anomaly Detection & Evasion

Quiz Mode - All answers are hidden under collapsible sections. Attempt each question before revealing the answer.


Question 1

You deploy a Suricata rule with the content keyword matching "passwd" in HTTP URI. During testing, an attacker uses the URL /etc%2Fpasswd. Your rule does not fire. What is the most likely cause, and what is the fix?

Reveal Answer & Explanation

Answer: The content keyword is matching against the raw (un-normalized) URI buffer. %2F is the URL-encoded form of /, so the literal bytes in the packet are %2Fpasswd, not /passwd.

Fix: Use the http_uri buffer modifier, which applies Suricata's HTTP normalization (URL decoding) before matching:

alert http any any -> $HTTP_SERVERS any (
msg:"LFI attempt - /etc/passwd";
content:"etc"; http_uri; nocase;
content:"passwd"; http_uri; nocase; distance:0;
sid:9900010;
rev:1;
)

http_uri invokes the HTTP inspector, which decodes %2F to /, %252F to %2F (double-encoding), and collapses /../ sequences. The match now fires on /etc%2Fpasswd, /etc/./passwd, /%65tc/passwd (hex-encoded 'e'), etc.

Deeper context: HTTP normalization is a multi-step process; double-encoding (%252F to %2F to /) requires two decode passes. Configure double_decode: yes in the Suricata HTTP configuration to handle this. This corresponds to evasion of T1027 (Obfuscated Files or Information).


Question 2

An attacker runs nmap -sS -T0 --randomize-hosts 10.0.0.0/24. Your Snort sfportscan preprocessor is configured to fire after 15 probes in 60 seconds from a single source. Does this scan trigger the alert? Why or why not? What detection mechanism would catch it?

Reveal Answer & Explanation

Answer: With -T0 (paranoid timing), Nmap sends one probe every ~5 minutes and randomizes target order. Over a /24 (254 hosts), the total scan duration is ~21 hours. In any 60-second window, at most 1-2 probes originate from the scanner - far below the 15-probe threshold. The sfportscan alert does not fire.

What catches it:

  1. Long-window behavioral aggregation - NetFlow/IPFIX analysis with a multi-hour window. Tools like Zeek + custom analytics or a SIEM query over connection logs can detect a single source touching many unique destinations over hours.
# Zeek conn.log: count unique dst IPs per src over the last 24h
cat conn.log \
| zeek-cut id.orig_h id.resp_h \
| awk '{count[$1][$2]=1} END {for(src in count) print length(count[src]), src}' \
| sort -rn | head -20
  1. SYN-only flow anomaly - Stealth SYN scans (-sS) never complete the three-way handshake. A source IP with hundreds of SYN-only flows (no corresponding SYN-ACK from target or ACK from source) is a statistical outlier regardless of timing.

  2. Distributed scan detection - If the attacker uses -D (decoys) or multiple source IPs, per-source thresholds fail entirely. Detection requires correlation across sources (shared destination patterns, same scan timing).

This maps to T1046 (Network Service Discovery).


Question 3

Explain the JA3 fingerprinting technique. Why does it provide detection value against TLS-encrypted C2 traffic, and what are its limits?

Reveal Answer & Explanation

Answer: JA3 hashes a set of fields from the TLS ClientHello message - fields that are determined by the TLS client library (not the application payload): TLS version, cipher suite list (in order), extension list (in order), elliptic curves, and elliptic curve point formats. The MD5 hash of these concatenated values is the JA3 fingerprint.

JA3 = MD5(SSLVersion,Ciphers,Extensions,EllipticCurves,EllipticCurvePointFormats)

Why it has detection value:

  • A specific C2 framework (e.g., Cobalt Strike with default profile) produces a consistent JA3 regardless of payload. The beacon's TLS library is identifiable even though the payload is encrypted.
  • Known-malicious JA3 hashes are published by threat intel sources and can be matched against observed traffic.
  • A JA3 mismatch - e.g., a connection to port 443 that produces a JA3 fingerprint associated with the Python requests library rather than a browser - is anomalous even without a specific IOC match.
# Zeek ssl.log has JA3 natively
cat ssl.log | zeek-cut ts id.orig_h ja3 server_name \
| grep "51c64c77e60f3980eea90869b68c58a8" # known Cobalt Strike default

Limits:

  1. Malleable profiles: Cobalt Strike and Sliver let operators customize the TLS profile, changing the JA3 fingerprint. Defenders cannot rely on a static hash blocklist for sophisticated actors.
  2. Shared JA3s: A JA3 associated with a popular browser (Chrome's JA3 is used by millions of legitimate sessions). Attacker libraries can mimic Chrome's TLS fingerprint.
  3. JA3S (server fingerprint): Hashes the ServerHello response; combining JA3 + JA3S pairs reduces ambiguity but increases tuning complexity.
  4. TLS 1.3 + ECH (Encrypted Client Hello): ECH encrypts the ClientHello extension data, potentially eliminating JA3 signal in future deployments.

JA3 is one signal in a layered detection strategy, not a standalone detection method. This relates to T1573 (Encrypted Channel).


Question 4

Write a Suricata rule that detects potential DNS tunneling by matching DNS queries with a QNAME longer than 50 characters over UDP port 53. Include appropriate metadata.

Reveal Answer & Explanation

Answer:

alert dns any any -> any 53 (
msg:"POSSIBLE DNS Tunnel - Excessive QNAME Length";
dns_query; -- match in the DNS query name buffer
dsize:>50; -- DNS query payload > 50 bytes (proxy for long QNAME)
threshold:type limit, -- rate-limit: alert once per source per 60s
track by_src,
count 1,
seconds 60;
classtype:policy-violation;
sid:9900020;
rev:1;
metadata:attack_target DNS_Server,
affected_product DNS,
mitre_tactic TA0011, -- Command and Control
mitre_technique T1071.004; -- Application Layer Protocol: DNS
)

Notes on accuracy:

  • dns_query is a Suricata-specific sticky buffer that normalizes the DNS QNAME field, making the content/dsize match operate on the decoded query name.
  • dsize alone is a blunt instrument - it fires on any large DNS payload, not just long query names. For production, combine with a PCRE or Lua script to measure only the QNAME length precisely.
  • Long QNAME queries are used in iodine, dns2tcp, dnscat2, and similar DNS tunneling tools. Legitimate queries rarely exceed 40 characters; DGA domains cluster around 20-30 characters but with high entropy rather than length.
  • Pair this rule with entropy analysis (see Lua example in Section 6) for lower false-positive rates.

Detection context (T1071.004): DNS tunneling typically shows:

  • Queries to a single authoritative NS (the attacker's domain) at high frequency
  • Large TXT or NULL record responses
  • Unusually high DNS query rate per host
  • Responses containing base64 or binary-encoded data

Combine NIDS detection with DNS query logging (BIND querylog, Windows DNS debug logging) for full coverage.