1 Introduction
1.1 Contributions and limitations
-
With respect to the previous work, we replace and customize an entire vehicle component, the IVI firmware, rather than solely exploiting vulnerabilities of a component;
-
Compute and read the encrypted AES-CBC 128 key;
-
Extract the RSA public key;
-
Decode the AES-CBC 128 key using the previous RSA public key;
-
Compute the SHA256 of the content of each file;
-
Discover the algorithm that generates the Initialization Vector (IV) for the AES-CBC cryptosystem;
-
Generate the Initialization Vector (IV);
-
Encode and decode each file with the AES-CBC 128 Key and the IV;
-
Bypass the check of the digital signature during the firmware installation by upgrading AppDMClient binary patch in Head-Unit;
-
Remotely control the Gen5W_L IVI system by injecting remote commands that impact also the CAN bus into M-bus, B-bus and C-bus. In particular, we forge CAN bus frames like we trigger services from the telematic app, e.g., Bluelink. This is possible only leveraging 1-Day exploit (AppNavi) or using our custom firmware;
-
Control and manage the cellular connection of the Head-Unit.
1.2 Structure of the paper
2 Related work
3 Chimaera working phases
DecryptToPIPE
, which, during the installation, is used to decrypt the firmware. Other significant executable files are AppDMClient
and AppUpgrade
, both involved in the installation checks like the verification of the digital signature, while the file lge.upgrade.xml
contains some firmware information like the version number and date. lge.upgrade.xml
. The main findings are the decrypted files, which we retrieve using a “public” RSA key;lge.upgrade.xml
file to allow us to install a version with an older firmware date with respect to the already installed version;4 Firmware structure analysis
IONIQ5_EU.ver
, while all the others are encrypted. IONIQ5_EU.ver
contains a list of the firmware files with some related information like the dimension. Besides, in the folders, some files are hidden like .lge.upgrade.xml
. By opening this file, we noticed that an error occurred due to the fact that the xml
file is not in clear format but it is encrypted together with the other downloaded files. In Fig. 3, we report the most significant files for our work. In particular, AppUpgrade
is an executable program in charge to decrypt and install the firmware. Other relevant files are mango.rootfs.tar.gz
and new_gui.tar.gz
, which are compressed archives.
DecryptToPIPE
file that is in charge of performing the decryption operation of each encrypted file sent as input and it is encrypted into the Gen5W_L IVI system. The Key_file
and DecryptToPIPE
can be retrieved from the HU using a specific procedure.85 Reverse engineering DecryptToPIPE (I)
DecryptToPIPE
can be executed as a C program and takes in input the Key_file
, the file to decrypt, and 0 which represents an offset of bytes to obtain in the decryption phase. To understand the behavior of DecryptToPIPE
, we use Ghidra which allows us to reverse the DecryptToPIPE
executable file. In Fig. 4, we show the selected parameters to import DecryptToPIPE
ELF file in Ghidra.
RSA_decrypt_and_AES_key
, reads the Key_file
and obtains a 128 bits key to decrypt the software file. The second function allocates some area of memory, while the third function calculates the Initialization Vector (IV) and uses it together with the 128 bits key to decode the file using AES-CBC. In any case, before proceeding with the decryption, the third function calculates and compares the SHA256 saved into the input file itself. If this check fails, then the decoding operation is quit and it is not executed.
5.1 RSA_decrypt_and_AES_key
RSA_decrypt_and_AES_key
calls six other functions, however, the only interesting to understand the flow is the function that we rename as reading_file
that contains the decryption operations.
reading_file
, there is an instruction (Fig. 7) that saves into a variable the result of a function, which takes in input five parameters, where the second last is a clear text string “rsa_decrypt” and the last is the number “11”, which represents the number of characters in the previous string. We use this piece of information to understand that this function is mbedtls_ctr_drbg_seed
which requires as the fourth parameter a const unsigned char pers
and as fifth parameter strlen (pers)
. This discovery allows us to understand that DecryptToPIPE
uses Mbed TLS for its encryption/decryption process, and also for the SHA generation and controls. Mbed TLS is a C library that implements cryptographic primitives, X.509 certificate manipulation and the SSL/TLS and DTLS protocols with a small code footprint [31].DecryptToPIPE
was compiled in a static-mode. This is proved by the fact that the entire Mbed TLS library, together with its implemented functions were available into DecryptToPIPE
. The consequence of this is that during the RE process, Ghidra tried to disassemble and decompile all these functions.
reading_file
takes in input two parameters, one of whom is the buffer of the Public_Key_file
, which is read with an fopen64 (file, “rb”)
. This operation allows us to understand that some information are retrieved from the file before starting the RSA decryption. Then, continuing the reading of the code, we identify two For
loops (decompiled as do...while
in Ghidra). The first For
read the AES-CBC 128 key from Public_Key_file
. However, as stated before, the reading of the key is not sequential, but the pointer jumps three positions before reading each character. In Fig. 8, we show in C language the reading process.For
is used to retrieve two values, called n and e, necessary to generate the RSA key in the library Mbed TLS. Then, we continue to read the following code of the function reading_file
. Reading the code of the called functions, we notice a precise correspondence between the code of the explored functions and the native functions of the Mbed TLS library. In this way, we can rename the functions giving the Mbed TLS names and identify the inputs and outputs of each function.5.2 Memory leakage vulnerability
printf
function that it is present in the disassembled code that prints the following: “Unexpected error, return code = %08X”, where %08X is the HEX value stored in the specific registry. This function is not intended to be used by DecryptToPIPE but it is part of the “mbedtls_printf”, which is the original printing function of Mbed TLS library, meaning that the vulnerable part was introduced by statically compilating the “mbedtls" code into DecryptToPIPE. Since DecryptToPIPE does not use that printf, the code works without any security reason. However, by editing the assembly code of DecryptToPIPE and by injecting the assembly code that is in charge to print a value obtained in EDX registry we are able to print the values of the registry contains or pointed by it. Listing 2 shows the original assembly code used to print the value stored in the R15D registry. Then, the instruction in the LEA is needed to load the “Unexpected error, return code = %08X” that is sent to the printf when invoked through the CALL.
Key_file
passed to DecryptToPIPE when invoked: the Public key
and of the encrypted AES-CBC key
. Thus, to retrieve the AES-CBC 128 key (Fig. 8), we replicate in C the reading process that DecryptToPIPE uses to read the Public key
and of the encrypted AES-CBC key
from the Key_file
. Then, to decrypt the key, we implement in C the RSA decryption as provided in the Mbed TLS library, reading the parameters n and e. Finally, we pass to the function the buffer containing the key, decrypt it with Mbed TLS library, and print the AES-CBC 128 key. To summarize, we: 1) Discover the usage of Mbed TLS library for the encryption/decryption process. 2) Understand where and how RSA and AES-CBC 128 keys are read. 3) Discover AES-CBC 128 key.6 Reverse engineering DecryptToPIPE (II)
DecryptToPIPE
. The second function seems to be a memory allocation and it does not call any other function, so it is not relevant to our study.AES_and_SHA
is mainly dedicated to the calculation of the SHA256 and its verification, as well as to the decryption of the software file passed to DecryptToPIPE. In particular, we notice that the third function read the file to decrypt from the bottom and look for a string of two subsequent HEX characters in the file: “TE” (0x54,0x45 in HEX). Then, the function controls the next character after “TE” to determine if it is a “2” or a “R”. In our case, we notice that all firmware files have “2” while checking another firmware for Genesis vehicles the terminators are “R”, so we can state that, according to the vehicle model, the file terminator is different. Continuing analyzing the disassembly and decompiled code from Ghidra of the function AES_and_SHA
, we discover that it starts a series of integrity checks that we properly link to mbedtls_sha256_starts, mbedtls_sha256_update, and mbedtls_sha256_finish functions. Moreover, by reverse engineering the HEX values of each file, as reported in Fig. 9, we found that after the “TE2”, there is an extra HEX character, which we call “x”, that can vary from file to file. In any case, we observed that the “x” value is not used.
AES_and_SHA
function computes the SHA256 of the file content starting from the first byte position up to the sequence “TE2+x” (0x54,0x45,0x32,0xFF). When calculating the SHA256, the “TE2+x” sequence is not considered. Then, to verify that the calculated SHA256 corresponds to that one present in the file firmware, DecryptToPIPE starts reading the 32 byte values after the “TE2+x” sequence. If the two SHA256 are equal then DecryptToPIPE goes ahead with the decryption otherwise it quits.6.1 Getting IV and SHA from DecryptToPIPE
DecryptToPIPE
to leak the HEX values from the memory of relevant information like the initialization vectors for the AES-CBC 128 encryption. In the next listings, we report an example of the assembly code of the print that we implement for each piece of information that we need to retrieve. Note that the registry R13 and the number of printed values can be changed according to the needs.
DecryptToPIPE_generate_IV
print the IV of the related file using the following command line. This information is used to encrypt again a file after the modification.
DecryptToPIPE_print_SHA256
print the SHA of the related file using the following command line. This information is used for the encryption after the modification.
DecryptToPIPE
allowed us to: i) Retrieve the RSA key and use it to find the AES-CBC 128 key. ii) Use the AES-CBC 128 key to decrypt the file. iii) Check the integrity of the file content verifying a hash SHA 256. iv) Generate the IV and SHA256 needed to create a customized encrypted file.7 File structure analysis
DecryptToPIPE
. After the string, there is a HEX char, which is the first character of the following digital signature. The next 32-byte are the SHA 256, computed on the file content. After the file content, we have 36-byte which needs to be written in this defined order, however, the firmware installation fails the checks. Then, we find 16,384 byte which contains a digital signature, generated with the private RSA key. In this situation, we can not replicate the digital signature because we have retrieved only the public RSA key and it is not feasible to try to find a private RSA key from a public RSA. With different tests, we discover that the lack or incorrect signature can block the installation of any file generated by us. This happens since AppDMClient
first, and AppUpgrade
then, are in charge of validating the digital signature of any encrypted file. With the retrieved information, to modify a file correctly, for example, to install a backdoor, we need to follow the next steps:-
Modify the file content, without any constraints about the dimension, it can be smaller or bigger than the original file content;
-
Paste at the end of the file content the string TE2+x, where x is the HEX value in the original file;
-
Compute the hash SHA 256 of the file content using Mbed TLS library;
-
Paste the hash after TE2x;
-
Copy the digital signature of the original file or create a dumb digital signature made of 16,384 FF bytes;
-
Append the copied digital signature at the end of the file.
8 Patching AppDMClient and AppUpgrade
AppDMClient
and AppUpgrade
, two binaries involved in the installation process, check for the valid digital signature of each encrypted file. Thus, to process with a complete and effective installation process of a customized software into the head unit, we need to i) skip the digital firmware check or ii) create a valid digital signature. Since, we cannot afford the case ii) since we do not have the private key, we can only work on skipping the digital signature check. However, to reach this goal, we need to modify AppDMClient
and AppUpgrade
:-
AppDMClient
, which is a program stored inside the HU and it callsAppUpgrade
after checking the relative digital signature; -
AppUpgrade
, which is called byAppDMClient
, that starts the installation process.
8.1 AppDMClient
AppDMClient
is responsible for the starting of the installation process and it checks the digital signature of two relevant files: AppDMClient
and .lge.upgrade.xml
. It computes the digital signature of the file content and compares it with the one present in the file. If the signatures is valid, the installation continues, otherwise, it is stopped. It decrypts the files and, then, copies their decrypted version in a defined internal Head Unit partition. As we can not generate the digital signature, we have to skip this control to continue the installation. To identify where AppDMClient
checks the digital signature, we observed the log of AppDMClient
9 during the installation process. In the logs, we observed that when the digital signature check fails, the error code -403 is displayed. Thus, we searched on Ghidra in the disassembled listing where the 0xfffffe6d value, which corresponds to 0x193 (-403 int) signed value, is present in the code. In Fig. 10, we compare the original version assembly code with our code. In particular, on the right, we underline in red the digital signature code, which allows us to find where the function goes if the digital signature is not correct. Then, we decide to skip the control and, to perform this operation, we patch the assembly by modifying the JZ instruction to JMP. Changing the assemble code with the unconditional “if” instruction allows us to bypass the digital signature check by jumping directly in the correct flow even if the digital signature is not correct.8.2 AppUpgrade
AppUpgrade
is responsible to continue the installation process and call DecryptToPIPE
for the decryption of the files. We modify AppUpgrade
to avoid the check of the digital signature of all files and allow us to install firmware versions with any date. In particular, we use the same methods as applied with AppDMClient
. In Fig. 11, we report the differences among the original one and our modified version. We change the assembly JZ instruction to JMP, which jumps directly into the correct flow even if the digital signature is not correct.
AppUpgrade
checks a variable, called iVar4 in the decompiled code, to determine if the firmware date is the same, later or older than the actual. Then, in any case, it prints a string with the result and associates a variable, called local_1a8, the value 1 if the updated version is the same, 0 if it is newer, and 2 if it is older. In the first two cases, there are not any issues during the installation. In the third case, the original version installation fails. we modify the assembly instruction MOV
to associate the value 1 also in the case of an older version.AppUpgrade
is related to the modification of the date and the version field in a customized .lge.upgrade.xml
file as shown in Fig. 12.
9 Custom firmware creation
AppDMClient
, AppUpgrade
. Then, we have to create the files that we want to customize. In our case, we decide to modify three main files:-
mango-rootfs.tar.gz
which is the archive containing the file system files in which we insert our backdoor. -
new_gui.tar.gz
which is the archive containing images and we substitute the original with our customized images. -
.lge.upgrade.xml
is an XML file that contains the number/date firmware version and we modify it to write our desired firmware date.
9.1 mango-rootfs.tar.gz
mango-rootfs.tar.gz
, we modify the file content and the relative SHA, while we have to keep the original digital signature, appending at the end of the file, as reported in Sect. 7. In the beginning, we have to decrypt the original tar file, using, for example, DecryptToPIPE
and the following command in a shell:
9.2 new_gui.tar.gz
new_gui.tar.gz
is a tar.gz archive that contains several images in two different image formats:-
.astc images that use Adaptive Scalable Texture Compression (ASTC). Each file is divided into two new parts, saved in two different files: the ASTC file header and the file content.
-
astc.lz4 images that have lz4 extension, which is a compressed archive containing an ASTC file.
chimaera_image.py
(Sect. 12). Then, we encrypt again the archive with the AES key, the IV, the SHA256 and the dummy digital firmware by using the Python program that we called chimaera_build_docker.py
(Sect. 12).10 Custom firmware installation
AppDMClient
with our modified version to skip the digital signature check. Then to start the installation, we have just to prepare a USB key in which we put the original firmware file but we replace our encrypted version of AppUpgrade
plus our encrypted files like new_gui.tar.gz
. At this point, we insert the USB stick into the head unit and the update button will be enabled to start the installation of our custom firmware. In addition to the customized images, a proof of our work is the installation of the firmware with a different version number written within the .lge.upgrade.xml file. We create a new .lge.upgrade.xml where the version number is AE_E_PE.EUR.CHIMAERA_CF01.808489, we encrypt and test it on the head unit that reads and accepts it (Fig. 15).11 Chimaera post-exploitation activities
11.1 Playing with CAN bus
-
A “system bus” for communicating between system applications and user sessions.
-
A “session bus” for exchanging data between applications in a desktop environments.
Path_name
, then the interface name must be indicated together with the name of the method to invoke. We noticed that interfaces and methods are hardcoded in some applications running in the head unit making easier understanding which interfaces and methods are useful to control applications of the head unit and its peripheral that manages the CAN bus. Messages exchanged using DBus can be sniffed using the binary dbus-monitor
. It can be instrumented to observe the messages exchanged both on the “system" and “session" bus. Since messages can be monitored in clear on the bus, we are able to see which are the methods called and the corresponding “used” payload. Following, we show an excerpt of “system bus” monitored with dbus-monitor
.
ID
=1.2 invokes a remote object /Can
using the interface com.lge.car.micom.can
and the method, aka member, NotifyKeyFrontPannelEvent
. Then to this method an array of two bytes is passed, i.e., 0x12 and 0x01. As an application connected to one of the bus, we can exploit the dbus-send
binary to invoke the same object as before, i.e., /Can
: we can invoke the method NotifyKeyFrontPannelEvent
of the /Can
in the system
.
dbus-send
binary to also execute commands in the head unit that impact to the CAN bus, For instance, by triggering the command, we are able to enable the seek up function in the radio application. In addition, the dbus-send
generates the CAN Bus frame to the M-Bus that corresponds to the CAN ID 0x122
and modifies last two bytes of the CAN bus frame payload.
11.1.1 Generating CAN bus frames on behalf of the Telematic Unit
TmsRemoteApp
binary is in charge of managing the operations sent by a user through the smartphone app. By decompiling the TmsRemoteApp
with Ghidra, we noticed some code similar to that one reported in Fig. 17 and 18.
ID
, DLC
and Payload
. Thus, by considering the variables from local_38
to local_2e
, we can build the CAN frame: 0x4A2 8 FF FF FF FF FF FF FF FF
. Then, we see that the memory location address starting as local_38
is used by the function FUN_00120cc0
, see red-rectangle number 2. In particular, this function uses the variable local_98
used by the function FUN_00120d90
. It takes as input the string SetCANMicomRecv
, which we discovered that being a method of the com.lge.car.micom.can
interface. Thus, if we decompile FUN_00120cc0
we obtain the code illustrated in Fig. 19.
com.lge.car.micom
and com.lge.car.micom.can
. In particular, the first one represents the destination bus object and the second one, as we said before, the interface. Then, the DBus message is sent. In a similar way, we can replicate this command using dbub-send
.
TmsRemoteApp
manages several telematics services that allow to control, for instance, the heating system, vent, lights, horn, vehicle position and so on. Those services are implemented using the same approach explained before.11.2 Controlling the Head Unit cellular connection
Powers on
the modem. Finally, line 4 shows the command to get the network info. To control the network interfaces in the Head Unit, we use the ConnMan daemon. To easily interact with the ConnMan deamon, we can exploit the software tool connmanctl
available in the Head Unit firmware.
services
command of “connmanctl” and we observed two available services. By connecting to the second services connect cellular_SOMENUMBERS_context2
we enable a second cellular network interfaces named as rmnet_usb1
. Instead, the first available service, i.e., connect cellular_SOMENUMBERS_context1
, enabled the rmnet_usb0
interface. Unfortunately, rmnet_usb0
did not provide a working Internet connection but through rmnet_usb1
we got the working cellular connection. Now, we set up it as default interface to route the traffic through the Internet. This setting can be performed with the following commands.
rmnet_usb0
interface, and in line 3 we set the new default gateway using the rmnet_usb1
. Now a simple ping
test reveals a default working Internet connection through the cellular network of the Head Unit.12 Chimaera tools
chimaera_build
automatically reproduces the encryption process and encrypts the custom firmware to install; the second, chimaera_image
, to compress in the right format the images of the custom firmware.12.1 Chimaera build
chimaera_build
tools handles all required operations for file encryption and, in particular, it exploits two docker containers that run our patched version of DecryptToPIPE
13 to leak from the memory the correct IV and SHA256. The tool can be accessed by entering the following command line for any decrypted file:
chimaera_build
steps are the follow. It: step 1
as the source filename;step 1
;step 1
;chimaera_build
tool asks if we want to check the correctness of the encryption process, executing the decryption. If the decryption ends correctly, the encryption was executed rightly.12.2 Chimaera image
.astc
, .astc.lz4
and .astc.gz
. From our reverse activity we understood that the .astc
and .astc.gz
files can be decompressed using the standard .astc
.14 Instead, the .astc.lz4
is a sort of double compression where first we have unpack .lz4
and then decompress the .astc
..lz4
using the standard tool like,15 the decompression is not properly performed. So, by opening the .astc.lz4
with a HEX editor we noticed that the first 14 bytes are 094C5A5F 454E4A4F 59544F4F 4C53
that in is ASCII corresponds to LZ_ENJOYTOOLS
. By googling this, we landed on this github project https://gist.github.com/edp1096/a791c659b0da4473c4139a9297f77dab that provides a C
file to compress and decompress a .lz4
file. Starting from this project, we customized it a bit and we were able to decompress the .lz4
file obtaining a file compressed onlysas .astc
format. The decompression of this latter one is can be done using the standard .astc
..astc
image is divided into two parts, saved in two different files: the ASTC file header and its content on another file. We developed chimaera_image
to easily decompress any type of .astc
, .astc.lz4
and .astc.gz
image and compress a PNG
image into .astc
, .astc.lz4
format compatible with the Gen5W_L firmware. So, by utilizing the chimaera_image
tool, developers can ensure that their custom firmware can easily incorporate the necessary firmware images without any compatibility issues.13 Conclusion, discussion and future works
printf
function in the statically compiled mbedtls
library, allows for a format string attack leading to the injection of malicious code and manipulation of the IVI system. Performing a reverse engineering process, we were able to exploit these vulnerabilities, bypass digital signature checks, and remotely control the IVI system. The importance of our findings lies in the potential risks associated with compromised IVI systems in modern vehicles. The number of connected vehicles has increased the vulnerability to remote attacks, and the IVI, as a crucial entry point, demands cybersecurity measures. Our responsible disclosure of these vulnerabilities aims to prompt necessary actions to address and correct these issues, ensuring the safety and security of vehicle systems.