1-616-874-7810 info@vdalabs.com

At VDA Labs we cover a wide berth of technologies and are sometimes asked to do unique engineering tasks. You also might have noticed that we are big fans of fuzzing as a means of finding bugs. Quite often, we are asked to work on technology that requires a learning curve. Recently we were doing some work that required getting better acquainted with the BACnet protocol. This generated a lot of questions: what is BACnet? Does a fuzzer exist for the BACnet protocol already? Is there research on breaking the BACnet protocol?

Why does BACnet exist?

BACnet stands for Building Automation and Control networks. Imagine the late 1980’s: networks are becoming ubiquitous in the American workplace, control systems are beginning the transition to automation, and vendors are creating proprietary protocols for their products. Since proprietary protocols do not offer interoperability, gaining aggregated visibility throughout a networked environment was impossible. Until BACnet!!! The BACnet protocol provides a vendor agnostic method for computerized automation devices to exchange information. BACnet devices answer four main questions via the protocol: ‘Who Is?’, ‘I am’, ‘Who has?’, and ‘I have.’ BACnet became a standard in 1995 and had an immediate impact on the HVAC community. Nowadays, the protocol is widely used internationally for building automation and control systems.

Packet Structure Overlaid onto the OSI model

identifying components of BACnet for fuzzing

Image from bacnetstack.com

Take note of the APDU and NPDU layers, they will become more important later on!

What do BACnet packets look like?

Let’s dig into the details of BACnet packets so we can eventually build a BACnet fuzzer. To get started, VDA set up a client/server BACnet relationship to sniff traffic while in transit. To perform this action we created a virtualized BACnet server with Steve Karg’s BACnet program. The other pieces involved starting a BACnet client in a separate virtual machine to interact with the BACnet server, and Wireshark to visualize this interaction taking place. The BACnet client that was used can be found at http://www.bac-test.com/bacnet-test-client-download/.

Here is our BACnet server running inside a Kali Linux virtual machine.

BACnet example client for fuzzing

This is a BACnet client running inside a Windows 10 virtual machine.

After sending some valid BACnet packets between the two, Wireshark was able to packet capture the Windows 10 BACnet client interacting with the Kali Linux BACnet server. The Windows 10 virtual machine is 192.168.10.129 and the Linux server is 192.168.10.131.

In order to build our BACnet fuzzer, we needed to focus primarily on three parts from this packet capture: the BVLL, the NPDU, and the APDU. For this blog the terms BVLC and BVLL are interchangeable.

The BVLL is responsible for creating a virtual link between BACnet devices. A device will set the BVLL ‘Function’ as either broadcast or unicast. This feature is reminiscent of TCP/IP.

The BVLC ‘Type’ has a value of 0X81. The Type byte of 0X81 is used to indicate that this packet is BVLC data for BACnet/IP. The ‘Function’ parameter can range from 0X01-0X09, 0X0A, and 0X0B. This code determines the purpose of this BACnet packet. 0X0A signifies that this message is used send BACnet/IP traffic to another BACnet device or router. However, the BVLC-Length varies with the Function field. For the purpose of fuzzing BACnet, we will build a model of all 3 parameters and maybe find vulnerabilities.

The NPDU stands for Network Layer Protocol Data Unit. The NPDU sets the version, and priority octets as well as others. Within the NPDU are the NPCI (Network Protocol Control Information), which is followed by the NSDU. Regarding the diagram below, it appears that based on octet containing a one or zero determines the functionality of that octet.

Image from http://www.bacnetwiki.com/wiki/index.php?title=Network_Layer_Protocol_Data_Unit

In the example BACnet packet capture below, the NSDU octet is set to zero, therefore it contains an APDU, which contains the Application Layer parameters.

The final BACnet segment of our Wireshark capture contains the APDU, which is responsible for data flow between BACnet applications. The APDU layer is equivalent to layers 5,6,and 7 of the OSI model. This is the primary part of a BACnet packet that we desire to fuzz test.

The screenshot below is an APDU section from the BACnet packet capture we performed with Wireshark.

building a fuzzer requires identifying the components of the network packet

Building a BACnet Fuzzer with Boofuzz

Having learned enough about the BACnet protocol to get started, we then built a simple network packet fuzzer that targets the BACnet protocol. This would be useful to help dynamically find vulnerabilities in devices that talk BACnet. Boofuzz is the successor to the unsupported/discontinued Sulley Fuzzing Framework. By using Boofuzz, we will save time developing a BACnet fuzzer. Part of the python code is shown below. Our fuzzer uses a basic BACnet packet as a model to start with, and does some very basic instrumentation by checking if the remote target device is still pingable between network fuzz iterations. With more time, the Boofuzz framework could be expanded to interact with a remote debugger to monitor crashes better.

boofuzz fuzzer example for BACnet packets

Our code above starts out by setting the ip address of the BACnet server that is going to be fuzzed. For this kind of fuzzer it is critical that we start with a correctly modeled BACnet packet. The three main chunks of code above should be reminiscent of the BACnet packet capture from Wireshark that we showed you earlier in this blog post. Each field within the BVLC, NPDU, and APDU will be fuzzed, even static values.

The screenshot below shows the fuzzer in the bottom screen and the BACnet server in the top screen. The BACnet fuzzer is randomizing the parameters in order to find a crash in the BACnet protocol.

In conclusion, the Boofuzz framework can be used to quickly create a fuzzer for any network protocol. Our BACnet example from this blog was quickly created in a single afternoon. To summarize what we learned in this blog, capture the client/server relationship in Wireshark, perform deep research on the chosen protocol for fuzzing, and then write a fuzzing program that modifies the correct sections of the packet to find crashes. For more information about Boofuzz see the Boofuzz Github page. To download our simple Boofuzz BACnet fuzzer, visit our Github page. If VDA Labs can help your organization fuzz network protocols, just let us know! We love this stuff!