E-C.O.P (Thailand)
Stand Watch with Care, Visibility First Security Operations Center
← เครื่องมือทั้งหมด
Quantum-Safe Monitoring
Detection Runbook v1.0
May 2026

Quantum-Safe Monitoring — Detection Runbook

เอกสารฉบับเต็มสำหรับ SOC engineer · 15 detections paste-able · onboarding sprint 4 สัปดาห์ · macros + lookups + dashboard XML outline · ทุก SPL ทดสอบ syntax แต่ ต้อง tune ที่หน้างาน เพราะ field name อาจแตกต่างตาม Splunk TA version

P0 (4) P1 + P2 (7) P3 (4) 15 total detections SOC engineer · 0.5 FTE

Sections

01 · Prerequisites

เปิด log + setup ก่อนเริ่ม

ถ้า prerequisite ไม่ครบ · alert จะท่วม false positive และทีมจะเลิกเชื่อ detection

1.1 Log sources — checklist

SourceSplunk indexSourcetypeใช้ใน detection
Zeek conn + sslzeekbro:conn / bro:sslD1, D2, D3, D4
NGFW (Palo Alto)pan_logspan:trafficD1, D2
NGFW (Fortinet)fortinetfortigate_trafficD1, D2
DNS BIND / Infobloxdnsinfoblox:dns / isc:bind:queryD7
Cisco Umbrella DNScisco_umbrellacisco_umbrella:dnsD7
CrowdStrike Falconcrowdstrikecrowdstrike:event:jsonD5, D6, D8
SentinelOnesentinelonesentinelone:dvD5, D6, D8 (alt)
Zscaler NSSzscalerzscalernss-webD9, D10
Netskopenetskopenetskope:webtxn / netskope:application:jsonD9, D10, D11
AWS CloudTrailawsaws:cloudtrailD12
Azure Key Vaultazuremscs:azure:eventhubD12
sslyze JSON (HEC)cert_inventorysslyze:scanD13, D14, D15

1.2 Setup checklist

  1. Baseline 30 วัน ก่อนเปิด anomaly alert · ใช้ scheduled saved search รัน earliest=-30d นี้สร้าง stats summary
  2. Asset CMDB lookup — สร้างไฟล์ asset_cmdb.csv mapping ip,hostname,business_unit,criticality,owner
  3. Whitelist lookupsbusiness_partner_asn.csv, known_crypto_consumers.csv, authorized_key_readers.csv
  4. Threat intel feed — subscribe abuse.ch JA3 + MISP feed + commercial CTI (Mandiant / Recorded Future)
  5. Storage capacity — TLS metadata ~1-5 GB/day/1000 endpoint · บัฟเฟอร์ retention 90 วัน
  6. Detection engineering owner — อย่างน้อย 0.5 FTE · ตอบ alert + tune ทุก 2 สัปดาห์
  7. PDPA + TLS decryption approval — ถ้าจะ inspect payload ผ่าน Zscaler/Netskope · ต้องผ่าน legal/HR + DPIA

1.3 Splunk apps แนะนำให้ติดตั้ง

02 · P0 Detections

4 ตัวที่ต้องเปิดก่อน — Value สูงสุด

ทุกตัวเป็น critical · ส่งเข้า SOC analyst tier 1 ทันที · response SLA 15 นาที

D1 P0 CRITICAL UC1 · HNDL Egress

🔴 HNDL Egress Volume Anomaly

Logic: Host ที่ปกติส่ง encrypted traffic ออกข้างนอก X MB/วัน · จู่ๆ ส่ง 10x ในวันเดียว = candidate HNDL bulk exfil · ใช้ z-score จาก 30 วัน baseline
Required: CIM Network_Traffic populated · Zeek conn.log หรือ NGFW traffic log
SPL · scheduled hourly
| tstats summariesonly=t sum(All_Traffic.bytes_out) as bytes_out
  from datamodel=Network_Traffic.All_Traffic
  where All_Traffic.app=ssl OR All_Traffic.dest_port IN (443,8443)
        AND NOT All_Traffic.dest_category=internal
  by All_Traffic.src, _time span=1h
