Binarly REsearch team investigates vulnerable image parsing components across the entire UEFI firmware ecosystem and finds all major device manufacturers are impacted on both x86 and ARM-based devices.
[ See previous blog post “The Far-Reaching Consequences of LogoFAIL” preview of Black Hat EU presentation ]
As discussed in our previous blog, security defects in image parsers expose significant attack surfaces across the entire UEFI firmware ecosystem. Our LogoFAIL research, presented at Black Hat EU today, discusses a set of security vulnerabilities affecting all major device manufacturers on both x86 and ARM-based devices.
In this post, we discuss the motivation for the research, how we used fuzz-testing to discover this set of vulnerabilities, how we built a proof-of-concept to show the path to arbitrary code execution.
Most image parsers exist to make it possible to display logos during boot or in BIOS setup. However, vendors introduce features, like customization of a device’s boot logo, that allow users to specify data input for these parsers. This feature creates an additional and very serious threat to the security of modern devices.
Some raw realities:
Keeping in mind classical firmware supply chain complexity and its asynchronous nature, we asked ourselves: what if the graphic image parsers embedded into system firmware do not update frequently and use not only outdated but also customized versions of the common image parsing libraries?
While researching image parsers, our REsearch team realized that the impact of these sightings on the entire UEFI firmware industry is significant, so we decided to reference the exposed attack surfaces as LogoFAIL.
Earlier this year, our research team looked at some of the vulnerabilities discovered by the Binarly Transparency Platform and found that the number of image parsers have significantly increased over the years.
To identify how image data can reach the code in each parser, we used a bottom-up approach: starting from the image parsing function, we then just look “backwards” to find the sources of image data.
For example, in the previous screenshot, the ParseImage()
function receives the output of the GetImage()
function exported by EfiOemBadgingProtocol
. By further analyzing GetImage()
, we can understand how the ImageData variable is created and thus where the logo image is read from.
Normally, the logo is read directly from a firmware volume. Since the volumes are often signed and protected by a hardware-based Verified Boot technology (e.g., Intel Boot Guard), an attacker cannot store a custom logo there — that’s it, as long as the OEM private keys used to sign these sections are not leaked affecting the entire industry. But in this case, an attacker wouldn't care about the logo at all, because it allows them to inject any custom modules instead.
In other cases, OEM-specific customizations allow users to supply their own logo, so attackers can do that too. Most of these OEMs-specific customization read the logo from the EFI System Partition (ESP), a disk partition that is used by system firmware to load additional software such as boot loaders.
Given its role in the UEFI boot process, the ESP has been targeted by modern UEFI bootkits (such as ESPecter and FinSpy) by replacing OS bootloaders and achieving persistency.
Our advisories BRLY-2023-006 and BRLY-2023-018 contain a complete overview of the OEM-specific customizations we found, but in general we observed the following behaviors:
“\EFI\OEM\Logo.jpg”
;These customization features represent a new attack surface because they allow attackers to modify the logo parsed during system boot and mount data-only attacks.
Keep in mind that even when none of the above customization methods are available, a device can still be exploited with a physical attack if the firmware region containing the logo is not covered by Boot Guard. In this case, the attack can be performed using an SPI flash programmer to inject the logo.
Certainly, this attack vector is worth being thoroughly researched to help the industry protect from such threats. However, the amount of code to be analyzed is huge, and for this reason, we decided to expand Binarly's internal program analysis framework, which empowers our products and supports instrumentation with emulation, to help manage this task. We were able to find all the documented vulnerabilities via fuzz-testing.
The sheer volume and severity of security problems we found during this research is further proof of the endemic security problems that affect the firmware supply chain ecosystem:
PS: This table does not cover all vendors in the device manufacturing industry. Our main priority was to research major UEFI IBVs, since the vulnerable parsers are in the codebase maintained by them as shown in the picture below.
We are constantly expanding our firmware dataset to improve coverage and detection capabilities of the Binarly Transparency Platform. It allowed us to determine that image parsers are common in device’s firmware. They are used to process not only most popular image formats like BMP, PNG and JPEG, but also more esoteric and less-known formats such as PCX and TGA. And all of them contain multiple high-impact security vulnerabilities.
Allowing users, and thus potentially attackers, to customize their boot logo would be a totally acceptable behavior if the image libraries used to parse the logo did not contain any security flaws. To prove this point, we decided to run a fuzzer against these parsers, as fuzz-testing is very suited for finding bugs in parsing code. Our fuzzer is based on emulation capabilities that we developed for this research, which were specifically designed to be easily integrated with the modern fuzzing environment LibAFL.
After this, we prepared a fuzzing harness for every parser we discovered. The harness is a crucial component for fuzzing, since it initializes the environment and allows the fuzzer to interact with the program under test. In our case, the harness receives an image generated by the fuzzer, invokes the parsing function by setting the correct arguments and then checks for any crashes.
We then started a fuzzing campaign and fuzzed each parser for a variable period of time depending on the parser’s complexity. When the campaign finished, we were overwhelmed by the amount of crashes we found, so much that triaging them manually was going to be challenging. For this reason, we decided to expand Binarly's internal program analysis framework, which empowers our products and supports instrumentation with emulation, to support us in this task.
The table above breaks down the triaged crashes per vendor and image parser. In total, we found 29 unique crashes, out of which we consider 15 to be exploitable with arbitrary code execution as a likely outcome.
These results also show the scope and the impact of LogoFAIL, since each IBV has at least one exploitable bug inside their parsers, and every parser contains bugs. The only exception is Insyde’s PNG parser that is based on an open-source project, and was likely already well-tested by the community. As we can see from the CWE column, we found a lot of different bug classes, from division-by-zero exceptions to NULL pointer dereference, from out-of-bounds reads to heap overflows.
This triaging process gave us a good understanding of the root causes behind these vulnerabilities. While they cover a wide range of software security problems, the underlying theme is a lack of validation on attacker-supplied data.
For example, the first screenshot shows a bug in the BMP parser of Insyde. This bug is present in the code supporting the RLE4/RLE8 compression, a feature we haven’t seen in any other BMP parsers. This vulnerability manifests itself when PixelHeight
(which is under the control of the attacker) and the variable i is 0. In this case, the variable Blt
will be initialized to the address of BltBuffer[PixelWidth * -1]
. In other words, the attacker can arbitrarily set Blt
to any address below BltBuffer
, and thus corrupt this memory when Blt
is used to write.
The second screenshot is taken from the PNG parser of AMI and contains two different security vulnerabilities. The first bug is a missing check on the return value of the “EfiLibAllocateZeroPool
” function, which returns NULL
on failure. The second bug is an integer overflow on the 32-bit integer representing the allocation size. When the attacker sets the variable “PngWidth
” to a large value, the multiplication by two will make the result overflow around and become a small value (for example: 0x80000200 * 2 = 0x400
). In this way, the attacker can force the allocation of a buffer that is too small to hold the decoded PNG data and thus overflow the buffer when it is used.
The results from our fuzzing and subsequent bug triaging unequivocally say that none of these image parsers were ever tested by IBVs or OEMs. We can confidently say this because we found crashes in almost every parser we tested. Moreover, the fuzzer was able to find the first crashes after running just for a few seconds and, even worse, certain parsers were crashing on valid images found on the Internet.
In the firmware ecosystem, any bug can have profound consequences on the entire platform security and must therefore be addressed and fixed promptly. We decided to prove the severity of our findings by turning one of the crashes found by the fuzzer into arbitrary code execution during the DXE phase. We decided to postpone the release of the nitty-gritty details behind our PoC to give more time to end-users and vendors to patch and mitigate LogoFAIL.
The crash we selected as a starting point for developing the exploit is the integer overflow in the PNG parser discussed in the previous section. This picture shows a high-level overview of how this PNG parser works. Starting from the PNG image, the parser first locates and extracts the PNG chunks of the image. In particular, it finds the IHDR chunk to retrieve some information regarding the image, such as the width and height, and it concatenates all the IDAT chunks, which contains the PNG image data, into a single buffer (called “Compressed IDAT chunks” in the previous figure). The parser then decompresses the compressed IDAT chunks and writes the results to the “OutputBuffer.”
The value affected by the integer overflow depends on the image width (so it’s attacker controlled) and it’s used as an allocation size for the OutputBuffer. The attacker is therefore able to allocate an OutputBuffer that is too small and that will be overflown with attacker-controlled data during the decompression phase. By using this bug, it’s straightforward to overflow an arbitrary amount of attacker-controlled data on the UEFI heap.
From heap overflow to arbitrary code execution, the road is still long and winding. For now, we just want to anticipate that it involves a new exploitation technique for preserving allocated chunks and the corruption of core UEFI objects (PROTOCOL_ENTRY
) to hijack the control flow.
As a proof of all we said in this blog, and in particular in this last section, we release the following video showing how an exploitation chain for LogoFAIL looks on a real device. After logging in, we start a terminal with Admin privileges. We then check that Secure Boot and Intel Boot Guard (Verified Boot) are enabled, and run the proof of concept. The PoC prepares some of the aforementioned objects, saves the malicious PNG file inside an NVRAM variable, and finally restarts the device. During the boot, the system firmware will parse the injected PNG and so the LogoFAIL attack will take place. In the video we demonstrate arbitrary code execution during DXE phase by printing a message on the display and by showing that our final payload is able to create a file on the Windows file system.
Since the vulnerable parsers are developed and distributed by the IBVs – AMI, Insyde and Phoenix – a large percentage of devices UEFI firmware image out there contains a parser vulnerable to LogoFAIL. This is also confirmed by the data our platform constantly scans. Thanks to our triaging efforts, we were able to produce rules for fwhunt, our firmware vulnerability scanner, and confirm that every OEM is impacted by this supply chain problem. As we can see in the following table, we detected parsers vulnerable to LogoFAIL in hundreds of devices sold by Lenovo, Supermicro, MSI, HP, Acer, Dell, Fujitsu, Samsung and Intel.
The exploitability of these vulnerabilities relies on whether the user is able to input data to a parser. When these parsers are used to display a logo during boot and when this logo can be replaced by an attacker, using any of the OEM customization techniques described in the Attack Surface section of this blogpost, then LogoFAIL becomes an exploitable threat. And there are multiple scenarios that could lead to it:
The main restriction of latter cases are explained in the following pictures. Some vendors such as Dell are not directly exploitable for two reasons. First, as shown in the previous screenshots, Dell distributes firmware where the logo is covered by Intel Boot Guard and thus cannot be replaced by an attacker, even using a physical attack. Second, Dell doesn’t provide any logo customization and so it effectively secures the LogoFAIL attack surface. However, despite these devices not being at immediate risk, they still contain image parsers with high-severity vulnerabilities that need to be fixed, as they represent a hazard that could inadvertently turn into a security issue.
Some important things to keep in mind:
Are you interested in learning more about Binarly Transparency Platform or other solutions? Don't hesitate to contact us at [email protected].