Skip to content

Instantly share code, notes, and snippets.

@sprout42
Last active August 12, 2021 16:00
Show Gist options
  • Save sprout42/84b0527f5f5e33975e4390c76cbd6fdb to your computer and use it in GitHub Desktop.
Save sprout42/84b0527f5f5e33975e4390c76cbd6fdb to your computer and use it in GitHub Desktop.
GRIMM's 3PO Challenge 2

CAN Bus Reverse Engineering Challenge #2: Find the Door Unlock Message

Prove it! Find the “unlock” message to gain access to the car!

Background:

Unlocking the doors through CAN message injection is the "hello world" of car hacking. Different vehicles have varying numbers of CAN buses, and send different messages on those buses. The number of messages sent on the vehicle bus make it seem overwhelming to identify which message will help you achieve your goal, but if you have physical access to a vehicle you can find the right message by:

  • Start recording CAN message traffic
  • Make the car do the thing
  • Play the recorded CAN messages back to the car and see if you captured the message

Setup:

These setup steps are only necessary if you are doing this on your own computer with your own vehicle and hardware.

NOTE: On GRIMM's 3PO (built from a 2012 Ford Focus) there are 3 CAN buses and they run at different speeds:

  • HS-CAN (High Speed CAN) running at 500Kbps
  • MS-CAN (Medium Speed CAN) running at 125Kbps
  • I-CAN (Infotainment CAN) running at 500Kbps

For the purposes of this challenge the CanCat device is already connected to the correct CAN bus to capture the door unlock message. If trying this on your own vehicle you will need to do some reconnaissance and find out how many CAN buses there are, what their speeds are, and attempt steps in the following section on each bus until you find the message.

  1. Clone the CanCat repo
$ git clone https://github.com/atlas0fd00m/CanCat ~/CanCat
  1. Install the necessary python dependencies (CanCat is currently only python2 compatible)
$ pip2 install ipython pyserial
  1. Connect a CanCat capable device, such as the Macchina M2, to your computer

  2. Update the CanCat device with the CanCat Arduino sketch. This can be done using the Arduino IDE, or if you have arduino-cli installed it can be done with the provided makefile:

$ cd ~/CanCat/sketches
$ make m2
  1. Connect the CanCat device to the MS-CAN bus. On GRIMM's 3PO test bench MS-CAN is clearly labeled. On your own vehicle you will need to identify the wires to connect to.

Step-by-step Instructions:

  1. move to the CanCat directory
$ cd ~/CanCat
  1. Start CanCat, this will start an ipython session that already has a CanCat object called c.
$ ./CanCat.py -p /dev/ttyACM0 -S 125K

The -p option specifies the port that the CanCat is connected to and the -S option specifies the CAN bus speed (in this particular example 3PO's MS-CAN bus runs at 125Kbps).

  1. Get a count of the CAN messages received, this helps to ensure that you are correctly connected to the CAN bus. If you run this command a few times you should see the number of received messages increasing fairly quickly.
In [1]: c.getCanMsgCount()
  1. Get one of the remote keyfobs and get ready to press the unlock button, if doing this challenge remotely, send a message to the 3PO helper be ready to press the unlock button.

  2. CanCat has the ability to place bookmarks, which are useful when trying to isolate an event. The snapshotCanMessages function places a bookmark, pauses until perform your task places a second bookmark after you hit enter. Run this command to set the first bookmark, the "Unlock" string can be anything you want, it is meant to be a way to keep track of what you are testing:

In [2]: c.snapshotCanMessages(“Unlock”)
  1. Press the unlock button on the remote keyfob, or tell the 3PO helper to press the button for you.

  2. After you have seen the door lock cylinder fire, press enter to bookmark the end of your test.

  3. You can view your bookmarks with the printBookmarks function. After running this command you should see two bookmarks named "Start_Unlock" and "Stop_Unlock".

In [3]: c.printBookmarks()
  1. CAN messages that have been recorded can be replayed by indicating which position in the recorded message buffer to start and stop sending messages. This can be done with message indexes or bookmarks. Replay the messages you recorded using the start and stop bookmarks, note that it typically takes longer to replay messages than it does to record them so this can take a little while:
In [4]: c.CANreplay(start_bkmk=0, stop_bkmk=1)
  1. Now it is time to isolate which CAN message causes the doors to unlock. The printBookmarks function also prints the message index of the start and stop bookmarks. Replay the messages again using the message indexes instead (replace the 54924 and 55273 values with the message indexes you see corresponding to the bookmarks you recorded):
In [5]: c.CANreplay(start_msg=54924, stop_msg=55273)
  1. Once you have confirmed that the original message indexes work as expected, start changing the start or stop msg indexes to move them closer to each other. A simple way this is to pick half of the messages to test at a time. Once you narrow the range to around 50 messages or so move onto the next step. An example of how to do this using example start and stop values of 50000 and 56000:
In [6]: # Original msg indexes
In [6]: c.CANreplay(start_msg=50000, stop_msg=56000)

In [7]: # Unlock happened! try just the first half of the messages
In [7]: c.CANreplay(start_msg=50000, stop_msg=53000)

In [8]: # Nothing happened, try just the second half
In [8]: c.CANreplay(start_msg=53000, stop_msg=56000)

In [9]: # Unlock happened! narrow the range more
In [9]: c.CANreplay(start_msg=53000, stop_msg=54500)

In [10]: # Unlock happened! narrow the range more
In [10]: c.CANreplay(start_msg=53750, stop_msg=54500)

In [11]: # Nothing happened, try the other half
In [11]: c.CANreplay(start_msg=53000, stop_msg=53750)
...
  1. Once you have narrowed down the possible set of messages to around 50 or so you can use the interactive replay mode to identify the unlock message. This replay mode will show you the message that will be sent, and then send that message immediately when you hit enter. If the door's unlock the message that caused it was the message that was displayed before you hit enter. Use the final start and stop message indexes you identified in the previous step:
In [20]: c.CANreplay(start_msg=53350, stop_msg=53400, timing=TIMING_INTERACTIVE)
  1. Once you think you have found the correct CAN message that unlocks the doors, you can cancel the CANreplay action by typing n, or CTRL-C. Then try sending the identified message with CANxmit.
In [21]: c.CANxmit(0x123, “0011223344556677”.decode(‘hex’))

Extra Credit:

  • Does the message with the arbitration ID you found above get sent regularly?
  • If it is sent regularly, how does the unlock message differ from the regularly sent message? NOTE: CAN packets with a specific CAN id can be viewed using the printCanMsgs command:
In [25]: c.printCanMsgs(arbids=[0x123])
  • Can you the specific bits that unlock the door?

Result:

During this exercise you should have used some of CanCat’s replay capabilities to discover a message that performs a specific function, in this case, unlocking the car.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment