ข้ามไปยังเนื้อหา
กลับไปหน้าบทความ
ความปลอดภัยเครือข่าย

STIX และ TAXII คืออะไร แชร์ Threat Intelligence ให้เครื่องอ่านได้

อธิบาย STIX 2.1 และ TAXII 2.1 ผ่านการประกอบ bundle ทีละขั้น พร้อม Pyramid of Pain ที่บอกว่าทำไม intel ระดับพฤติกรรมทำให้ผู้โจมตีเสียต้นทุนมากกว่า IP และ hash

ขั้นสูง10 นาทีในการอ่าน

ในบทความนี้

พวกเราส่วนใหญ่เจอ threat intelligence ครั้งแรกในรูปของรายการ: IP address หลายพันรายการ, domain จำนวนหนึ่ง, คอลัมน์ SHA-256 hash หรืออาจเป็นไฟล์ CSV แนบมากับอีเมล เราโหลดเข้า firewall หรือ SIEM แล้ว alert ก็เด้งขึ้นมาบ้าง แต่ผ่านไปหนึ่งเดือนก็ไม่มีใครตอบได้ว่ารายการไหนยังสำคัญอยู่ ใครเป็นคนส่งมา หรือทำไมมันถึงอันตรายตั้งแต่แรกครับ

โพสต์นี้พูดถึงอีกวิธีหนึ่ง เราจะสร้าง threat intelligence ชิ้นเล็ก ๆ ที่เครื่องอ่านได้ทีละขั้นด้วย STIX 2.1 ส่งมันผ่าน TAXII 2.1 และใช้ Pyramid of Pain ของ David Bianco อธิบายว่าทำไมส่วนที่มีค่าที่สุดของแพ็กเกจนี้ไม่ใช่ IP address ครับ

สัญญาณเดี่ยว ๆ เป็นแค่จุด เมื่อเชื่อมเข้ากับบริบท มันจึงกลายเป็นภาพที่เอาไปลงมือทำได้

Data, information, intelligence

Guide to Cyber Threat Information Sharing (SP 800-150) ของ NIST เป็นจุดเริ่มต้นที่ดีสำหรับการจัดศัพท์ให้ตรงกัน เอกสารนี้เรียก threat information ว่าเป็นข้อมูลใดก็ได้ที่ช่วยให้องค์กร identify, assess, monitor และ respond ต่อภัยไซเบอร์ได้ และแยกย่อยออกเป็นหลายประเภท (ฉบับเต็ม ส่วนที่ 2):

  • Indicators: artifact หรือ observable ทางเทคนิคที่บ่งชี้ว่าการโจมตีกำลังจะเกิด กำลังเกิดอยู่ หรือเกิดขึ้นไปแล้ว ตัวอย่างในเอกสารคือ IP address ของ command-and-control server ที่ต้องสงสัย, domain ที่น่าสงสัย, URL ที่ชี้ไปยังเนื้อหาอันตราย, file hash หรือหัวเรื่องของอีเมลอันตราย
  • TTPs (tactics, techniques and procedures): คำอธิบายว่าผู้โจมตีมีพฤติกรรมอย่างไร
  • Security alerts, threat intelligence reports และ tool configurations

แล้วก็มีประโยคที่ผมชอบที่สุด: threat intelligence คือ threat information ที่ผ่านการ "aggregated, transformed, analyzed, interpreted, or enriched" เพื่อให้มีบริบทพอสำหรับการตัดสินใจ IP address หนึ่งตัวคือ data ส่วน "IP นี้โผล่ใน proxy log ของเรา" คือ information และ "IP นี้เป็นช่องทาง command ของ malware ตระกูลหนึ่งที่มากับ spearphishing attachment เรามั่นใจ 70% และควร block ถึงสิ้นเดือนนี้เท่านั้น" คือ intelligence เนื้อหาที่เหลือของโพสต์นี้คือการเขียนประโยคสุดท้ายนั้นในแบบที่เครื่องอ่านได้ครับ