| eventstats avg(bytes_out) as avg_30d, stdev(bytes_out) as sd_30d
  by All_Traffic.src
| eval z_score = (bytes_out - avg_30d) / sd_30d
| where z_score > 4 AND bytes_out > 500000000
| eval gb_out = round(bytes_out/1024/1024/1024, 2)
| lookup asset_cmdb.csv ip as "All_Traffic.src" OUTPUT business_unit, criticality, owner
| table _time, All_Traffic.src, hostname, business_unit, gb_out, z_score, avg_30d
| sort -z_score
Tuning: Whitelist backup servers, ETL jobs, S3 sync · z > 4 AND > 500MB · ปรับ z-score threshold หลัง baseline 30 วัน · false positive ที่พบ: cloud backup, video conferencing, software update
D2 P0 CRITICAL UC1 · HNDL Egress

🔴 Long-Lived TLS Session to Foreign ASN

Logic: TLS session > 4 ชม. + ปลายทาง foreign ASN ที่ไม่ใช่ business partner = candidate beacon/exfil channel · enrich ด้วย iplocation + business partner lookup
Required: index=zeek bro:conn · lookup business_partner_asn.csv
SPL · scheduled every 4h
index=zeek sourcetype=bro:conn proto=tcp service=ssl
| where duration > 14400
| iplocation id.resp_h
| lookup business_partner_asn.csv asn OUTPUT partner as is_partner
| where isnull(is_partner) AND Country!="Thailand"
| eval gb = round(orig_bytes/1024/1024/1024, 2)
| where gb > 1
| lookup asset_cmdb.csv ip as "id.orig_h" OUTPUT business_unit, criticality
| table _time, id.orig_h, business_unit, id.resp_h, Country, asn, duration, gb, ja3
Tuning: เก็บ business_partner_asn.csv ที่ AWS/Azure/GCP/Cloudflare ASN + ลูกค้า/partner cloud providers · false positive ที่พบ: SaaS dashboards ที่เปิดทิ้งไว้, monitoring agents (Datadog, NewRelic)
D5 P0 CRITICAL UC1 + UC3 · Staging Pattern

🔴 Crypto Staging → Upload (Multi-Stage)

Logic: Classic HNDL staging — process รัน archive tool ด้วย password (7z -p, winrar a -p, openssl enc, gpg --encrypt) แล้วตามด้วย TLS upload > 100MB จาก host เดียวกันภายใน 30 นาที · นี่เป็น Multi-stage correlation
Required: CrowdStrike ProcessRollup2 + Zeek conn.log · join บน host
SPL · real-time alert (1m window)
index=crowdstrike sourcetype=crowdstrike:event:json
  event_simpleName=ProcessRollup2
  (CommandLine="*7z*-p*" OR CommandLine="*openssl enc*"
   OR CommandLine="*gpg*--encrypt*" OR CommandLine="*rar* a -p*"
   OR CommandLine="*Compress-Archive*Password*")
| eval staging_time=_time, host=ComputerName
| table host, UserName, ParentBaseFileName, FileName, CommandLine, staging_time
| join host [
    search index=zeek sourcetype=bro:conn service=ssl earliest=-30m
    | where orig_bytes > 100000000
    | stats min(_time) as upload_time, sum(orig_bytes) as bytes
      by id.orig_h as host
  ]
| where upload_time - staging_time BETWEEN 0 AND 1800
| eval delta_min = round((upload_time - staging_time)/60, 1)
| eval gb = round(bytes/1073741824, 2)
| table host, UserName, CommandLine, delta_min, gb
Tuning: ทุก hit ส่ง critical ทันที — false positive น้อยมาก · whitelist เช่น backup tools (Veeam, NetBackup), DevOps deploy scripts ที่ใช้ password protection legitimate
D6 P0 CRITICAL UC1 · Key Theft

🔴 Private Key File Read by Non-Service Process

