Automotive Ethernet Training#

4 Exercises:​

  • Automotive Ethernet AudiCgw​

  • Ethernet DoIP/UDS AudiCgw​

  • ECU Simulation TLS/DoIP​/UDS​

  • SomeIP BCM​ ​

Optional: Sniff UART#

Audi cGW3.1 UART/JTAG Wiring Solution

image image

ECU Point of View!. 6 pins to connect for JTAG communication: GND, VCC, TDI, TMS, TCK, TDO. 2 pins to connect for UART communication: TX, RX.

Audi cGW3.1 UART Connection Solution
#Bash
picocom  --imap=lfcrlf -b 921600 /dev/ttyUSB0

Automotive Ethernet with AudiCgw​#

1. Ethernet DoIP/UDS AudiCgw​#

Connect ECU​#

Audi cGW3.1 Wiring Solution

image

image

Pro Solution
  • Setup Ethernet (Blinking = Good)​

  • Should work automatically if ECU and Eth Activation Line are Powered

Sniff for a DoIP Announcment using Tshark / Wireshark#

Tshark Solution

image

Wireshark Solution

image

Do a nmap Scan of the ECU​#

Nmap cmd hint
sudo nmap -p 1-65535 -e ethX 192.168.XXX.XXX
Nmap options hint

Read the table in subchapter IP and Service Scanning in the chapter Automotive Ethernet

Nmap Solution
sudo nmap -n -Pn -v -sT -sV -r -p 1-65535 -e ethX 192.168.XXX.XXX --disable-arp-ping --max-retries 10 --max-rtt-timeout 100ms

Add IP in the same subnet to your PC:#

Ip link Solution
sudo ip addr add IP/NETMASK dev DEVICE

Send UDS Packet to the ECU#

Audi cGW3.1 DoIP Solution send UDS over DoIP
#PYTHON
from scapy.all import *
from scapy.contrib.automotive.doip import DoIPSocket
from scapy.contrib.automotive.uds import UDS, UDS_RDBI

load_contrib("automotive.doip")

sock = DoIPSocket("169.254.117.238")
pkt = DoIP(source_address=0xe80, target_address=0x4010)/UDS()/UDS_RDBI(identifiers=[0x1000])
resp = sock.sr1(pkt, timeout=1)
resp.show()

Scan your way into the Bootloader of the ECU#

UDS DoIP Scan Solution
#Python
from scapy.all import *
from scapy.contrib.automotive.doip import DoIPSocket, UDS_DoIPSocket
from scapy.contrib.automotive.uds import UDS, UDS_RDBI
from scapy.contrib.isotp import *
from scapy.contrib.automotive.uds_scan import *
from scapy.contrib.automotive.uds_ecu_states import *

load_contrib("automotive.doip")
conf.contribs['CANSocket'] = {'use-python-can': False}
conf.contribs['ISOTP'] = {'use-can-isotp-kernel-module': True}

sock = UDS_DoIPSocket("169.254.117.238")

def reset():
    sock.sr1(UDS()/UDS_ER(resetType="hardReset"), verbose=False, timeout=1)

s = UDS_Scanner(sock, reset, test_cases=[UDS_ServiceEnumerator, UDS_DSCEnumerator])
s.scan(timeout=10)
s.show_testcases()

ECU Simulation TLS / DoIP​ / UDS#

Connect ECU​ Simulation#

Pro Solution
  • Setup Ethernet (Blinking = Good)​

  • Should work automatically if ECU and Eth Activation Line are Powered

Sniff for a DoIP Announcment using Tshark / Wireshark#

Do a nmap Scan#

Nmap Solution
sudo nmap -n -Pn -v -sT -sV -r -p 1-65535 -e ethX 192.168.XXX.XXX --disable-arp-ping --max-retries 10 --max-rtt-timeout 100ms

Download Testssl.sh#

Testssl Download Solution
git clone --depth 1 https://github.com/drwetter/testssl.sh.git 

Do a Testssl.sh Scan#

Testssl Solution
./testssl.sh --nodns=none --connect-timeout=2 192.168.0.2:44446

Connect to DoIP with/without TLS#