เอกสาร NIST ฉบับเดียวกันยังบอกว่า indicator ที่ดีควรเป็นอย่างไร: timely, relevant, accurate, specific และ actionable จำห้าคำนี้ไว้ เพราะ STIX ส่วนใหญ่มีไว้เพื่อแบกบริบทที่ทำให้ indicator ผ่านเกณฑ์เหล่านี้ครับ

Pyramid of Pain

ในเดือนมีนาคม พ.ศ. 2556 David Bianco เผยแพร่ The Pyramid of Pain ภาพง่าย ๆ ที่จัดอันดับประเภทของ indicator ตามระดับความเจ็บปวดที่ผู้โจมตีได้รับเมื่อเรา detect และปฏิเสธมันได้ ต่อมาในการปรับปรุงเดือนมกราคม พ.ศ. 2557 เขาเพิ่มชั้น hash ไว้ที่ฐาน จากฐานขึ้นไป พร้อม label ในภาพฉบับปัจจุบันของเขา:

ระดับ ความเจ็บปวดของผู้โจมตี
Hash values Trivial
IP addresses Easy
Domain names Simple
Network/host artifacts Annoying
Tools Challenging
TTPs Tough!

เหตุผลของเขาตามได้ไม่ยาก เปลี่ยนไฟล์แค่หนึ่ง bit แล้ว hash ก็เปลี่ยนไปทั้งหมด ผู้โจมตีที่มีความสามารถพอสมควรเปลี่ยน IP address ได้ทุกเมื่อที่ต้องการโดยแทบไม่ต้องออกแรง domain มีต้นทุนมากขึ้นอีกนิดเพราะต้องจดทะเบียนและหา hosting ส่วนบนยอด ถ้าเรา detect และ respond ต่อ พฤติกรรม ได้ (ตัวอย่างของเขาคือ Pass-the-Hash) ผู้โจมตีจะต้องเรียนรู้วิธีทำงานแบบใหม่ ซึ่งเป็นสิ่งที่แพงที่สุดที่เราบังคับให้เขาทำได้ครับ

พีระมิดของ Bianco เติมจากฐานที่เปลี่ยนได้ถูก ๆ ขึ้นไปยังยอดที่เปลี่ยนได้แพง

บทเรียนเชิงปฏิบัติมีสองข้อ ข้อแรก feed ที่มีแค่สองชั้นล่างสุดจะต้องวิ่งแข่งกับผู้โจมตีตลอดเวลา ดังนั้นวันหมดอายุและบริบทสำคัญกว่าปริมาณ ข้อสอง ส่วนที่มีค่าของรายงานที่แชร์กันมักเป็นตัวเชื่อมจาก indicator ราคาถูกไปยังพฤติกรรมราคาแพง และ STIX ทำให้ตัวเชื่อมนั้นมีรูปร่างที่ชัดเจนครับ

ประกอบ STIX 2.1 bundle ทีละชิ้น

STIX 2.1 เป็นมาตรฐานของ OASIS เป็นภาษาบน JSON สำหรับ "cyber threat and observable information" มี STIX Domain Object (SDO) 18 ชนิด เช่น Indicator, Malware, Attack Pattern, Threat Actor และ Vulnerability บวก relationship object (SRO) อีกสองชนิด คือ Relationship แบบทั่วไปและ Sighting ทุก object มี id ที่ประกอบด้วยชื่อ type, ขีดสองตัว และ UUID เช่น indicator--8e2e2d2b-… และ spec_version ต้องเป็น "2.1"

มาสร้างเรื่องเล็ก ๆ กันครับ ค่าทั้งหมดข้างล่างนี้สมมติขึ้นสำหรับโพสต์นี้ IP มาจาก 203.0.113.0/24 ซึ่งเป็น block ที่สงวนไว้สำหรับเอกสาร และไม่ควรปรากฏบนอินเทอร์เน็ตสาธารณะ

ขั้นที่ 1: indicator

Indicator เก็บ pattern สำหรับ detection field ที่บังคับเฉพาะของมันคือ pattern, pattern_type และ valid_from ตัว pattern จะเขียนด้วย STIX Patterning หรือภาษาอื่นอย่าง Snort หรือ YARA ก็ได้ โดย pattern_type บอกว่าเป็นภาษาไหน