Logic: process อ่านไฟล์ .pem, .pfx, id_rsa, *.key, ~/.ssh/* ที่ไม่ใช่ authorized service · ขโมยกุญแจวันนี้ → decrypt ข้อมูลเก่าได้ในอนาคต — ตรงกับ HNDL philosophy
Required: CrowdStrike FileOpenInfo หรือ SentinelOne file access · lookup authorized_key_readers.csv
SPL · scheduled every 1h
index=crowdstrike event_simpleName=FileOpenInfo
  (TargetFileName="*.pem" OR TargetFileName="*.pfx"
   OR TargetFileName="*\\.ssh\\id_*" OR TargetFileName="*private.key"
   OR TargetFileName="*\\AppData\\Roaming\\*\\Local State"
   OR TargetFileName="/root/.ssh/*" OR TargetFileName="/home/*/.ssh/*")
| stats count, values(TargetFileName) as files, values(UserName) as users
  by ComputerName as host, ImageFileName
| lookup authorized_key_readers.csv process as ImageFileName OUTPUT is_authorized
| where isnull(is_authorized)
| sort -count
Tuning: สำคัญมาก — เพราะกุญแจที่ถูกขโมยตอนนี้ = decrypt ได้ใน 8 ปี · false positive จาก SSH client, GitOps tools (terraform, ansible), CI/CD agents · ใส่ในไฟล์ whitelist
03 · P1 Detections

4 ตัวที่เปิดสัปดาห์ที่ 2-3

High value detection · response SLA 1 ชม. · trial period 2 สัปดาห์ก่อน promote เป็น production alert

D3 P1 HIGH UC3 · Hunting

🟠 JA3 Client Fingerprint Anomaly

Logic: JA3 hash = TLS client fingerprint · malware tool มักมี JA3 ที่ rare ในองค์กร · ใช้ rarity detection · enrich ด้วย abuse.ch threat intel feed
Required: Zeek ssl.log + JA3 IOC feed lookup (abuse_ja3.csv)
SPL · scheduled every 6h
index=zeek sourcetype=bro:ssl
| stats count, dc(id.orig_h) as host_count,
        values(server_name) as sni,
        latest(_time) as last_seen by ja3
| lookup abuse_ja3.csv ja3 OUTPUT malware_family, threat_type
| where host_count <= 2 AND count > 5
| eval suspicious_score = case(
    isnotnull(malware_family), "critical",
    match(mvjoin(sni,","), "(?i)(pastebin|telegram|discord|onion)"), "high",
    count < 20, "medium",
    1=1, "low")
| eval last_seen = strftime(last_seen, "%Y-%m-%d %H:%M")
| where suspicious_score!="low"
| sort -suspicious_score, count
Tuning: ใช้ abuse.ch JA3 feed update ทุกวัน · whitelist enterprise tools ที่ใช้ใน org น้อย (1-2 hosts) แต่ legitimate · sni keyword สามารถเพิ่ม cryptocurrency exchange, anonymizing proxy
D7 P1 HIGH UC1 · DNS Exfil

🟠 DNS Exfiltration — High Entropy Queries

Logic: DNS exfil ใช้ subdomain ยาว random เป็น covert channel · ตรวจจาก: query length, entropy, NXDOMAIN burst, query rate per host
Required: DNS query log (Infoblox/Umbrella/BIND)
SPL · scheduled hourly
index=dns sourcetype IN (infoblox:dns,cisco_umbrella:dns,isc:bind:query)
| eval q_len = len(query)
| eval subdomain = mvindex(split(query,"."),0)
| eval entropy = round(, 2)
| stats count, avg(q_len) as avg_len, max(entropy) as max_ent,
        dc(query) as unique_queries,
        values(reply_code) as codes
  by src_ip, query_domain
| where avg_len > 30 AND max_ent > 4.0 AND unique_queries > 50
| eval nxdomain_burst = if(match(mvjoin(codes,","),"NXDOMAIN"), "yes", "no")
| lookup asset_cmdb.csv ip as src_ip OUTPUT business_unit, criticality
| sort -unique_queries
Tuning: requires shannon_entropy macro (ดู section 06) · whitelist CDN, anti-malware update domains · false positive จาก telemetry domains (segment.io, google-analytics)
D9 P1 HIGH UC1 · User-Attributed HNDL

🟠 Bulk Upload to Unsanctioned Cloud Storage

Logic: User upload > 2GB ไป SaaS ที่ unsanctioned/shadow ใน 24 ชม. = HNDL candidate · CASB เห็น user identity (ไม่ใช่แค่ IP)
Required: Zscaler หรือ Netskope (TLS decryption + user binding)
SPL · scheduled every 4h (Zscaler variant)
index=zscaler sourcetype=zscalernss-web action=allow
| eval gb_up = bytes_out/1073741824
| stats sum(gb_up) as gb_total, count, values(url) as urls,
        values(appname) as apps
  by user, urlcategory, bin(_time, 1d) as day
| where (urlcategory IN ("personal_storage","unsanctioned_apps","shadow_it")
         OR risk_score > 70) AND gb_total > 2
| eval severity = case(gb_total > 20, "critical",
                       gb_total > 10, "high", 1=1, "medium")
| sort -gb_total
SPL · Netskope variant
index=netskope sourcetype="netskope:webtxn"
  activity=Upload OR activity=PostUpload
| eval gb_up = client_bytes/1073741824
| stats sum(gb_up) as gb_total by user, app, app_risk, bin(_time, 1d) as day
| where (app_risk >= 7 OR match(app_category,"(?i)Personal")) AND gb_total > 2
| sort -gb_total
Tuning: whitelist legitimate users (lawyer, M&A, audit) ที่อัปโหลด external เป็นปกติ · ใส่ approval flow · false positive จาก videoconferencing recording upload
D12 P1 HIGH UC1 · Cloud KMS Anomaly

🟠 KMS Bulk Decrypt Anomaly

Logic: Service account ที่ปกติเรียก KMS Decrypt 100 ครั้ง/ชม. · จู่ๆ 10,000 ครั้ง = bulk decrypt = data harvest signal · attacker ที่เข้าถึง service account ใช้ KMS ทำ bulk decrypt application ไม่เห็น แต่ KMS audit เห็น
Required: AWS CloudTrail data event เปิด หรือ Azure Key Vault diagnostic
SPL · scheduled hourly
index=aws sourcetype=aws:cloudtrail
  eventSource=kms.amazonaws.com
  eventName IN (Decrypt,GenerateDataKey)
| bin _time span=1h
| stats count by _time, userIdentity.userName, "resources{}.ARN"
| eventstats avg(count) as avg_30d, stdev(count) as sd_30d
  by userIdentity.userName, "resources{}.ARN"
| eval z_score = (count - avg_30d) / sd_30d
| where z_score > 5 AND count > 1000
| table _time, userIdentity.userName, "resources{}.ARN", count, avg_30d, z_score
Tuning: baseline 30 วัน · whitelist batch jobs ที่ทำ legitimate bulk decrypt (backup restore, data migration) · enrich ด้วย IAM role assumption tracking
04 · P2 Detections

3 ตัวสำหรับ medium priority

Daily report ส่ง security team · ไม่ต้อง real-time · ใช้ trend analysis เป็นหลัก

D4 P2 MEDIUM UC2 · Crypto Posture

🟡 Quantum-Vulnerable Algorithm Active

Logic: TLS handshake ที่ negotiate RSA-1024, SHA-1, RC4, DES, TLS 1.0/1.1 · ออก list ทุกวัน · ส่งเป็น ticket ให้ system owner ปิด
Required: Zeek ssl.log (cipher + version fields)
SPL · scheduled daily 09:00
index=zeek sourcetype=bro:ssl earliest=-1d@d latest=@d
| eval issue = case(
    match(cipher, "(?i)RC4|DES|MD5|EXPORT|NULL"), "weak_cipher",
    match(version, "TLSv10|TLSv11|SSLv3"), "weak_version",
    match(cipher, "RSA_WITH"), "non_PFS",
    1=1, "ok")
| where issue != "ok"
| stats count, values(issue) as issues, latest(_time) as last
  by id.resp_h, server_name, cipher, version
| eval last_seen = strftime(last, "%Y-%m-%d %H:%M")
| lookup asset_cmdb.csv ip as id.resp_h OUTPUT business_unit, owner
| sort -count
Tuning: output เป็น weekly Crypto Drift Report · auto-create JIRA ticket per business_unit · trend chart panel ใน dashboard
D8 P2 MEDIUM UC1 + UC3 · Staging Signal

🟡 Unusual Process Loading Crypto Library

Logic: bcrypt.dll, ncrypt.dll, libcrypto.so ถูก load โดย process ที่ไม่ใช่ browser/service ปกติ = อาจเป็น custom encryptor
Required: CrowdStrike ImageHash event · lookup known_crypto_consumers.csv
SPL · scheduled every 4h
index=crowdstrike event_simpleName=ImageHash
  (ImageFileName="*bcrypt.dll" OR ImageFileName="*ncrypt.dll"
   OR ImageFileName="*libcrypto*" OR ImageFileName="*libssl*")
| stats count, values(ImageFileName) as libs, values(UserName) as users
  by ComputerName as host, ParentBaseFileName as parent
| lookup known_crypto_consumers.csv process as parent OUTPUT is_known
| where isnull(is_known)
| where parent NOT IN ("chrome.exe","firefox.exe","svchost.exe","msedge.exe",
                       "outlook.exe","teams.exe","slack.exe")
| sort -count
Tuning: สร้าง known_crypto_consumers.csv จาก baseline 14 วัน · whitelist business apps (SAP, banking client, internal tools)
D10 P2 MEDIUM UC1 · Visibility Gap

🟡 TLS Inspection Bypass / QUIC Evasion

Logic: บาง app evade proxy โดย cert pinning หรือ QUIC ที่ proxy decrypt ไม่ได้ · user pump traffic เยอะผ่านช่องนี้ = HNDL covert channel
Required: Zscaler bypass logs หรือ Netskope decryption failure logs
SPL · scheduled every 6h
index=zscaler (action=bypass OR ssl_decrypt_action=no_decrypt)
  AND (reason IN ("cert_pinning","protocol_quic","unknown_protocol"))
| stats sum(bytes_out) as bytes, dc(url) as url_count
  by user, dest_host, reason
| eval mb = round(bytes/1048576, 2)
| where mb > 500
| iplocation dest_host as host
| eval risk = case(
    reason="protocol_quic", "medium",
    match(dest_host,"(?i)(t\.me|telegram|tor|onion|protonmail|signal)"), "critical",
    1=1, "high")
| where risk!="medium"
| sort -mb
Tuning: ใส่ใน visibility gap report รายเดือน · push policy team ปรับ allowed app list · keyword สามารถเพิ่ม anonymizing proxies, cryptocurrency exchanges
05 · P3 Detections

4 ตัวสำหรับ posture tracking

Weekly/monthly report · ใช้ใน dashboard KPI ไม่ส่ง alert · sslyze HEC pipeline

D13 P3 LOW UC2 · Crypto Posture

🔵 Daily Crypto Drift

Logic: Day-over-day diff — endpoint ไหนเปลี่ยน algorithm, key size, cert expiry, weak cipher ใหม่
Required: sslyze JSON via HEC daily · ดู section 06 สำหรับ ingestion pattern
SPL · scheduled daily 06:00
| multisearch
  [search index=cert_inventory sourcetype=sslyze:scan
     earliest=-1d@d latest=@d
   | spath server_scan_results{}.scan_commands_results.ssl_2_0_cipher_suites
   | stats values(cipher_suite) as today_cipher,
            latest(pubkey_size) as today_pksize by hostname]
  [search index=cert_inventory sourcetype=sslyze:scan
     earliest=-2d@d latest=-1d@d
   | stats values(cipher_suite) as yesterday_cipher,
            latest(pubkey_size) as yesterday_pksize by hostname]
| eval drift = case(
    today_cipher!=yesterday_cipher, "cipher_changed",
    today_pksize!=yesterday_pksize, "keysize_changed",
    1=1, "same")
| where drift!="same"
| lookup asset_cmdb.csv hostname OUTPUT business_unit, owner
| table hostname, business_unit, drift, today_cipher, yesterday_cipher
Output: Weekly chart "PQC readiness % over time" — Slack/Teams alert + dashboard panel
D14 P3 LOW UC2 · KPI

🔵 PQC-Readiness Score per Endpoint

Logic: สร้าง score 0-100 ต่อ endpoint จาก sslyze data · เป็น KPI ใน dashboard executive
Required: sslyze JSON · field-level: cipher_list, pubkey_algorithm, pubkey_size, supports_pqc_hybrid
SPL · scheduled daily 08:00
index=cert_inventory sourcetype=sslyze:scan earliest=-1d
| eval score = 100
| eval score = if(match(tls_versions,"TLS_1_0|TLS_1_1|SSL"), score-30, score)
| eval score = if(match(cipher_list,"RSA_WITH|EXPORT|RC4|MD5|3DES"), score-25, score)
| eval score = if(pubkey_algorithm="rsaEncryption" AND pubkey_size<3072,
                  score-20, score)
| eval score = if(pubkey_algorithm="ecPublicKey" AND match(curve,"prime256"),
                  score-15, score)
| eval score = if(supports_pqc_hybrid="true", score+10, score)
| eval score = max(0, min(100, score))
| lookup asset_cmdb.csv hostname OUTPUT business_unit
| stats avg(score) as overall_score, count by hostname, business_unit
| sort score
Output: Dashboard panel "PQC Readiness Heatmap" by business_unit · executive KPI for board reporting
D11 P3 LOW UC2 + UC5 · Vendor Management

🔵 SaaS App with Weak/No PFS Configured

Logic: Netskope/Zscaler มี cloud app cipher info · cloud service ที่ negotiate cipher ไม่มี PFS = ข้อมูลที่ผ่าน app นั้นถ้าถูก harvest = decrypt ได้ทั้ง history
Required: Netskope application metadata
SPL · scheduled weekly Monday 09:00
index=netskope sourcetype="netskope:application:json"
| stats count, values(cipher_suite) as ciphers,
        latest(_time) as last_seen
  by app, app_risk, app_category
| where match(mvjoin(ciphers,","), "(?i)RSA_WITH|TLS_RSA|EXPORT|RC4|3DES")
| eval last_seen = strftime(last_seen, "%Y-%m-%d")
| table app, app_risk, app_category, ciphers, count, last_seen
| sort -count
Output: Vendor PQC pressure list — ส่ง procurement ไปคุยกับ vendor หรือ block app · monthly report
D15 P3 LOW UC1 + UC3 + UC6 · ALL

🔥 Multi-Stage HNDL Kill Chain Risk Score

Logic: รวม signal 3 layers (EDR + CASB + sslyze) · alert เมื่อ host เดียวกันโดน 3 signal ใน 7 วัน · risk_score sum-weighted · นี่คือสิ่งที่ Big 4 ทำไม่ได้
Required: D5 + D9 + D4 results indexed
SPL · scheduled daily 09:30
| multisearch
   [search index=crowdstrike CommandLine="*7z*-p*"
              OR CommandLine="*openssl enc*" earliest=-7d
    | eval signal="edr_staging", weight=3
    | stats max(_time) as last_seen, values(signal) as signals,
            values(weight) as weights by ComputerName as host]
   [search index=zscaler urlcategory IN ("personal_storage","shadow_it")
              earliest=-7d
    | eval gb_up=bytes_out/1073741824
    | stats sum(gb_up) as gb by user
    | where gb>2
    | eval signal="casb_upload", weight=2
    | rename user as host
    | stats max(_time) as last_seen, values(signal) as signals,
            values(weight) as weights by host]
   [search index=cert_inventory sourcetype=sslyze:scan
              earliest=-7d
              cipher_list IN ("*RSA_WITH*","*RC4*","*DES*")
    | eval signal="weak_crypto", weight=1
    | rename hostname as host
    | stats max(_time) as last_seen, values(signal) as signals,
            values(weight) as weights by host]
| stats sum(weight) as risk_score, values(signals) as signals,
        max(last_seen) as last_seen by host
| where risk_score >= 4
| eval last_seen = strftime(last_seen, "%Y-%m-%d %H:%M")
| lookup asset_cmdb.csv hostname as host OUTPUT business_unit, criticality
| sort -risk_score
Output: Weekly executive risk report — multi-signal hosts ที่ต้อง investigate · this is the "killer detection" ที่ขายลูกค้าได้
06 · Macros + Lookups

Splunk macros.conf + lookup tables

Drop-in templates · save ใน $SPLUNK_HOME/etc/apps/ecop_pqc/local/

6.1 macros.conf

macros.conf
# Shannon entropy macro for DNS exfil detection
[shannon_entropy(1)]
args = field
definition = eval _chars=split($field$,"") \
| stats count by _chars \
| eventstats sum(count) as total \
| eval p=count/total, ent=-p*log(p,2) \
| stats sum(ent) as entropy

# PQC vulnerable algorithm regex
[pqc_weak_cipher]
definition = (RSA_WITH|EXPORT|RC4|MD5|3DES|DES_)

# PQC vulnerable TLS versions
[pqc_weak_version]
definition = (TLSv10|TLSv11|SSLv2|SSLv3)

# Foreign ASN whitelist (cloud + business partner)
[trusted_foreign_asn]
definition = asn IN (16509,14618,8075,15169,13335,32934)
# AWS, Azure, Google, Cloudflare, Meta

6.2 Lookup tables (CSV templates)

asset_cmdb.csv

CSV · upload via Splunk Web
ip,hostname,business_unit,criticality,owner,environment
10.1.1.100,bank-app-prod-01,banking_core,critical,team-banking@ecop.co.th,production
10.1.1.101,bank-app-prod-02,banking_core,critical,team-banking@ecop.co.th,production
10.2.1.50,hr-portal-01,hr,medium,team-hr@ecop.co.th,production
10.3.1.10,build-server-01,it_ops,low,team-devops@ecop.co.th,development

business_partner_asn.csv

CSV
asn,partner,relationship
16509,aws,cloud_provider
8075,microsoft_azure,cloud_provider
15169,google_cloud,cloud_provider
13335,cloudflare,cdn
14618,aws_alt,cloud_provider
32934,meta,saas_partner

known_crypto_consumers.csv

CSV
process,is_known,notes
chrome.exe,yes,web browser
firefox.exe,yes,web browser
msedge.exe,yes,web browser
outlook.exe,yes,email client
teams.exe,yes,communications
slack.exe,yes,communications
svchost.exe,yes,windows service host
java.exe,yes,java runtime (review case by case)
python.exe,yes,python runtime (review case by case)
node.exe,yes,nodejs runtime

authorized_key_readers.csv

CSV
process,is_authorized,notes
ssh.exe,yes,ssh client
sshd,yes,ssh daemon
ssh-agent,yes,key agent
terraform,yes,iac tool
ansible-playbook,yes,config mgmt
git.exe,yes,version control with ssh
nginx,yes,web server reads cert
apache2,yes,web server reads cert
haproxy,yes,load balancer
openssl,yes,crypto tooling

6.3 savedsearches.conf (5 example schedules)

savedsearches.conf
[D1 - HNDL Egress Volume Anomaly]
search = # paste D1 SPL here
cron_schedule = 5 * * * *
dispatch.earliest_time = -1h
dispatch.latest_time = now
is_scheduled = 1
alert.severity = 5
action.email = 1
action.email.to = soc@ecop.co.th
action.email.subject = [PQC-P0] HNDL Egress Anomaly $result.host$

[D5 - Crypto Staging Upload]
search = # paste D5 SPL here
cron_schedule = */5 * * * *
is_scheduled = 1
alert.severity = 5
action.script = 1
action.script.filename = create_incident.py

