The Hitchhiker's Guide to Hacking Connected Cars: The Devil's Details of TCU Init Scripts in Android
A dissection of attacks resulting from faulty logic in the writing of init scripts in Telematics Control Units
"Son, the greatest trick the Devil pulled was convincing the world there was only one of him." ― David Wong, John Dies at the End
Overview of Init
Most TCUs and Head Units will run a flavor of Linux, whether it's Nvidia Linux, Android, or some other real-time operating system (RTOS). It's important to think of Android as more of an application framework that sits atop of Linux. Android is supplied as open source code, but does not bind the user with the constraints of the GPL and has no requirement for developers to make public any code developed using Android. Understanding that Android sits on top of Linux is not too dissimilar to recalling how Windows 3 sat on top of the old DOS operating system (dating myself here).
Having said that, Unix-based operating systems run an initialization (init) continuously that controls startup and shutdown of the operating system (OS) and corresponding commands that get executed during those specific "init levels." Init is the very first process that is executed during the boot of the embedded system that runs as a daemon until the embedded system is shut down and is started by the Kernel, typically as PID (Process ID) 1.
Many platforms will run SysV-style (System 5) init. At any moment a running System V is in one of the predetermined number of states referred to as run levels. At least one run level is the normal operating state of the system, such as 0 for HALT the system, 1 for Single User Mode, or run level 6 for Reboot. Simply typing $ init 6 at the command-line will for example reboot the embedded system.
"It's the little details that are vital. Little things make big things happen." -John Wooden
In Android, the init language is used in plain text files that take the file extension of .rc and are typically found in more than one number in quantity across different locations on the system. Particularly, /init.rc is the primary .rc file and is loaded by the init executable at the beginning of its execution and is responsible for the initial setup of the embedded system, for purposes of this article, we'll be reviewing mistakes made on different penetration tests of a TCU.
Actions and Order of Execution
Actions in Android are named sequences of commands. Actions have a trigger, which is used to determine when the action is executed. When an event occurs which matches an action's trigger, that action is added to the tail of a to-be-executed queue. Actions take the form of:
on <trigger> [%% <trigger>]*
These commands are added to the queue and executed on the order that the file contains them was parsed then sequentially within an individual file.
Therefore the order in which commands appear in the init files is critical to the security and integrity of the TCU.
Android Debug Bridge (ADB) is a standard suite of tools and protocols which allow interaction with an Android system via USB/serial connections. It can be used to copy data to or from an Android device, present the user with a system shell on the device, and support software debugging. During the different tests across numerous OEM TCUs, the data, copy and shell access features were used extensively to access the TCU under test.
Logic Errors and Typos in Sequence
First we'll examine the /init.rc script. As discussed earlier, the sequence in which commands are listed as line items in this file are emphatically critical to the security of the system. If commands are listed in this file in the wrong order, an OEM can easily compromise the security posture of the system inadvertently by putting commands in the wrong sequence. Based on our previous tests, we'll examine some real-life scenarios we've found systemic across multiple OEMs.
# Once everything is setup, no need to modify the / root filesystem
mount rootfs rootfs / rw remount
At first glance, the comment by the developer in this OEM's TCU would indicate an intent to remount the root filesystem as read-only since there was no longer a reason to have the root filesystem as writeable. However, a typo in the command where the developer added the "w" for writeable can be clearly seen here following the "r" switch for read-only. This developer inadvertently remounted the root filesystem as read + write instead of read only like she had originally intended.
# Set Android Debugger Properties and enable the ADB Service
setprop persist.service.adb.enable 1
setprop ro.debuggable 1
setprop service.adb.root 1
Here, with this OEM, the developer is attempting to start the adb service, which was found under the "on boot" section of the init.rc script. However, further down below in the same file, the developer set the property command as the condition to enable the ADB daemon (adbd) accidentally when the intent was to disable it after it had been previously started.
# adbd is controlled by the persist.service.adb.enable system property
service adbd /sbin/adbd
# adbd on at boot in emulator
While the "service adbd" section does indeed disable adbd, the developer inadvertently superseded that command with a new property command below it: on property.persist.service.adb.enable=1, which manually started adbd again consequently causing it to start at every system boot. Best practice would be to have had the adbd service only start when the device is in development mode by setting the adb enable property from within the component that validates the diagnostic commands that changes the mode.
# Enable core dump for all processes
echo | > /proc/sys/gs/suid_dumpable
In this penetration test, the OEM added this line in the init.rc script giving permission to every executable to core dump upon crashing. While this may make sense in development to troubleshoot issues, it is a security issue when the TCU is placed into a production automobile as attackers can gain a lot of information from kernel debug messages and core dump files to gather information on running system processes.
The value in the file suid_dumpable is assigned to a process "dumpable" flag. The "1" flag tells all processes to core dump when possible which is then owned by the filesystem user ID of the dumping process with no security applied. This is intended for system debugging situations only: this mode is insecure because it allows unprivileged users to examine the memory contents of privileged processes. This means that particularly sensitive system processes, which are run with the UID/GID root at execution can also dump core with no security checks applied whatsoever. In several of the OEMs, this flag was applied to SSL workarounds enabling some attackers to be able to cause memory contents that may include the SSL certificate keys to be dumped to flash memory.
Take into consideration that an attacker does not require a TCU to be in development mode in order to gain access to the filesystem of the TCU, just physical access. Devices are available which allows an attacker to connect directly to external flash memory devices on the device's PCB and read/write the flash memory directly.
It's important to always remember, especially developers who are building embedded systems in IoT devices such as connected cars, that simple mistakes such as putting lines in a startup script in the wrong order or typos in flags for system-level commands can have devastating affects on the security posture or integrity of the device. Always keep in mind that humans are the weakest link in security and most of the vulnerabilities we've found in TCUs and Head Units have been a result of typos, improperly implemented controls, or misconfigurations due to human err.
As usual, if you liked this article, please support me by clicking LIKE and share it to your own feed! This is the best possible way that you can support me and my continued research in this area. If anyone has any other mistakes made by human err on embedded systems that created vulnerabilities in the system, please feel free to share it with everyone below in the comments section!
I am the Group CEO of Brier & Thorn and heads up its Connected Car Division where my team and I perform penetration testing and risk assessments of cyber-physical vehicles (CPVs) from OEMs in the United States, Europe, and Asia. As a recognized thought leader in the new Internet of Everything economy, specifically telematics and infotainment systems, I can be found speaking at security conferences in North America and EMEA, vlogging, blogging, and writing contributed articles on the idiosyncratic cybersecurity issues affecting IoT that matter most. Learn more about me at my homepage at www.alissaknight.com, LinkedIn, listen to my weekly podcast episodes, or follow me on Twitter @alissaknight.