Exploring the BACnet Protocol for Fun and Profit

by Teguna

I have one of the greatest jobs in the world working in the field of Operational Technology or "OT."  I define OT as the place where computers meet the physical world, including devices that control and monitor large infrastructures like power grids, water systems, dams, manufacturing plants, and energy pipelines.  OT also includes things as mundane as the computer system in your car, your home alarm system, or thermostats that can be controlled from your phone.  My OT world depends heavily on appliances like historians, SCADA servers, Industrial Control Systems (ICS), Human Machine Interfaces (HMIs), and Programmable Logic Controllers (PLCs).

OT professionals depend on a set of communication protocols that are reliable and easy to use, but severely lacking in security features.  Protocols like Modbus, DNP3, and Ethernet/IP were developed before security was vogue and they focused exclusively on availability without any concern for integrity or confidentiality.  Lately, I've taken a keen interest in a protocol called BACnet.  BACnet stands for "Building Automation and Control Network" and is the communications protocol ubiquitous with Building Automations Systems or "BAS."  If you work in a modern office or industrial building that has HVAC, lighting control, access control, or fire detection systems, then those systems are probably monitored and controlled using a BAS.

Before you blow off the importance of these systems to the overall security picture, please keep in mind that the 2013 Target hack that exposed 40 million debit and credit card accounts started by hacking the store's HVAC system.  Attacks on IT enabled by attacks on OT have become much more popular in recent years because of security flaws that are very common in OT equipment.  Most of us in the OT industry realize we can be the "soft underbelly" of network security.  Expect attacks on OT to become much more common as the demand increases for smart refrigerators, network connected litter boxes, and even Bluetooth and Wi-Fi connected clitoral stimulators.  But I digress...

As with other OT protocols, there are plenty of free or open-source tools that can assist us with exploring BACnet/IP communications to understand how BAS communication works and its inherent security problems.  BACnet/IP is BACnet communications over IP networks, which is different than BACnet MS/TP that typically uses the RS-485 standard for communications.  This article will be an overview of two free tools or exploring BACnet/IP and a discussion of the BACnet protocol itself.  This is probably an excellent time to advise you that this article has been written for educational purposes only.  To use any of the techniques in this article constitutes a thought-crime at a minimum and international terrorism in the most extreme cases.  The contents of this article should never be used by anyone... anywhere... ever.

The first thing we are going to need to explore BACnet is a BACnet device.  This can be accomplished free of charge by visiting Contemporary Controls, creating an account, and downloading their BASemulator.  It is available at the following site: www.ccontrols.com/basautomation/bastools.php

You'll be downloading the entire BAScontrol toolset, which also includes Sedona Application Editor (SAE) for programming Contemporary Controls devices.  You can choose only to install the BASemulator when you run the install program.  The software must be installed on a Windows machine.  For this project, I recommend a VM running Windows 10 and using an "internal only" network.

After you finish the installation, find the BASemulator icon on the desktop or in the Start menu and load the program.  Select the "Start Emulator" button to begin the emulation (the default settings are normally fine).  This will also bring up a web page in your browser.  The default credentials are admin/admin.  What you have just installed is a complete emulation of a BAScontrol22 hardware appliance sold by Contemporary Controls.  Normally a technician would use the BAScontrol22 for control and monitoring of an HVAC or other building automation system.  For our purposes, we have a free software device that emulates BACnet/IP in the same manner as its hardware counterpart.  If you wanted to set up a BACnet hacking lab, you could certainly set up armies of these emulators.

There are a few things we need to do for the purpose of demonstrations later in this article.  In the emulator web interface, select the "System Config" button on the bottom left.  At the top of the "System Configuration" page that pops up, change the "Device Object Name" to "Thermostat" and hit the "Submit" button at the bottom right of the page.  After returning to the main page, select "Restart Controller" on the bottom right side (nothing will appear to happen, but the controller will reset).  Select the "Virtual Points" button in the bottom middle of the page.  Double-click "Virtual Point 1" and bring up the Object Configuration page.  In the middle of the page, change the "Object Name" to "RoomTempSetting" and select "Submit" at the bottom of the page.  Close the window.  Lastly, select the check box under our newly named "RoomTempSetting" on the Virtual Points page.  This will allow you to change the value of 0.000 to 72.000.  After you have changed the value, uncheck the box and close the window.

A few fun facts about BACnet/IP that you will need to know as you play with this protocol:

Let's spin up a Linux machine with Nmap installed (Kali Linux would do just fine) and ensure that it is on the same subnet as our BASemulator machine.  Type the following command:

$ sudo nmap -sU -script bacnet-info -p 47808 192.168.56.0/24

Set the subnet to whatever you're using in your lab or just direct the scan at the IP address of the emulator.  In my case, I used the VirtualBox default internal network for my devices.  Your scan should come back with something like this:

