Penetration Testing Methodology: Emulating Realistic Attacks by a Malicious Actor
The foundation of VerSprite’s penetration testing methodology is based on emulating realistic attacks by a malicious actor through the use of PASTA (Process for Attack Simulation and Threat Analysis). Download our guide to the PASTA Threat Modeling methodology:*
The trend of automotive security research began in the 2010s and has resulted in the discovery of several critical security issues within modern vehicles.
Hackers have repeatedly demonstrated their ability to remotely track, steal, and control a variety of unaltered vehicles. In most cases, manufacturers can mitigate these issues by applying updates to the affected automotive software, but what happens when patching a critical vulnerability is less than trivial?
Aftermarket automotive remote starters are off-the-shelf systems that may be installed in a vehicle to enable advanced features such as remote engine start or keyless entry. Despite the convenience offered by these devices, applying security updates may be quite difficult. While some aftermarket remote start systems offer over-the-air updates, several models require physical access to update the firmware which introduces the risk of unmitigated threats.
In addition, professional installation is often required for these products, rendering the device inaccessible to the driver. As we saw no mention of aftermarket products in prior automotive security research, we decided to investigate these products ourselves.
Traditionally, remote start systems are controlled by a key fob, but smartphone controls have become prevalent among aftermarket solutions. Our research suggests that the leading vendors of mobile automotive remote start solutions are VOXX International and Directed Electronics, both of whom manage several different brands. The aftermarket remote start products offered by these vendors primarily support communications over Bluetooth or wireless cellular networks.
We felt that the isolated attack environment offered by a Bluetooth enabled system is very appealing from the perspective of grand theft auto.
The CarLinkBT mobile application communicates to the Carlink ASCLBT remote start module over the Bluetooth Low Energy (BLE) protocol. In order to understand exactly how the remote start module is controlled by the mobile application, we downloaded the CarLinkBT Android APK from APKPure.com for further analysis.
An Android PacKage (APK) is an archival file format that contains an application’s code and resources. APKs are used by the Android operating system to install applications, but they may also be analyzed to gain an understanding of how an application works.
Included within an APK is a file named classes.dex which contains class definitions and application bytecode. We began by processing this file using dex2jar to convert the application to a JAR file.
We then used Bytecode Viewer to decompile the application’s bytecode for analysis. Our interests lied in understanding how the application connects to and communicates with the CarLinkBT remote start module, so we looked for classes that related to BLE. This led to the prompt discovery of the BLEUtilities class.
The BLEUtilities class defines the following public methods which are used by the application for managing a BLE connection with the CarLinkBT remote start module:
Figure 1: BLEUtilities public methods
When an instance of BLEUtilities is created, scanLeDevice() is called to begin scanning for the CarLinkBT module. scanLeDevice() is primarily a wrapper for several BLE methods found in Android API’s BluetoothAdapter class that relate to BLE scanning. The callback method, onLeScan, will stop scanning for new devices when it detects the CarLinkBT module then attempt to establish a new connection to the device’s GATT server by calling connectToDevice().
Figure 2: scanLeDevice() code snippet
The Basics of Bluetooth LE GATT
GATT is an abbreviation for the Generic Attribute Profile, which is a specification that defines how BLE devices may communicate through a hierarchical data structure exposed by a GATT server.
At the top of this hierarchy is the GATT profile, which contains one or more GATT services. GATT services are identified by a Universal Unique Identifier (UUID) and are comprised of GATT characteristics.
GATT characteristics are also identified by UUIDs and include a characteristic value, a set of characteristic properties, and optional characteristic descriptors. After a connection is established with a GATT server, a client may read from and/or write to characteristics depending on their access permissions.
The Android API’s BluetoothDevice class contains a method called connectGatt(), which establishes a connection to the GATT server hosted by a BLE device and returns a new BluetoothGatt instance. The CarLinkBT application’s BLEUtilities class includes a public BluetoothGatt object named mGatt that is used throughout the class as a GATT client.
The connectToDevice() method is responsible for calling connectGatt() to populate mGatt with a BluetoothGatt instance corresponding to the CarLinkBT module. After the GATT connection has been established, the writeCommandToDevice() method may be used by the application to send commands to the GATT server and control the remote start module.
Figure 3: connectToDevice() code snippet
The writeCommandToDevice() method includes a couple of preliminary checks. The first check calls the enableNotifications() method if GATT notifications are not enabled. Notifications are one of two ways in which a client may communicate with a GATT Server through characteristic values, the other being Indications.
Unlike Indications, Notifications do not require an acknowledgment from the client, which allows for a connectionless form of communication. Notifications are not enabled by default, however, and must be enabled by a GATT client.
Understanding the UART Service
As we mentioned before, GATT components are identifiable by their UUID values. The UUID instances are statically defined within the BLEUtilities class:
Figure 4: Nordic UART UUIDs
Investigation of these UUID values reveal that they correspond to the Nordic UART Service. UART is an acronym for Universal asynchronous receiver-transmitter and it enables serial communication between two devices. UART_SERVICE_UUID corresponds to the UART service.
A reference to this service must be acquired prior accessing its underlying characteristics. This is done by calling the getService() method of a BluetoothGattService instance.
Figure 5: Call to getService()
UART_WRITE_UUID corresponds to the RX characteristic of the service, and UART_NOTIFICATION_UUID to the TX characteristic. The getCharacteristic() method must be called from the BluetoothGattService instance returned by getService() in order to access the TX and RX characteristics.
Figure 6: Call to getCharacteristic()
Finally, UART_NOTIFICATION_DESCRIPTOR is the Client Characteristic Configuration Descriptor (CCCD) that corresponds to the TX Characteristic. The bit field values of this descriptor are used to enable and disable Notifications and Indicators for the associated characteristic.
The getDescriptor() method is called to acquire a BluetoothGattDescriptor instance corresponding to the CCCD, then writeDescriptor() is called to enable notifications for the service’s TX characteristic. The setCharacteristicNotification() method is called for each characteristic instance to inform the GATT client to listen for Notifications from the GATT service.
Figure 7: Call to getDescriptor()
XXTEA Encryption Key Generation
After Notifications have been enabled for the device, the second check in writeCommandToDevice() calls the resendDynamicKey() method if the value of currentXXTeaKey has been set. currentXXTeaKey is a global byte array that contains the XXTEA key to be used for encrypted communications with Nordic UART Service. XXTEA is block cipher that uses a 128-bit key, and was likely chosen due to its relatively lightweight implementation.
The CarLinkBT application includes an XXTEA class that contains methods for encryption, decryption, array manipulation, and data type conversion. The XXTEA class also includes a method named generateRandomKey() which is used to generate a random 128-bit (or 16 byte) XXTEA key. We can see that in resendDynamicKey(), the key returned by generateRandomKey() is supplied as an argument to writeDynamicKey().
Figure 8: resendDynamicKey() code snippet
The writeDynamicKey() method is responsible for updating the Nordic UART Service with a new encryption key. This is achieved by writing an encrypted key message to the service’s RX characteristic (UART_WRITE_UUID). The key message is a 20-byte array containing the randomly generated XXTEA key prefixed by the values “1”, “37”, “-7” and the least significant byte of the message ID.
Figure 9: Constructing the key message
Prior to being written to the service’s RX characteristic, the key message is encrypted using a default encryption key that’s computed within the XXTEA class. After successfully writing this key message, the currentXXTeaKey is updated with the new key value.
Figure 10: Default XXTEA Key
Following the second check in writeCommandToDevice(), the application proceeds by constructing a command message to be written to service’s RX characteristic. The command message is an 8-byte array whose first 4 bytes are derived from the current system time.
Figure 11: Constructing the command message
The 5th byte of the command message is populated by the least significant byte of the message ID. The 6th contains the pendingCommand value, for which we were able to find the following descriptively definitions:
Figure 12: CarLink UART Commands
Finally, the command message is suffixed by the values “55” and “-66”. After the command message has been built, it is encrypted using the current XXTEA key. However, if currentXXTeaKey is null, the default XXTEA key is used for encryption instead. This logic implies that updating the device with a new XXTEA key is completely optional. Following this, the encrypted command message is written to the RX characteristic, and the command is processed by the CarLinkBT module.
Figure 13: Encrypting the command message
Now that we have an understanding of the application’s BLE operational workflow, lets summarize:
scanLeDevice() scans for the CarLinkBT module, then calls connectToDevice()
connectToDevice() calls connectGatt() and populates mGatt with the instance returned
writeCommandToDevice() calls enableNotifications() to enable Notifications
writeCommandToDevice() calls resendDynamicKey() to configure a new XXTEA key
writeCommandToDevice() builds and encrypts a command message using the current XXTEA key
writeCommandToDevice() writes the encrypted message to the service’s RX characteristic
The CarLinkBT remote start module processes this command message and responds accordingly
The most critical observation to be made is that the client is responsible for the generation and management of encryption keys. This implies that a rogue BLE client should be capable of mimicking the application and sending commands to the CarLinkBT remote start module.
In part 2 of this series, we’ll focus on the dynamic analysis performed to confirm our findings and understand how the CarLinkBT device operates in a practical environment. Stay tuned on part 2 of this series. Click here to subscribe to VerSprite’s blog.