Ken
Ken CTO of Canis Automotive Labs

Introducing the CANHack toolkit

For the last few weeks we’ve been developing the CANHack toolkit for CAN protocol hacking. It’s a portable bit-banging library to emulate the minimal parts of the CAN protocol required for hacking a CAN bus. This toolkit is a proof-of-concept to show how various attacks on the CAN bus can be done purely in software if a microcontroller can be hijacked (we’ve not addressed how the hijacking could occur: it might be as simple as reflashing the firmware on an OBD-II dongle that an attacker owns, or something more complex like an exploit of a buffer overrun in a diagnostic messaging stack).

In most situations a microcontroller’s on-chip CAN controller is connected to a CAN transceiver and through this transceiver to the CAN bus. If the microcontroller can be hijacked then in general the pins allocated to the CAN controller can be re-purposed as GPIO pins. The CANHack toolkit has minimal assumptions about the environment, which are implemented in target-specific code that wraps the library. The basic requirements are:

  • Access to CAN RX and CAN TX as GPIO pins
  • Access to a timer to read the elapsed clock cycles (typically a free-running counter)
  • Interrupts are disabled around key operations (the code spins on the timer waiting for events)

This can be ported to pretty much anything fast enough to bit-bang CAN (a Cortex M0 at 48MHz is probably too slow, but an ESP32 should be fast enough). The only other hardware requirement is that a CAN transceiver is connected to two GPIO pins.

We’ve ported CANHackfirst to the PyBoard v1.1. This is a board using the STM32F405 microcontroller, which has a Cortex M4 CPU running at 168MHz. We’ve customized the MicroPython firmware to wrap the toolkit and make it available via a MicroPython API. MicroPython is a great platform for CAN hacking: all kinds of scenarios can be scripted up. We’ve included the Python wrappers in the CANHack respository.

The test rig is a card designed by Canis Automotive Labs that has a header 9-pin D-sub cable with standard CAN connector: this is the standard used by most bus analyzers and it makes it very easy to prototype a CAN bus using 10-way ribbon cable, with simple plugs at either end for bus termination.

The MicroPython API is provided as a class called CANHack that allows a CAN frame to be defined and various attacks to be mounted against traffic on the bus.

The toolkit is initialized with an instance of the CANHack class:

1
>>> ch = CANHack()

This sets up the CAN TX pins and sets a default baud rate (500kbit/sec). The pins B8 and B9 are used (this is CAN1 on the PyBoard’s STM32F405). A different CAN bit time can be selected with the bit_time parameter:

1
>>> ch = CANHack(bit_time=CANHack.KBIT_125)

The parameters of the CAN frame are specified by calling set_frame:

1
>>> ch.set_frame(0x14)

This call pre-computes the bitstream of the CAN frame (it has a C implementation very similar to the Python CAN calculator).

Identifiers default to standard IDs. Extended IDs can be set with the extended parameter:

1
>>> ch.set_frame(0x14, extended=True)

Remote frames can be set by the remote parameter.

Once the CAN frame parameters have been set the toolkit can be used to attack a frame matching the parameters. There is also a method to transmit the frame on the bus, which is very useful to test that everything has been wired up properly. The payload of the CAN frame can be set with the data parameter, and the frame is set with the send_frame method:

1
2
>>> ch.set_frame(0x14, data=bytes([1]))
>>> ch.send_frame()

This is the trace on the CAN RX and TX pins of the PyBoard:

CAN RX and TX trace

The trace is produced by the Digilent Analog Discovery 2 USB scope (it has 8 channels of digital inputs and the software has a CAN protocol decoder). Notice that the ACK field is transmitted dominant. The CANHack toolkit does this so that a protocol decoder on the bus with just the transmitter won’t treat this as an ACK failure and expect the transmitter to send an error frame. In the test setup used to produce this there were other boards connected to CAN that anyway asserted a dominant bit in the ACK field. But this illustrates the power of bit-banging CAN: the protocol can be changed to do what we want.

The Bus-Off Attack is one of the simplest attacks on the CAN protocol. The idea is to target a specific device that’s transmitting and then generate error frames when that frame emerges so that the Transmit Error Counter (TEC) in the targeted device exceeds the bus-off threshold. Various follow-up attacks are then possible, including doing nothing (knocking a device off-line is a denial-of-service attack all by itself) and stepping in to emulate the missing device by spoofing its frames. The attack was published in 2016 by Kyong-Tak Cho and Kang G. Shin (PDF).

The attack can be run on the PyBoard with CANHack by first setting a CAN frame with the ID we wish to attack:

1
>>> ch.set_frame(0x123)

This will attack a frame with standard ID 0x123. We mount the attack by calling the error_attack method. This waits to see a frame with the set ID and then injects an error frame. It will stimulate further errors by injecting an error frame into the error delimiter, causing error recovery to repeat. The repeat parameter indicates the number of times an error frame is injected. For example:

1
>>> ch.error_attack(repeat=3)

results in this trace:

CAN RX and TX trace

The transmitter will have seen a total of four errors while transmitting and its TEC will have increased by 31 (8 for each attack less 1 for a successful transmission). When it exceeds 255 it will go bus-off.

An attack of 32 repeats is sufficient to drive any transmitter bus off. For example:

1
>>> ch.error_attack(repeat=32)

gives this trace:

CAN RX and TX trace

CAN RX and TX trace

But attacking a transmitter directly in one go is not the best approach: receivers will have their Receive Error Counter (REC) incremented too and might be pushed error passive. It is probably best to attack a transmitter over time, incrementing TEC gradually so that the disruption to the bus is minimized (particularly if there is an intrusion detection system on the bus).

A CANHack toolkit demo video shows spoofing and bus-off attacks. It also shows the toolkit used for three new unpublished CAN protocol attacks:

  • The Double Receive Attack
  • The Freeze Doom Loop Attack
  • The Janus Frame Attack

These new attacks will be written up in their own blog posts.

UPDATE: 22-01-2020

See also the CANT bit-banging CAN toolkit for the Nucleo-H743ZI2 board that also can do low level attacks on the CAN protocol (H/T @ehntoo).

comments powered by Disqus