[D13 - Daily Crypto Drift]
search = # paste D13 SPL here
cron_schedule = 0 6 * * *
dispatch.earliest_time = -1d@d
dispatch.latest_time = @d
is_scheduled = 1
action.email = 1
action.email.to = crypto-team@ecop.co.th

[D14 - PQC Score Daily]
search = # paste D14 SPL here
cron_schedule = 0 8 * * *
is_scheduled = 1
# no email - feeds dashboard only

[D15 - Multi-Stage Kill Chain]
search = # paste D15 SPL here
cron_schedule = 30 9 * * *
is_scheduled = 1
alert.severity = 4
action.email = 1
action.email.to = soc-mgmt@ecop.co.th, ciso@ecop.co.th
action.email.subject = [PQC-Weekly] Multi-Stage HNDL Kill Chain
07 · Dashboard Outline

Splunk Dashboard — 2 หน้า

XML Studio outline · panel layout · drag-drop import ได้

Dashboard 1: "PQC Risk Operations"

PanelSourceVisualizationPosition
HNDL Kill Chain alertsD15Single value + sparklineTop-left
Top 10 risky hosts (volume)D1Bar chartTop-right
Top 10 risky users (CASB upload)D9Bar chartMid-left
Long-lived foreign TLS sessionsD2Table (live, top 20)Mid-right
Crypto staging events (real-time)D5Table (last 24h)Bottom-left
KMS access spikeD12Line chart (24h)Bottom-right

