零成本入門車聯網安全研究

kxliping發表於2021-11-12

對車聯網安全感興趣,但卻沒有實車拿來練手,是一件很可惜的事情。為了解決這個問題,筆者結合自己的車聯網安全實踐經驗,為大家搭建一個高度接近真實車輛的實驗環境。這個環境使用了目前流行的多域架構,實現了包括VLAN、防火牆等真實的安全功能,供大家學習和參考。


域架構

零成本入門車聯網安全研究

對域架構的解釋:

1)本實驗環境實現了兩個經典的通訊域VCU和HU,VCU可以理解為整車控制域,而HU則是資訊娛樂域,兩個域透過乙太網進行通訊;

2)VCU域實現了車身CAN(BDCAN)和自動駕駛CAN(ASCAN),這兩路CAN透過閘道器相連,用來模擬車身CAN報文傳送至自動駕駛模組;

3)HU域實現了儀表CAN(ICCAN)與攝像頭CAN(CAMCAN),它們分別與BDCAN、ASCAN透過乙太網相連,第一路連線(BDCAN -> ICCAN)模擬車身資料在儀表盤上顯示,第二路連線(CAMCAN -> ASCAN)模擬攝像頭採集的資料傳送給自動駕駛模組;

4)第一路連線與第二路連線透過VLAN進行隔離。


車輛功能

透過ICSim[1]模擬車輛功能,ICSim是一個開源的車輛儀表模擬器,該模擬器包含controls和ICSim兩個模組,其中controls負責生成模擬的車輛資料,以CAN報文的方式傳送給虛擬的CAN介面,ICSim從虛擬CAN介面讀取CAN報文,並在儀表上更新對應零件的狀態,如車速、車門狀態等等。

零成本入門車聯網安全研究

(ICSim儀表和操作介面)

在我們這個架構中,ICSim和controls分別連線到兩路不同的CAN上,其中ICSim連線到HU域的ICCAN,代表真實的儀表盤;controls連線到VCU域的BDCAN,代表真實的車身部件。VCU域與HU域透過乙太網進行連線,controls產生的CAN報文透過乙太網傳送給ICSim。這種實現與真實的整車域架構及其接近,因為有些車型的儀表確實被劃分到了HU域,乙太網作為VCU與HU的通訊協議也是當下比較流行的域架構。

透過如下方式建立vcanic和vcanbd:

sudo ip link add name vcanic type vcan
sudo ip link set dev vcanic up

sudo ip link add name vcanbd type vcan
sudo ip link set dev vcanbd up


接下來將ICSim與HU域的vcanic繫結,controls與VCU域的vcanbd繫結:

./icsim vcanic
./controls vcanbd


此時,代表車身零部件的controls產生的報文還不能順利達到ICSim,因為vcanic與vcanbd兩路CAN匯流排目前還未聯通,我們將透過乙太網的方式將這兩路CAN連線起來,同時也將意味著VCU與HU的聯通。


CAN-ETH通訊

乙太網的實現使用開源專案cannelloni[2],cannelloni的核心原理是透過UDP協議傳送CAN報文,如下圖所示:


零成本入門車聯網安全研究


(圖片來自論文《Mapping CAN-to-ethernet communication channels within virtualized embedded environments》)

因為我們這個實驗是在一臺機器上進行的,所以我們將透過不同的埠區分VCU和HU這兩個獨立的通訊域,結合劃分廣播域的需求,我們將透過vconfig建立帶有vlan id的虛擬網路卡。


VLAN劃分廣播域

考慮到透過乙太網傳輸的報文型別包含了安全性要求比較高的ADAS(自動駕駛)報文,我們的想法是根據報文的不同安全等級來劃分廣播域,將普通控制報文和自動駕駛報文透過VLAN劃分到不同的網路,相互之間不能訪問。

零成本入門車聯網安全研究


首先需要在真實的網路卡上建立帶有vlan id的虛擬網路卡:

$ sudo vconfig add enp0s31f6 20
$ sudo vconfig add enp0s31f6 30


建立結果如下:

$ ip link
(此處省略不相關網路卡)
5: enp0s31f6.20@enp0s31f6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 70:85:c2:7f:31:ef brd ff:ff:ff:ff:ff:ff
6: enp0s31f6.30@enp0s31f6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 70:85:c2:7f:31:ef brd ff:ff:ff:ff:ff:ff


給網路卡新增ip地址並啟動網路卡:

$ sudo ifconfig enp0s31f6.20 192.168.20.100 netmask 255.255.255.0 broadcast 192.168.20.255 up
$ sudo ifconfig enp0s31f6.30 192.168.30.100 netmask 255.255.255.0 broadcast 192.168.30.255 up


啟動成功之後的效果如下:

