The hunt is only half the work. A confirmed finding that doesn’t produce a detection, an IR ticket, or a CTI deliverable has no lasting value. This lesson covers converting network hunt findings into durable detection rules — and knowing which findings are ready for conversion and which need more evidence.
The PEAK Act Phase: Three Outputs
Hunt finding confirmed
│
├─────────────────► (1) Detection Rule
│ Write Sigma → PR to detection repo → CI/CD test
│
├─────────────────► (2) IR Ticket
│ Scope, IOCs, ATT&CK chain → escalate to IR team
│
└─────────────────► (3) CTI Deliverable
Hunt report + IOC pack + ATT&CK Navigator layer
A high-quality hunt produces all three. A routine beacon hunt with a known-family implant produces (1) and (2). A novel C2 framework discovery produces all three.
ABLE Quality Gate
Before converting a finding to a production detection rule, run the ABLE check:
A — Assumptions
Every detection rule encodes assumptions. Name them explicitly:
Rule: "Cobalt Strike default JA3 on port 443"
Assumptions:
- Cobalt Strike default JA3 (72a7c4de...) is not used by any legitimate application
in our environment
- Port 443 outbound with service=ssl is expected to use standard TLS
- Hosts connecting to external IPs with this JA3 are not part of any authorized
penetration test
Validation: Check with AppSec team — is there any approved tool with this JA3?
Check with IR team — is there an authorized pentest ongoing?
B — Behaviors
The detection must target a specific behavior, not just an artifact:
Too artifact-focused (bad):
"Alert when JA3 = 72a7c4de AND dst_ip = 91.213.50.22"
Problem: IP changes every campaign. Rule dies in days.
Behavior-focused (good):
"Alert when JA3 = 72a7c4de AND host_count_for_ja3 = 1
(rare JA3, seen only by this host)"
Problem: slower to develop but works across campaigns.
L — Logging
Questions:
- Is Zeek ssl.log collected from all network segments?
Known gap: branch offices use a separate Zeek deployment with 7-day retention.
Implication: detection coverage gap for branch office C2 that lasts >7 days.
- Is the JA3 field populated by all Zeek versions in our fleet?
Gap: Zeek < 3.0 doesn't compute JA3 — 2 of 8 sensors are version 2.6.
Action: upgrade before shipping the rule, or add a version-conditional filter.
E — Exploitability
"Cobalt Strike default JA3" exploitability:
- Trivially bypassed: any operator who reads this rule will change their JA3
(Cobalt Strike malleable profile: one line to set custom ciphers/extensions)
- Mitigation: pair JA3 rule with certificate metadata rule (harder to evade simultaneously)
- Expected TP lifespan: 2-4 weeks before sophisticated operators evade it
- Expected commodity-malware coverage: indefinite (most malware doesn't customize JA3)
- Decision: ship rule with 90-day review trigger
Writing the Sigma Rule
From Hunt Finding to Rule Logic
Hunt finding: Host 10.1.2.33 beaconing with JA3 = a1b2c3d4, to self-signed cert, port 443, from svchost.exe in AppData.
What’s universal (include in rule):
- Self-signed cert on port 443 (cert issuer = cert subject)
- Empty SNI + port 443
- Rare JA3 (use as tag, not hard-coded hash — too fragile)
What’s specific to this incident (do NOT include — too IOC-specific):
- IP 185.220.101.9 (changes)
- Domain cdn-update-services.net (changes)
- Specific JA3 hash (trivially bypassed by changing one cipher)
Sigma rule:
title: Outbound TLS with Self-Signed Certificate to Rare External Destination
id: c3f7a2e1-...
status: experimental
description: Detects TLS connections where the server certificate is self-signed
(issuer == subject), which is uncommon for legitimate services and
commonly seen in attacker-controlled C2 infrastructure.
references:
- https://attack.mitre.org/techniques/T1071/001/
author: Threat Hunt Team
date: 2024-08-14
tags:
- attack.command_and_control
- attack.t1071.001
logsource:
product: zeek
category: ssl
detection:
selection:
local_orig: true
local_resp: false
destination.port: 443
self_signed:
tls.server.issuer|contains:
- tls.server.subject # issuer == subject = self-signed
filter_legitimate:
destination.ip|cidr:
- '13.107.0.0/14' # Microsoft
- '52.96.0.0/14' # Microsoft
- '8.8.8.8/32' # Google DNS
condition: selection and self_signed and not filter_legitimate
fields:
- src_ip
- dst_ip
- dst_port
- ja3
- tls.server.issuer
- tls.server.subject
falsepositives:
- Internal development/test servers with self-signed certs
- Some legacy enterprise software
- IoT devices
level: medium
The Hunt Journal Entry
Every hunt, even null results, deserves a journal entry:
## Hunt 2024-08-14 — Network Beacon (Cobalt Strike JA3)
**Analyst:** M. Torres
**Hypothesis type:** Hypothesis-driven (known TTP)
**Hypothesis:** Cobalt Strike default JA3 profile (72a7c4de) is present in our environment,
targeting port 443, from a host not in any authorized pentest scope.
**Data source:** Zeek ssl.log, 30 days, Sentinel workspace TDL-PROD
**Data validation:** Full-fidelity Zeek confirmed (no sampling). JA3 field populated
all sensors. 30-day retention confirmed.
**Queries run:**
1. JA3 frequency baseline (30 days)
2. Rarity filter: JA3 host_count == 1, conn_count > 50
3. Peer cohort filter: dst host_count <= 3
4. CV calculation on top 10 candidates
**Findings:**
- 1 confirmed beacon: 10.1.2.33 → 185.220.101.9:443, JA3=a1b2c3d4
- CV = 0.031 (very regular, 60s interval)
- Cert: self-signed, issued 4 days ago
- Endpoint: svchost.exe from C:\Users\jsmith\AppData\ (abnormal path)
- Confidence: HIGH
- 3 null results for 72a7c4de specifically (no Cobalt Strike default JA3 found)
**Decision:**
1. IR ticket created (10.1.2.33 — active C2 confirmed)
2. Detection rule: see sigma/network/c3f7a2e1.yml (self-signed TLS hunt)
3. Next hypothesis: Are there other hosts in AppData with similar behavioral patterns?
(Spawn: hypothesis 2024-08-14-02 — scheduled for next hunt window)
**Limitations:**
- Branch office Zeek sensors (old version) excluded — coverage gap remains
- High-jitter C2 (CV > 0.30) would not be caught by interval method
**Confidence in null result (no CS default JA3):** Medium
(Full data available; however branch office gap means 0% coverage for branch hosts)