{
  "type": "indicator",
  "spec_version": "2.1",
  "id": "indicator--5f6b8c1e-3a8d-4f7e-9b62-0d1c2e3f4a5b",
  "created": "2026-10-20T08:00:00.000Z",
  "modified": "2026-10-20T08:00:00.000Z",
  "name": "C2 address for example loader",
  "indicator_types": ["malicious-activity"],
  "pattern": "[ipv4-addr:value = '203.0.113.45']",
  "pattern_type": "stix",
  "valid_from": "2026-10-20T08:00:00Z",
  "valid_until": "2026-11-20T08:00:00Z",
  "confidence": 70
}

มีสอง field ที่ตอบคำถามซึ่ง CSV เปล่า ๆ ตอบไม่ได้ valid_until คือเวลาที่ indicator "should no longer be considered a valid indicator" ถ้าไม่ใส่ไว้ก็แปลว่าไม่มีวันหมดอายุเลย ส่วน confidence เป็นจำนวนเต็มตั้งแต่ 0 ถึง 100 ที่บอกว่าผู้สร้างมั่นใจแค่ไหนครับ

ขั้นที่ 2: malware และ "indicates"

Malware object อธิบาย malware ตระกูลหนึ่งหรือตัวอย่างหนึ่ง ตัวเชื่อมระหว่างสอง object คือ Relationship ที่มี relationship_type เป็น indicates ซึ่ง spec นิยามว่า "the Indicator can detect evidence of" เป้าหมาย

{ "type": "malware", "spec_version": "2.1",
  "id": "malware--0c7b5e1a-2f4d-4a8b-9e3c-6d5f4a3b2c1d",
  "created": "2026-10-20T08:00:00.000Z", "modified": "2026-10-20T08:00:00.000Z",
  "name": "Example Loader", "is_family": true }

{ "type": "relationship", "spec_version": "2.1",
  "id": "relationship--7a1e2d3c-4b5a-4f6e-8d7c-9b0a1e2d3c4b",
  "created": "2026-10-20T08:00:00.000Z", "modified": "2026-10-20T08:00:00.000Z",
  "relationship_type": "indicates",
  "source_ref": "indicator--5f6b8c1e-3a8d-4f7e-9b62-0d1c2e3f4a5b",
  "target_ref": "malware--0c7b5e1a-2f4d-4a8b-9e3c-6d5f4a3b2c1d" }

ขั้นที่ 3: พฤติกรรม และ "uses"

ตอนนี้เราไต่ขึ้นพีระมิด Attack Pattern เป็น TTP ประเภทหนึ่งที่อธิบายว่าผู้โจมตีพยายามเจาะเป้าหมายอย่างไร ตัวอย่างใน spec เองคือ spear phishing ตัว Malware ชี้ไปหามันได้ด้วย relationship แบบ uses ถ้าอยากให้ทุกคนหมายถึงพฤติกรรมเดียวกัน ให้อ้างอิง MITRE ATT&CK ใน external_references MITRE เผยแพร่ ATT&CK ทั้งหมดเป็น STIX 2.1 bundle โดยtechnique และ sub-technique เป็น object แบบ attack-pattern ที่ค้นหาได้ด้วย external_id เรื่องของเราใช้ T1566.001 Spearphishing Attachment ภายใต้ tactic Initial Access

{ "type": "attack-pattern", "spec_version": "2.1",
  "id": "attack-pattern--3d2c1b0a-9e8f-4a7b-8c6d-5e4f3a2b1c0d",
  "created": "2026-10-20T08:00:00.000Z", "modified": "2026-10-20T08:00:00.000Z",
  "name": "Spearphishing Attachment",
  "external_references": [{ "source_name": "mitre-attack", "external_id": "T1566.001" }] }

บวก relationship อีกหนึ่งตัว: malware --uses--> attack-pattern IP ในขั้นที่ 1 จะเปลี่ยนในไม่ช้า แต่ตัวเชื่อมนี้จะไม่เปลี่ยน และมันบอกผู้อ่านว่าควรไปดูที่ไหนต่อ: mail gateway, การจัดการไฟล์แนบ และการที่ผู้ใช้เปิดไฟล์ครับ