UDS DoIP Connections Solution
from scapy.all import *
import socket as socketlib
from scapy.contrib.automotive.doip import *
from scapy.contrib.automotive.uds import UDS, UDS_RDBI

from concurrent.futures import ProcessPoolExecutor

def connect_DoIP_TCP():
   socket = DoIPSocket("127.0.0.1")
   pkt = DoIP(payload_type=0x8001, source_address=0xe80, target_address=0x1000) / UDS() / UDS_RDBI(identifiers=[0x1000])
   resp = socket.sr1(pkt, timeout=1)
   print("Received response:", resp)

def connect_DoIP_TLS():
   # Create client-side SSL context
   context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)

   # This disables hostname verification
   context.check_hostname = False
   # This disables server certificate validation entirely.
   context.verify_mode = ssl.CERT_NONE

   # Load client certificate and key required by the server
   context.load_cert_chain(certfile="client-cert.pem", keyfile="client-key.pem")

   socket = DoIPSocket(ip="127.0.0.1", tls_port=4433, force_tls=True, context=context)
   pkt = DoIP(payload_type=0x8001, source_address=0xe80, target_address=0x1000) / UDS() / UDS_RDBI(identifiers=[0x1000])
   rep = socket.sr1(pkt, timeout=1)
   print(repr(rep))
   socket.outs.unwrap()
client-cert.pem
-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----
client-key.pem
-----BEGIN PRIVATE KEY-----
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
I1KBH15ZyRXPv7j4J4mgfn2xJkeE9d0=
-----END PRIVATE KEY-----

SomeIPs#

Connect ECU​#

Pro Solution
  • Setup Ethernet (Blinking = Good)​

  • Should work automatically if ECU and Eth Activation Line are Powered

Sniff for a SomeIp using Tshark / Wireshark#

Have Fun with a Scapy answering Server#

Audi cGW3.1 DoIP Solution send UDS over DoIP
#PYTHON
#! /usr/bin/python3
from copy import copy
from scapy.contrib.automotive.someip import SD, SOMEIP, SDOption_IP4_EndPoint, SDEntry_EventGroup
from scapy.layers.inet import IP, UDP
from scapy.layers.l2 import Dot1Q, Ether
from scapy.packet import Packet
from scapy.sendrecv import sendp, sniff

def answering_server(pkt: Packet):
    sd_options = [SDOption_IP4_EndPoint(addr="160.48.199.17", l4_proto="UDP", port=30498)]

    if pkt.haslayer(SOMEIP):
        if pkt[IP].src != "160.48.199.16":
            return

        offer_pkts = []
        sub_pkt_array = []
        if not pkt.haslayer(SD):
            return
        try:
            offer_pkts = [copy(p) for p in pkt[SD].entry_array if p.type == 1]
        except AttributeError:
            pass
        for p in offer_pkts:
            print(
                f"Found SomeIP Discovery Offer for Service {p.srv_id}, InstanceID {p.inst_id}\n", flush=True)
            sub_pkt_array.append(SDEntry_EventGroup(srv_id=p.srv_id, inst_id=p.inst_id, type=0x06, n_opt_1=0x01,
                                                    n_opt_2=0x00, index_1=0x00, index_2=0x00, eventgroup_id=0x1,
                                                    ttl=4, res=0, cnt=0, major_ver=1))
            print(
                f"Creating Subscribe for Service {p.srv_id}, InstanceID {p.inst_id}\n", flush=True)
        if sub_pkt_array:
            sd_pkt = SD(flags="REBOOT+UNICAST", entry_array=sub_pkt_array, option_array=sd_options)
            offer_pkt = (
                    Ether(dst="d8:18:2b:c0:bd:81") /
                    Dot1Q(vlan=73) /
                    IP(dst="160.48.199.16", src="160.48.199.17") /
                    UDP(sport=30490, dport=30490) /
                    SOMEIP(srv_id=0xffff, client_id=0x0, proto_ver=0x01, iface_ver=0x01) / sd_pkt
            )
            sendp(offer_pkt, iface="enp7s0f3u1", verbose=False)

sniff(iface="enp7s0f3u1", prn=answering_server)