Starting Nmap 7.92 ( https://nmap.org ) at 2022-12-02 21:33 CST
Nmap scan report for 192.168.56.103
Host is up (0.00035s latency).

PORT      STATE SERVICE
47808/udp open  bacnet
| bacnet-info:
|  Vendor ID: Contemporary Control Systems Inc (245)
|  Vendor Name: Contemporary Control Systems, Inc.
|  Object-identifier: 2749
|  Firmware: 3.1.28
|  Application Software: 1.2.28
|  Object Name: Thermostat
|  Model Name: BAScontrol
|_ Description:
MAC Address: 08:00:27:D7:C0:D7 (Oracle VirtualBox virtual NIC)

That is a ton of valuable information from a research perspective, which is why I enjoy this Nmap script quite a bit.  Did you notice that the property of "Object Name" above for the device now has the name "Thermostat" like we assigned earlier?  You should especially take note of the "Object-identifier" and the IP address.  We are going to use both of those to learn even more information after we install BACpypes on our Linux machine.

BACpypes is a BACnet module for Python.  I always keep it in my arsenal because it's freeware and can support anything I want to do in BACnet/IP.  Use the following link for simple instructions to install and configure BACpypes.  Download the git repository to your home directory in Linux for the rest of the examples in this article: bacpypes.readthedocs.io/en/latest/gettingstarted/gettingstarted001.html

Configuring your BACpypes.ini correctly is particularly important, so pay attention to that area of the tutorial.  Our network does not have a BBMD so don't sweat it.  The ~/bacpypes/ samples directory is chock full of useful tools for information gathering on BACnet devices and manipulating BACnet devices.  I think you should explore all of them, but let's cover just a couple.

From your ~/bacpypes directory, type the following command, replacing the IP address with the one you discovered in your earlier Nmap scan:

$ python3 samples/ReadObjectList.py 2749 192.168.56.103

The blabbermouth BACnet device is going to tell you everything.  In this case, you are using the ReadObjectList.py program to get a list of all objects on device instance number 2749 at IP address 192.168.56.103 (both were passed to the program as parameters).  The BASemulator has responded with a complete list of all object types, instance numbers, and object names presently on the device.  In the list, you will see the "object Identifier" enclosed in parentheses.  The object identifier is a combination of the object type and the instance number and we will need it later.  Two stick out because we changed their object names when we set up our emulator:

('device', 2749): Thermostat
('analogValue', 201): RoomTempSetting

Assume for a second that a similar device is servicing an HVAC system in a large office building.  I would expect that the engineer programming the device is going to use descriptive object names in order to identify where the device is (for example, "HVAC Plant BLDG 1234") and what points it monitors ("RoomTempSetting", "ChillWaterTemp", or "OutdoorTemp").  This practice will allow technicians to better service the device during trouble calls.  Object naming makes BACnet/IP a powerful tool for simplifying programming and maintenance, but it also makes reconnaissance against BACnet devices much easier than OT protocols like DNP3 and Modbus.

Let's read some values from the device using BACpypes's ReadWriteProperty.py program:

$ python3 samples/ReadWriteProperty.py

The program will present you with a new prompt: >

Enter the following command:

> read 192.168.56.103 analogValue:201 presentValue

If you followed my instructions earlier, the program should have responded with 72.0 and given you another prompt.  Let's pretend for a second that we are an attacker, and we want to turn up the temperature in the boss's office.  Let's try:

> write 192.168.56.103 analogValue:201 presentValue 88.0

The system responds with "ack" and gives us another prompt.  We were able to write to the point because analogValue is read/write and we can use the "WriteProperty" service to change its properties remotely.  If you repeat our previous read command on the same point, you'll see that that "RoomTempSetting" presentValue has been increased to 88.0.

But what about digital?  Let's choose a random binaryOutput object from our list and execute a read command:

> read 192.168.56.103 binaryOutput:18 presentValue

The system responds with "inactive" and gives us another prompt.  Binary values, as you know, are either "1" or "0", true or false, high or low.  In this device, "inactive" refers to false.  In order to make this point "active" or true, we enter:

> write 192.168.56.103 binaryOutput:18 presentValue active

The system will respond with "ack" and a new prompt.  Repeating the read command from earlier will show that the presentValue property of the binaryOutput:18 object has switched to "active".

I have merely given you a taste of BACnet and I encourage you to explore BACnet more in your own lab.  The BACpypes package has a variety of sample programs that are fun to play with and can be used to learn more about BACnet/IP.  Be sure to use Wireshark and analyze the APDUs that are generated when BACnet devices communicate.  Use the Sedona Application Editor (SAE) from Contemporary Control to program your BASemulator.

Happy hacking!

Sources

1.)  Peter Chipkin.  "BACnet for Field Technicians"  cdn.chipkin.com/assets/uploads/2018/mar/15-19-09-42_Bacnet_For_Beginners2.pdf, 2018

2.)  BACnet International.  "Introduction to BACnet for Building Owners and Engineers"  www.ccontrols.com/pdf/BACnetIntroduction.pdf, 2014

3.)  Jaspreet Kaur, Jerneq Tonejc, Steffen Wendzel, and Michael Meier.  "Security BACnet's Pitfalls"  link.springer.com/content/pdf/10.1007%2F978-3-319-18467-8_41.pdf, 2015

Return to $2600 Index