Scapy CAN-Layer#

The Scapy can-layer is a module within the Scapy packet manipulation tool that provides support for Controller Area Network (CAN) protocol. It allows users to craft, dissect, and manipulate CAN frames and packets. The can-layer is built on top of the Scapy’s core packet manipulation capabilities, providing a set of functions and classes for interacting with the CAN protocol. It allows the user to create and parse packets, set and get properties of the packets, and perform other common packet manipulation tasks. The can-layer also supports extended frame format and provides a way to define custom filters to select specific packets. The Scapy can-layer is a powerful tool for security researchers, developers, and penetration testers working with CAN-based systems as it allows them to easily automate and analyze CAN traffic.

Scapy CAN Frames#

  • Load the CAN layer in Scapy

from scapy.all import *

load_layer("can")
  • Create a CAN frame

frame = CAN(flags='extended', identifier=0x10010000, length=8, data=b'\x01\x02\x03\x04\x05\x06\x07\x08')
frame.show()
hexdump(frame)
###[ CAN ]###
  flags     = extended
  identifier= 0x10010000
  length    = 8
  reserved  = 0
  data      = b'\x01\x02\x03\x04\x05\x06\x07\x08'

0000  90 01 00 00 08 00 00 00 01 02 03 04 05 06 07 08  ................

Scapy CANSockets#

  • Scapy provides two types of Sockets

    • NativeCANSocket: Uses SocketCAN underneath. Requires Linux and Python3. Scapy NativeCANSocket objects are part of Scapy library that provide a way to interact directly with the CAN bus using the native socket interface of the operating system.

    • PythonCANSocket: Uses python-can underneath. Runs on Linux, Windows and OSX with Python2 and Python3. Scapy emulates the socket behavior similar to SocketCAN. Scapy PythonCANSocket objects are a part of the Scapy library that provide a way to interact with the CAN bus using the Python-CAN library.

  • Use NativeCANSocket

conf.contribs['CANSocket'] = {'use-python-can': False} # default
load_contrib('cansocket')

socket = CANSocket(channel='vcan0')
  • Use PythonCANSocket

conf.contribs['CANSocket'] = {'use-python-can': True}
load_contrib('cansocket')

socket = CANSocket(bustype='socketcan', channel='vcan0')
  • Send CAN frame

packet = CAN(identifier=0x123, data=b'01020304')
socket.send(packet)
16
  • Receive CAN frame

rx_packet = socket.recv()
rx_packet.show()
###[ CAN ]###
  flags     = 
  identifier= 0x123
  length    = 5
  reserved  = 0
  data      = b'"\x11\xaa\xbb\xcc'
  • Sniff 10 CAN frames

pkts = socket.sniff(timeout=5, count=10)
print(pkts)
pkts[0].show()
<Sniffed: TCP:0 UDP:0 ICMP:0 Other:10>
###[ CAN ]###
  flags     = 
  identifier= 0x68f
  length    = 8
  reserved  = 0
  data      = b'>\x82&]L\xd3\tG'

Read and write pcap files#

Examplefile download: ECU_Trace.pcap.gz

x = CAN(identifier=0x7ff,length=8, data=b'\x01\x02\x03\x04\x05\x06\x07\x08')
wrpcap('/tmp/scapyPcapTest.pcap', x, append=False)
pkts = rdpcap('/tmp/scapyPcapTest.pcap', 1)

pkts[0].show()
###[ CAN ]###
  flags     = 
  identifier= 0x7ff
  length    = 8
  reserved  = 0
  data      = b'\x01\x02\x03\x04\x05\x06\x07\x08'

Read candump logfile#

  • Treat logfile as socket

with CandumpReader("candump.log") as sock:
    can_msgs = sniff(count=50, opened_socket=sock)
    
print(len(can_msgs))
50
  • Read entire logfile

can_msgs = rdcandump("candump.log")
print(len(can_msgs))
100