Dashboard 2: "Crypto Posture KPI"

PanelSourceVisualizationAudience
PQC Readiness Score trend (30d)D14Line chartCISO / board
PQC Score heatmap by business_unitD14Heat mapEngineering managers
Daily Crypto Drift countD13Single value + deltaCrypto team
Weak Cipher endpoints (current)D4Table with owner columnSystem owners
SaaS vendor PFS gapD11Bar chart with risk scoreProcurement / vendor mgmt
Vulnerable algorithm trend (90d)D4 statsStacked areaCrypto team

Dashboard XML skeleton (Studio format)

dashboard XML
<form theme="dark" version="1.1">
  <label>PQC Risk Operations</label>
  <description>Real-time HNDL detection · refresh every 5m</description>
  <fieldset>
    <input type="time" token="tr">
      <label>Time range</label>
      <default><earliest>-24h</earliest><latest>now</latest></default>
    </input>
  </fieldset>
  <row>
    <panel>
      <title>Multi-stage HNDL alerts (D15)</title>
      <single>
        <search>
          <query>| inputlookup d15_results.csv | where risk_score>=4 | stats count</query>
          <earliest>$tr.earliest$</earliest>
          <latest>$tr.latest$</latest>
        </search>
        <option name="colorBy">value</option>
        <option name="rangeColors">["0x65a637","0xf7bc38","0xd93f3c"]</option>
        <option name="rangeValues">[1,5]</option>
      </single>
    </panel>
    <!-- repeat for D1, D9 etc -->
  </row>
</form>
08 · Sprint Plan

4-week onboarding — engineer ทำได้คนเดียว

0.5-1 FTE detection engineer · ~80-100 ชม. · ผลลัพธ์: 15 detection + 2 dashboard live

WK 1 Foundation

  • Onboard Zeek logs ที่ 1-2 critical segment (DMZ + internal-egress)
  • Validate bro:conn / bro:ssl ingestion ใน Splunk
  • Install CIM + TA-bro / TA-crowdstrike
  • สร้าง asset_cmdb.csv + business_partner_asn.csv
  • เปิด baseline saved search รัน 30 วันย้อนหลัง (warm-up data model)

WK 2 P0 Detections

  • Deploy D1 (HNDL Egress) + D4 (Weak Cipher) — tune 7 วัน
  • Deploy D5 (Crypto Staging) + D6 (Private Key Read) — CrowdStrike data
  • เก็บ false positive log → update whitelist
  • Setup email/Slack alerting + SOAR integration

WK 3 P1 + DNS

  • เพิ่ม DNS log + D7 (DNS exfil)
  • Deploy D2 + D3 (JA3) — subscribe abuse.ch feed
  • Deploy D9 (CASB Upload) + D12 (KMS)
  • เริ่ม Dashboard 1 "PQC Risk Operations" skeleton

WK 4 P2/P3 + Polish

  • Deploy D8 (Crypto DLL), D10 (TLS bypass), D11 (SaaS PFS)
  • Setup sslyze cron + HEC ingestion
  • Deploy D13 + D14 + D15 (multi-stage)
  • Finalize Dashboard 2 "Crypto Posture KPI" → present to CISO
  • Document tune-log + handoff playbook

Acceptance criteria เมื่อจบ Sprint 4

Beyond Sprint 4 — continuous improvement

คัดลอกแล้ว