esDynamic
Manage your attack workflows in a powerful and collaborative platform.
Expertise Modules
Executable catalog of attacks and techniques.
Infrastructure
Integrate your lab equipment and remotely manage your bench.
Lab equipments
Upgrade your lab with the latest hardware technologies.
Side Channel Attacks
Evaluate cryptography algorithms from data acquitition to result visualisation.
Fault Injection Attacks
Laser, Electromagnetic or Glitch to exploit a physical disruption.
Photoemission Analysis
Detect photon emissions from your IC to observe its behavior during operation.
Evaluation Lab
Our team is ready to provide expert analysis of your hardware.
Starter Kits
Build know-how via built-in use cases developed on modern chips.
Cybersecurity Training
Grow expertise with hands-on training modules guided by a coach.
esReverse
Static, dynamic and stress testing in a powerful and collaborative platform.
Extension: Intel x86, x64
Dynamic analyses for x86/x64 binaries with dedicated emulation frameworks.
Extension: ARM 32, 64
Dynamic analyses for ARM binaries with dedicated emulation frameworks.
Penetration Testing
Identify and exploit system vulnerabilities in a single platform.
Vulnerability Research
Uncover and address security gaps faster and more efficiently.
Code Audit & Verification
Effectively detect and neutralise harmful software.
Digital Forensics
Collaboratively analyse data to ensure thorough investigation.
Software Assessment
Our team is ready to provide expert analysis of your binary code.
Cybersecurity training
Grow expertise with hands-on training modules guided by a coach.
Semiconductor
Automotive
Security Lab
Gov. Agencies
Academics
Defense
Healthcare
Energy
Why eShard?
Our team
Careers
Youtube
Gitlab
Github
Fuzz testing is a powerful way to find vulnerabilities by throwing unexpected inputs at software. But when something crashes? That’s where things get tricky.
Using CVE-2023-4041, a Secure Boot vulnerability, as our example, we’ll demonstrate how time travel analysis helps trace the root cause of a crash, assess its impact, and understand the flaw with speed and accuracy.
CVE-2023-4041 is a vulnerability present on the EFx32x modules, from Silicon Labs vendor, using the Gecko Bootloader before version 4.3.1. It was discovered and published by Quarkslab, and described in different conferences. They identified a flaw in the updating process which enabled them to get control of the execution flow. So, an unsigned firmware could be updated: the Secure Boot was bypassed.
The exploitation was carried out on the BGM220-EK4314A board (see image below), a low-cost (~20€) development kit equipped with an on-board debugger utilizing a Serial Wire Debug (SWD) interface. It's noteworthy that all Gecko Bootloader code and documentation are open source, with Silicon Labs providing a dedicated IDE and example code for rapid development.
This board supports Bluetooth connectivity, allowing seamless over-the-air (OTA) updates for the bootloader.
The update process can be secured with encryption and digital signatures, a mechanism referred to as Secure Boot by Silicon Labs. However, despite its name, it's important to note that Secure Boot only verifies firmware authenticity during updates, not at startup.
In their blog post, Quarkslab details the steps they took to identify and exploit the CVE-2023-4041 vulnerability.
Their blogpost provides a great overview of the entire vulnerability discovery process as well as exploitation. But, what was the difficulty in understanding a crash and tracing its origin?
Time Travel Analysis is a powerful technique that allows analysts to record and explore a program's complete execution history. Instead of repeatedly running the code, analysts capture a persistent dataset representing every step. This “execution trace” can be revisited at will, allowing analysts to rewind through time, pinpoint crucial moments, and investigate vulnerabilities, bugs, or unexpected behavior.
The ability to rewind through the execution history eliminates the need for repeated debugging sessions. We explored this in-depth in our comparison blogpost.
This analysis was conducted using esReverse platform. With its all-in-one environment, we created a project and integrated all the necessary tools for our analysis. This included the fuzzing tool AFL++, time travel debugging tool on an Arm binary, and static analysis tools like Ghidra and IDA.
Overview of IDA integrated into esReverse
To power time travel debugging, esReverse combines key emulation technologies. It uses QEMU, Unicorn, or Qiling to run the binary and capture a full execution trace. Once recorded, this trace can be explored in depth, either through a user-friendly graphical interface or directly via Python scripts for full control.
Our target: the GBL (Gecko BootLoader) file format used for bootloader updates.
The update process uses a proprietary format called Gecko BootLoader (GBL), which employs a Tag Length Value (TLV) structure. In this format, each piece of information is represented as a triplet:
This structure allows for flexible and straightforward parsing of the update file.
The GBL file contains more than just the code. It also includes essential metadata about the update, such as:
Here's a snippet of a GBL file, along with an explanation of its structure.
This intricate structure necessitates a parser to analyze and interpret the GBL file. It is within this parser that the vulnerability lies.
We used a firmware emulation with Unicorn and AFL++ for fuzzing. Notably, one crash caused Unicorn to halt, indicating the execution of an invalid instruction.
A snippet of this GBL file is given below.
It's a perfect case to analyze with time travel analysis: understanding what happens during the crash and its origin.
As described at another blog post of ours, generating a time travel analysis trace from a Python Unicorn script is straightforward:
unicorn.mem_map
and unicorn.mem_write
methods with reven_unicorn.mem_map
and reven_unicorn.mem_write
, respectively.Since less than 40 000 instructions are emulated, the time travel trace generation does not affect Unicorn's emulation performance in our case: the emulation and trace generation are immediate. The generated TTA files collectively weigh less than 2 MB.
We are now ready to display this trace and understand the crash's origin!
The time travel debugger's user interface was used to dive into the generated trace:
Opening the generated trace with the user interface brings us to the main interface as seen in the image below.
Moving forward, we will refer to the number displayed for each instruction in the “1. Disassembly” view as the 'transition'. This name is chosen because of the “2. CPU” view shows us the register values both before and after an instruction's execution.
When we start from the middle of the trace, we notice the same instruction repeating continuously, strongly suggesting that incorrect code is being executed.
We can quickly trace back to the last correctly executed instructions at transition 7468.
0xA38
and belongs to the parser_parse function.0x20000CDC
to 0x20000D00
. We will use this information later on.
It's clear that an incorrect PC value is restored. The key question now is the cause of this alteration: are we dealing with stack pointer corruption or a stack overflow?The time travel debugger user interface provides a backtrace feature, which lists the sequence of function calls leading to the current execution point, helping to trace the flow of execution and diagnose issues. We used it to verify whether returning to the previous functions work correctly.
advanceParser
function to the parser_parse
function during the transition 3890.0x20000CF0
.0x20000D00
to 0x20000CDC
, perfectly reflecting the behavior of transition 7468. This suggests that the SP register remained intact and was not corrupted.Therefore, it must be a stack overflow, which has overwritten the return PC value stored at 0x20000CF0
. A quick bird’s-eye view of all the reading and writing operations affecting a specific memory location are possible. Ticking “Show access history of selection” in the “Memory History Access” immediately shows all the memory accesses.
0x25DC
: STRB R2, [R7, R3]
. Also, we are inside the gbl_getData
function.This conclusion is confirmed when opening the ELF code file in IDA, for example:
gbl_getData
function.gbl_getData
function’s parameters.We compiled the binary from the source code, and took this opportunity to link the call to the gbl_getData
function, which is at the address 0xAE0, to the source code for a clearer view. We can use addr2line
tool, for instance.
addr2line -fiC -e bootloader-storage-internal-single-512k.axf -a 0xae0 0x00000ae0 parser_parseApplicationInfo gecko_sdk/platform/bootloader/parser/gbl/btl_gbl_parser.c:1304 parser_parse gecko_sdk/platform/bootloader/parser/gbl/btl_gbl_parser.c:627
The following source code excerpt corresponds to the previous findings.
// gecko_sdk/platform/bootloader/parser/gbl/btl_gbl_parser.c:L626 case GblParserStateApplication: retval = parser_parseApplicationInfo(parserContext, &input, imageProperties); if (retval != BOOTLOADER_ERROR_PARSER_PARSED) { return retval; } break;
// gecko_sdk/platform/bootloader/parser/gbl/btl_gbl_parser.c:1295 static int32_t parser_parseApplicationInfo(ParserContext_t *parserContext, GblInputBuffer_t *input, ImageProperties_t *imageProperties) { volatile int32_t retval; uint8_t tagBuffer[GBL_PARSER_BUFFER_SIZE]; while (parserContext->offsetInTag < parserContext->lengthOfTag) { // Get data retval = gbl_getData(parserContext, input, tagBuffer, parserContext->lengthOfTag, true, true);
gecko_sdk/platform/bootloader/parser/gbl/btl_gbl_parser.h:60 /// GBL parser buffer size #define GBL_PARSER_BUFFER_SIZE 64UL
We conclude the following:
parser_parseApplicationInfo
function, meaning that we are parsing the GBL Application Info Tag
structure. You can also notice we do not see this function parser_parseApplicationInfo
in the assembly code, simply meaning it was inlined.gbl_getData
function, and is stored in the local array tagBuffer
which has 64-byte size.GBL Application Info Tag
, named parserContext->lengthOfTag
in the source code, determines the amount to copygbl_getData
:
0x20000C98
, located in the stack.gbl_getData
function responsible for this copy didn't check if the length field within the structure was smaller than or equal to 64 bytes. This unchecked copying ultimately led to the stack overflow vulnerability.So, an attacker can exploit this by carefully crafting malicious GBL to overwrite data on the stack, especially the saved Program Counter (PC). This gives him the ability to hijack control of the program's execution flow and potentially take complete control of the system. Our findings lead us to the same conclusion presented in Quarkslab's article, even if there are a few differences between our analyzed crash and the one described in their article:
The final piece of the puzzle is identifying the specific bytes within the GBL that corrupt the saved Program Counter (PC) value. It will enable crafting malicious GBL updates to jump to any location in the bootloader’s code.
0x20000C98
and the PC value is saved at 0x20000CF0.The following provides a concise summary of our investigative work.
This work leverages Quarkslab blog post titled breaking secure boot on the Silicon Labs Gecko Platform which details how the CVE-2023-4041 vulnerability was identified and exploited through a fuzzing campaign. The blogpost provides an overview of the entire vulnerability discovery process as well as exploitation. However, a key question remains: how challenging was it to interpret a crash and trace its origin?
The purpose of this post is to see how time travel analysis could accelerate the identification and the understanding of the flaw. For this, we generated a time travel analysis trace from a fuzzing crash and analyzed. We could confirm that the tool was efficient to mitigate both the time and complexity for identifying the flaw.
Initially reserved to complex analyses involving full systems emulation, this blogpost shows that the recent developments open more opportunities to leverage Time Travel Analysis for boosting security investigations and improve their depth and length in the IoT or connected object space.