$ ifconfig
(此處省略無關網路卡)
enp0s31f6.20: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.20.100  netmask 255.255.255.0  broadcast 192.168.20.255
        inet6 fe80::7285:c2ff:fe7f:31ef  prefixlen 64  scopeid 0x20<link>
        ether 70:85:c2:7f:31:ef  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 81  bytes 12838 (12.8 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
enp0s31f6.30: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.30.100  netmask 255.255.255.0  broadcast 192.168.30.255
        inet6 fe80::7285:c2ff:fe7f:31ef  prefixlen 64  scopeid 0x20<link>
        ether 70:85:c2:7f:31:ef  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 81  bytes 12838 (12.8 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0


測試以下兩個VLAN的連通性:

$ ping 192.168.20.100 -I enp0s31f6.30
PING 192.168.20.100 (192.168.20.100) from 192.168.30.100 enp0s31f6.30: 56(84) bytes of data.
^C
--- 192.168.20.100 ping statistics ---
70 packets transmitted, 0 received, 100% packet loss, time 70637ms
pipe 4

$ ping 192.168.30.100 -I enp0s31f6.20
PING 192.168.30.100 (192.168.30.100) from 192.168.20.100 enp0s31f6.20: 56(84) bytes of data.
^C
--- 192.168.30.100 ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 4100ms
pipe 4


VLAN劃分成功,接著我們使用cannelloni將BDCAN(vcanbd)和ICCAN(vcanic)連線起來:

$ cannelloni -I vcanbd -R 192.168.20.100 -r 20001 -l 20000
INFO:udpthread.cpp[INFO:146]:run:UDPThread up and running
canthread.cpp[108]:run:CANThread up and running


$ cannelloni -I vcanic -R 192.168.20.100 -r 20000 -l 20001 -p
INFO:udpthread.cpp[146]:run:UDPThread up and running
INFO:canthread.cpp[108]:run:CANThread up and running


連通之後透過controls的操作,便可將CAN報文傳送給ICSim,儀表盤也可以顯示狀態了。透過同樣的方式將ASCAN和CAMCAN連線起來,VCU域與HU域的通訊就完全打通了。在實際的通訊場景下,我們可能會依據類似最小許可權原則來配置業務能力,比如在VCU與HU的通訊場景中,我們可能會認為HU域只需要從VCU接收車身CAN報文的能力,而不需要傳送車身CAN報文的能力;相反,HU域產生的攝像頭資料,需要經乙太網傳送給VCU的ADAS模組,此時HU域可能需要的是傳送攝像頭報文的能力,而不需要接收能力。為了滿足這種需求,我們在實驗中增加了網路防火牆。


 防火牆

透過iptables規則分別在VCU域和HU域建立防火牆,過濾存在風險的乙太網報文,以達到如下兩個目的:

  1. 車身零部件產生的報文只能由VCU傳給HU;

  2. 攝像頭採集的報文只能由HU傳遞給VCU。

零成本入門車聯網安全研究


以HU為例,透過如下規則對報文的流向進行控制:

$ sudo iptables -A INPUT -d 192.168.20.100 -j LOG --log-prefix='[hu-normal-in]' --log-ip-options
$ sudo iptables -A INPUT -p udp -d 192.168.20.100 -s 192.168.20.100 --dport 20001 --sport 20000 -j ACCEPT
$ sudo iptables -A INPUT -d 192.168.20.100 -j DROP


 到目前為止,VCU與HU的通訊已經完全打通,並且我們加上了防火牆規則,但VCU內部的通訊卻還沒有解決,因為ADAS模組可能也需要車身零部件的資料來做自動駕駛決策,所以我們需要透過閘道器將BDCAN與ASCAN連線起來。


CAN閘道器功能

使用cangw可以實現簡單的CAN閘道器功能,連線車身CAN(BDCAN)和ADAS CAN(ADASCAN),車身產生的CAN報文透過閘道器路由至ADAS模組。(其實cangw和cannelloni的功能結合起來已經很接近真實的CAN閘道器,真實的CAN閘道器還支援LIN、Flexray等)

零成本入門車聯網安全研究


 閘道器的配置方式如下:

$ sudo cangw -A -s vcanbd -d vcanas -e
$ sudo cangw -A -s vcanas -d vcanbd -e


cangw還支援配置報文過濾規則以及完整性校驗,讀者可以繼續探索,攝像頭模組與ADAS模組的功能也可繼續完善。

 

參考

[1].GitHub - zombieCraig/ICSim: Instrument Cluster Simulator

[2].GitHub - mguentner/cannelloni: a SocketCAN over Ethernet tunnel

本文首發於本人的CSDN專欄“車聯網安全雜貨鋪”,地址https://blog.csdn.net/andlee/article/details/121228330,轉載請申明出處!


相關文章