ขั้นที่ 4: sighting

Sighting แปลว่า "ฉันเห็นสิ่งนี้" spec แยกความต่างไว้อย่างระมัดระวัง: Observed Data คือ information ("ฉันเห็นไฟล์นี้") ส่วน Sighting คือการยืนยันเชิง intelligence ("ฉันเห็น threat actor ตัวนี้") field ที่บังคับมีแค่ sighting_of_ref ส่วน count, first_seen, last_seen และ where_sighted_refs เป็น optional และ count ที่เป็น 0 ยังใช้บอกได้ด้วยว่า indicator ไม่ได้ ถูกพบเลย Sighting คือทางที่ intel ไหลกลับไปหาผู้ผลิตครับ

{ "type": "sighting", "spec_version": "2.1",
  "id": "sighting--9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
  "created": "2026-10-22T03:15:00.000Z", "modified": "2026-10-22T03:15:00.000Z",
  "sighting_of_ref": "indicator--5f6b8c1e-3a8d-4f7e-9b62-0d1c2e3f4a5b",
  "count": 3,
  "first_seen": "2026-10-22T01:02:00Z", "last_seen": "2026-10-22T02:47:00Z" }

ขั้นที่ 5: bundle

สุดท้าย ห่อทั้งหมดไว้ใน Bundle: {"type": "bundle", "id": "bundle--…", "objects": [ … ]} มีรายละเอียดหนึ่งที่หลายคนแปลกใจ: bundle "does not have any semantic meaning" และ object ไม่ได้ สัมพันธ์กันเพียงเพราะเดินทางมาด้วยกัน ตัวเชื่อมอยู่ใน relationship object (และใน property ที่อ้างอิงถึง object อื่น เช่น sighting_of_ref ของ sighting) นี่คือเหตุผลที่แพ็กเกจของเรามีหก object: กล่อง SDO/SRO สี่กล่อง บวก relationship อีกสองตัวครับ

bundle ของเรา: relationship object เป็นตัวแบกความหมาย ไม่ใช่ซองที่ห่อ

TAXII 2.1: bundle เดินทางอย่างไร

TAXII 2.1 (OASIS Standard, 10 มิถุนายน พ.ศ. 2564) เป็นโปรโตคอลระดับ application สำหรับแลกเปลี่ยน CTI ผ่าน HTTPS ออกแบบมาเพื่อ STIX แต่ไม่ได้จำกัดอยู่แค่ STIX ส่วนต่าง ๆ ประกอบกันแบบนี้:

  • Discovery: client ส่ง GET /taxii2/ แล้วจะรู้ว่า server มี API Root อะไรบ้าง server ยังประกาศตัวเองผ่าน DNS SRV record ได้ด้วย
  • API Roots: "logical groupings" ของ collection ทำให้ server เดียวมี root แยกสำหรับแต่ละ trust group ได้ แต่ละ root มี access control ของตัวเอง
  • Collections: คลังเชิงตรรกะของ CTI object ดูรายการได้ด้วย GET {api-root}/collections/ และแต่ละ collection บอกว่าเรา can_read และ can_write หรือไม่
  • Objects: GET {api-root}/collections/{id}/objects/ คือการดึง ส่วน POST ไปที่ URL เดียวกันคือการส่งขึ้น เนื้อหาเดินทางอยู่ใน TAXII envelope และทุก request ใช้ media type application/taxii+json;version=2.1

รายละเอียดที่มีประโยชน์อยู่ฝั่งการดึง filter อย่าง ?match[type]=indicator,sighting ช่วยกรองผลลัพธ์ สำหรับการ poll added_after ใช้ขอ object ที่ถูกเพิ่มหลังเวลาหนึ่ง และ spec เน้นว่าเวลานี้คือเวลาที่ object ถูกเพิ่มเข้า server ไม่ใช่วันที่ใด ๆ ภายใน STIX object ผลลัพธ์ขนาดใหญ่มาเป็นหน้า ๆ: flag more ใน envelope บอกว่ายังมีอีก และ client ไปต่อด้วย next หรือด้วย header X-TAXII-Date-Added-Last

