Automotive security – How to brick your car with a tricky Bluetooth name

Since 2017, some hackers have been making scattered reports on Twitter about a recurring automotive security vulnerability over several different infotainment systems that appeared to leak memory contents and could potentially end up bricking the infotainment system (or more). In all cases, the hackers exploited this by setting the Bluetooth name of their mobile phone to a tricky name, then connecting it to the infotainment system.

Some – but not all – of these vulnerability reports made it to well-known vulnerability databases, like CVE. A lot of the researchers only did limited testing – they obviously didn’t want to cause permanent damage to their own vehicles.

Well-known security expert Solar Designer has identified that the data being leaked on the screenshots was related to map information.

automotive security, secure coding in C and C++, format string

But we can go further than that. The infotainment system is an important part in the attack surface of modern vehicles and is thus one of the critical points of automotive security. In the worst case, an attacker could potentially gain control over the vehicle through it! That’s why this particular vulnerability can be deceptively powerful when exploited. Let’s take a closer look.

When variadic functions go bad

To understand the nature of the problem, we first need to look at variadic functions: functions that can accept a variable number of arguments. Such functions exist in many different languages and using them is not a vulnerability. However, the inherent type-unsafe nature of the C language leads to problems if a variadic function is used with untrusted input, since the function doesn’t inherently know how many arguments it has been invoked with.

The best-known variadic function in the C programming language is printf(char* format, …). In this function, the first argument specifies the format string that determines how to process the subsequent arguments for printing (to the standard output in case of printf(), to a file in case of fprintf() and to a string in case of sprintf()). Thus, a format string like “Hello %s, you have %d points” indicates to printf() that there are two subsequent arguments; the first one has to be printed out as a string, and the second one as a signed integer.

However, if the format string doesn’t actually match the number and/or the types of the rest of the arguments, it will cause the function to perform unsafe memory operations.

Why a %s or %n can ruin your day – even today

If the developer mistakenly composes the format string from user input, the attacker can directly manipulate it. This vulnerability related to secure coding in C and C++ is called Use of Externally-Controlled Format String, and it has been a target of exploitation ever since the late 1980s. Since it affected a basic C function used by many different types of software, it was particularly popular in the 1990s and early 2000s. Since then, printf() itself has fallen out of fashion, and thus the exploitation of this vulnerability dropped as well; but lately it revived in some car infotainment systems, causing automotive security problems.

But how is it actually exploited? Consider that the printf() function can only determine the number of its arguments by parsing the format string. If the format string is incorrect, the function will nevertheless try to parse its stack (or other memory areas, depending on the compiler’s calling convention) according to it. This is a big problem by itself because it leaks potentially sensitive information from the memory of the program. Exploitation can potentially lead to stealing cryptographic keys or Personally Identifiable Information (PII). This is what we can see in the infotainment system photos: %x is used to dump 4 bytes of memory from the stack at a time, formatted as a hexadecimal string.

To take it one step further, the attacker can put a %s specifier into the format string. This tells the function to dereference the memory address on the stack at a certain position and process whatever is at that location as a string (char*). If the address cannot be dereferenced, this will crash the program; if it can be dereferenced, it will potentially leak some further data from the memory, like a password. But then it gets even worse: if the attacker uses the %n specifier, printf() will not READ, but instead WRITE a value (specifically, the number of characters printed out so far) to the memory address referenced on the stack.

automotive security, secure coding in C and C++, format string

If the attacker is crafty enough, they can exploit an arbitrary write vulnerability like this to overwrite a return address or any other code pointer, resulting in the CPU executing arbitrary code – so we have gone from a humble information leakage vulnerability to full Remote Code Execution (RCE)! RCE is the ‘holy grail’ of attackers; it is one of the most important concerns when it comes to secure coding, and especially secure coding in C and C++. Of course, these attacks are hard to carry out in practice, and thus they are quite popular in hacker contests (called CTFs). But hackers can be very persistent, especially if exploitation can allow them to – say – steal a high-value vehicle.

Everything old is new again in automotive security

Format string vulnerabilities have become significantly less relevant over the years. But there is still a particular area where they occur with some regularity: embedded systems.

A recent example is an exploitable format string vulnerability in the telnet server of the well-known INTEGRITY RTOS, discovered in 2019 (CVE-2019-7715). And at this point we go full circle, because the previously discussed vulnerabilities in car infotainment systems are all format string vulnerabilities. We can speculate why these vulnerabilities are in the code (Lack of awareness? Reliance on legacy code?), but the conclusion is clear from the automotive security perspective: format string vulnerabilities are just as important in 2021 as they were in 1989!

So, what can we do against these vulnerabilities? To bring some good news: compilers are quite good at detecting dangerous use of printf() and will warn the developer before it’s too late. Particularly, in the GCC compiler, the -Wformat -Werror=format-security flags will spot this vulnerability. Many source code analysis tools such as cppcheck can find it too. If you find a printf() vulnerability in your code, you can rewrite the code so that the format string does not contain any user input. If that is not possible, employ strict whitelist-based validation. In case your C library implements the optional bounds-checking interfaces defined in Annex K of C11, use printf_s() instead of printf() – it forbids the use of the %n specifier completely, preventing code execution.

Of course, this is just the tip of the iceberg. A programming language like C has many similar pitfalls that can easily lead to critical vulnerabilities, jeopardizing automotive security in various ways.

In our courses, you can understand how these vulnerabilities can affect your code, and what you can do about them – just check out all subjects related to C and C++. Focusing specifically on automotive security, Secure coding in C and C++ for automotive adds essential awareness that all developers should have about the environment in which they develop code, like guidelines and standards (such as the MISRA C of The Motor Industry Software Reliability Association). That course also presents a number of real-world case studies from the automotive domain, just like what we discussed in this article.