XXE (XML External Entity) adalah serangan terhadap aplikasi yang mem-parsing XML dari user. Bayangin formulir yang punya kolom ajaib bertuliskan "tempel isi file ini di sini". Kalau mesin pengisi formulirnya nurut, siapa pun yang mengisi kolom itu dengan alamat file rahasia bisa membuat isinya ikut tercetak. Di XML, kolom ajaib itu namanya external entity, dan mesinnya adalah XML parser.
🧪 Tebakan cepat: fitur parser apa yang, kalau dibiarkan aktif, membuka pintu XXE: external entities, komentar XML, atau encoding UTF-8? Tebak dulu, jawabannya ada di bagian "Cara memperbaiki".
Entity: nilai yang ditunjuk
Entity di XML itu seperti singkatan yang nanti diganti nilainya. Yang normal sudah kamu kenal: < diganti jadi <. Yang berbahaya adalah external entity, yang didefinisikan di DTD (Document Type Definition) dan menunjuk ke sebuah file atau URL:
<!ENTITY xxe SYSTEM "file:///etc/passwd">
<!ENTITY xxe ...>mendefinisikan entity bernamaxxe.SYSTEM "file:///etc/passwd"menyuruh parser mengambil isi dari path itu waktu&xxe;dipakai.
Jadi &xxe; bukan lagi teks biasa: dia jadi pintu ke file di server.
Payload klasik: baca file
Di Lab, kirim dokumen ini ke endpoint yang mem-parsing XML:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<foo>&xxe;</foo>
Dengan parser yang masih memproses external entity, langkahnya begini:
- Parser membaca
<!DOCTYPE>dan mendefinisikan entityxxeyang menunjuk kefile:///etc/passwd. - Waktu sampai
&xxe;, parser menggantinya dengan isi file di path itu. - Hasilnya masuk ke response, jadi isi file server bocor ke penyerang.
Tidak ada kode penyerang yang jalan di sini. Yang terjadi: parser menuruti alamat file yang ditunjuk entity, lalu menaruhnya di jawaban. Bagian file:///etc/passwd itulah yang berubah dari sekadar teks jadi sebuah path yang dibaca server.
Varian lain
- XXE menjadi SSRF. Ganti path jadi URL internal, misalnya
SYSTEM "http://169.254.169.254/latest/meta-data/". Parser menembak alamat itu dari dalam server.169.254.169.254adalah metadata internal cloud, jadi serangan ini membuat server meminta data internal atas nama penyerang. - Billion laughs (DoS). Entity yang memanggil entity lain berkali-kali, bersarang makin dalam, sampai teksnya mengembang jadi miliaran karakter dan memori server habis. Tidak ada file yang dibaca, tapi server tumbang.
Cara memperbaiki
Intinya satu: matikan pemrosesan DTD/external entity. Hampir semua aplikasi web tidak butuh DTD. Itu jawaban tebakannya: fitur yang membuka pintu XXE adalah external entities.
// PHP: jangan tambah flag berbahaya. Default PHP 8+ sudah aman.
// Di PHP lama, matikan pemuat entitas eksternal secara eksplisit:
libxml_disable_entity_loader(true);
libxml_disable_entity_loader(true)memblokir pemuat entity eksternal, jadi&xxe;tidak pernah diisi apa-apa. Kata yang dilengkapi di kuis adalahloader.- Di Python, jangan pakai parser bawaan untuk input user. Pakai
defusedxml, yang memblokir DTD dan entity secara default. - Kalau bisa, ganti ke JSON. JSON tidak punya konsep entity eksternal, jadi XXE tidak mungkin terjadi.
Latihan: deteksi pola XXE
Di latihan, kamu menulis isXmlDangerous(xml) yang mengembalikan true kalau sebuah string XML kemungkinan payload XXE. Yang paling menentukan adalah adanya DTD inline (<!DOCTYPE) atau deklarasi entity (<!ENTITY), karena tanpa DTD tidak ada tempat mendefinisikan external entity. Cek secara case-insensitive, karena <!doctype dan <!DOCTYPE sama bahayanya. Contoh: <note><to>Budi</to></note> mengembalikan false, sedangkan <!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]> mengembalikan true.
⚠️ Jebakan yang sering ketemu
- Mengira JSON-only aman otomatis, lalu diam-diam ada endpoint XML. Satu endpoint XML yang terlewat sudah cukup. Audit semua tempat yang menerima XML.
- Menyaring kata, bukan mematikan fitur. Yang benar adalah mematikan DTD di parser, bukan sekadar menolak request yang mengandung tulisan tertentu.
- Mengira
&xxe;perlu kode jahat untuk jalan. XXE tidak menjalankan kode penyerang; dia menyalahgunakan fitur normal parser (resolusi entity). - Lupa kalau format lain pun XML di dalam. File
.docxdan banyak format kantor pada dasarnya ZIP berisi XML, jadi fitur impor file pun bisa kena XXE.
TL;DR: XXE terjadi saat XML parser memproses external entities, yang didefinisikan di DTD lewat <!ENTITY xxe SYSTEM "...">. Entity itu menunjuk ke file (bocor isi file), URL internal (jadi SSRF), atau mengembang eksponensial (billion laughs, DoS). Perbaikannya: matikan DTD/external entity. Di PHP lama pakai libxml_disable_entity_loader(true), di Python pakai defusedxml, dan kalau bisa ganti ke JSON. Deteksi dini: tandai XML yang mengandung <!DOCTYPE atau <!ENTITY, case-insensitive.