GET /api1/collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/objects/?match[type]=indicator&added_after=2026-10-24T00:00:00Z HTTP/1.1
Host: taxii.example.com
Accept: application/taxii+json;version=2.1

การส่งขึ้นเป็นแบบ asynchronous POST ที่สำเร็จจะได้ 202 Accepted พร้อม status resource แล้ว client ก็ poll {api-root}/status/{status-id}/ จนกว่าจะขึ้นว่า complete spec ยังจองชื่อ Channels (publish-subscribe) ไว้ แต่ยกไปกำหนดในเวอร์ชันถัดไป ในทางปฏิบัติ TAXII 2.1 จึงหมายถึง collection ครับ

การแชร์เกิดขึ้นที่ไหน

ตัวอย่างสองตัวแสดงให้เห็นความหลากหลายครับ

CISA Automated Indicator Sharing (AIS) เป็นบริการที่ไม่มีค่าใช้จ่าย สำหรับ "real-time exchange of machine-readable cyber threat indicators" ระหว่างภาครัฐและเอกชน การเข้าร่วมต้องยอมรับเงื่อนไข มีความสามารถด้าน STIX/TAXII (ใช้ TAXII 2.1 client แบบ open source ได้) มี PKI certificate และทำ interconnection agreement CISA สนับสนุนให้ผู้เข้าร่วมแชร์กลับผ่าน TAXII connection แบบสองทาง ไม่ใช่รับอย่างเดียว

MISP เป็น threat intelligence platform แบบ open source สำหรับเก็บรวบรวม จัดเก็บ และแชร์ indicator มี STIX export เป็นหนึ่งในรูปแบบที่รองรับ และมี taxonomy ของชุมชนที่รวม TLP ไว้ด้วย มีสองฟีเจอร์ที่ควรลอกไปใช้ไม่ว่าจะใช้ platform ไหน แต่ละ event มี distribution level (เฉพาะองค์กรของเรา, community นี้, connected communities, all communities หรือ sharing group ที่ระบุชื่อ) และ attribute มี flag to_ids ที่แยก "indicator ที่ลงมือได้" ออกจาก "บริบทอย่างเดียว" MISP ยังดูแล warninglists ซึ่งเป็นรายการค่าที่รู้จักกันดีและมีแนวโน้มเป็น false positive: public DNS resolver, ช่วง IP ของ CDN, อันดับเว็บไซต์ยอดนิยม และช่วง private ของ RFC 1918

ฝั่งผู้ใช้ SIEM ก็พูดโปรโตคอลเดียวกัน ตัวอย่างเช่น Microsoft Sentinel มี TAXII data connector ที่ดึงจาก TAXII 2.0 หรือ 2.1 server เมื่อใส่ API root URL และ collection ID และมี export connector สำหรับ TAXII 2.1

จาก intel สู่การลงมือ โดยไม่ block อินเทอร์เน็ตทั้งก้อน

ตรงนี้คือจุดที่พื้นหลังสาย firewall ทำให้ผมระวังตัว วิธีที่เร็วที่สุดที่จะทำให้คนเลิกเชื่อ threat intel คือ entry แย่ ๆ แค่ตัวเดียว: address ของ CDN, public resolver หรือช่วง IP ของ cloud provider ที่ถูกดันเข้า deny rule ตรง ๆ ข้างล่างนี้เป็นนิสัยของผมเอง ไม่ใช่มาตรฐานครับ

  1. ให้ทุก feed ผ่าน allowlist filter ก่อน warninglists มีอยู่ก็เพราะ feed ที่แชร์กันมี address ยอดนิยมที่ถูกต้องตามปกติปนอยู่จริง ปลายทางสำคัญของเราเอง (identity provider, update server, VPN peer ของพาร์ตเนอร์) ก็ควรอยู่ในรายการนี้ด้วย
  2. ใช้กลไก exception ของ firewall แทนการแก้ feed บน firewall ของ Palo Alto Networks นั้น External Dynamic List นำเข้า IP, domain หรือ URL จาก web server และ refresh ตามรอบเวลาโดยไม่ต้อง commit เอง การตั้งค่า EDL ให้เลือกตรวจหา update ทุกห้านาที (ค่าเริ่มต้น), รายชั่วโมง, รายวัน, รายสัปดาห์ หรือรายเดือน และเพิ่ม manual exception ให้รายการได้
  3. alert ก่อน block เริ่ม feed ใหม่ใน SIEM ในฐานะ detection ก่อน แล้วค่อยย้ายไป block เฉพาะส่วนที่มี confidence สูง มี valid_until และมี sighting สักหนึ่งสองครั้งใน log ของเราเอง
  4. ให้พฤติกรรมเป็นตัวนำการ hunt และให้ indicator แบบ atomic เป็นตัวนำการ block ระยะสั้น attack-pattern ใน bundle ของเราคือเหตุผลให้ทบทวน detection ของอีเมลและ endpoint ส่วน IP คือเหตุผลสำหรับการ block ที่มีวันหมดอายุ

วันหมดอายุ ความมั่นใจ และการจัดการข้อมูล

feed ที่ไม่มีวันหมดอายุจะมีแต่โตขึ้น STIX ให้เครื่องมือสามอย่าง: valid_until บน indicator, revoked: true เมื่อผู้สร้างบอกว่า object นั้นไม่ valid แล้ว (การ revoke เป็นแบบถาวร) และ confidence ตั้งแต่ 0 ถึง 100 ผู้ใช้ควรเคารพทั้งสามอย่าง และผู้ผลิตก็ควรตั้งค่าเหล่านี้ครับ NIST SP 800-150 ยังขอให้ผู้ผลิตมีช่องทางสำหรับ update และถอน indicator ที่ผิดหรือแชร์ออกไปโดยไม่ตั้งใจ

อีกครึ่งหนึ่งคือการจัดการข้อมูล Traffic Light Protocol กำหนดว่าใครรับข้อมูลที่แชร์ได้บ้าง และ "not a formal classification scheme" เวอร์ชันปัจจุบันของ FIRST คือ TLP 2.0 ซึ่งเป็นฉบับอ้างอิงตั้งแต่เดือนสิงหาคม พ.ศ. 2565 มี label สี่แบบ คือ RED, AMBER, GREEN และ CLEAR โดย AMBER+STRICT จำกัด AMBER ให้แชร์ได้เฉพาะภายในองค์กรผู้รับเท่านั้น รายละเอียดหนึ่งที่ควรตรวจ: TLP marking definition ที่มากับ STIX 2.1 คือ WHITE, GREEN, AMBER และ RED ซึ่งเป็นชื่อ TLP แบบเก่า ดังนั้นตรวจดูว่าเครื่องมือของเรา map ค่าเหล่านี้อย่างไร ก่อนจะพึ่งกฎอัตโนมัติแบบ "แชร์ให้ community" ครับ

ให้ถือว่า marking เป็นส่วนหนึ่งของข้อมูล ถ้า indicator ที่เป็น TLP:AMBER+STRICT ไปโผล่ใน blocklist สาธารณะเพราะเครื่องมือทำ marking หล่นหาย นั่นคือความล้มเหลวในการแชร์ ถึงแม้การ block จะได้ผลก็ตาม

ส่งท้าย

IP address ใน bundle ของเรามีอายุการใช้งานสั้น ๆ แต่มีประโยชน์ ส่วน relationship ที่บอกว่า loader ตัวนี้ใช้ spearphishing attachment จะยังมีประโยชน์อยู่อีกหนึ่งปีข้างหน้า STIX ทำให้ relationship นั้นมีรูปร่าง TAXII พามันข้ามองค์กร และ field อย่าง valid_until, confidence และ TLP marking ช่วยให้มันยังซื่อตรงเมื่อไปถึงปลายทาง ถ้าจะสร้างนิสัยเดียวจากโพสต์นี้ ขอให้เป็นข้อนี้: อย่า import indicator ที่เราอธิบายไม่ได้ครับ

แหล่งอ้างอิง

อ่านต่อ