11/01/2023 | News release | Distributed by Public on 10/31/2023 21:33
Reverse engineering plays a critical role in uncovering and understanding software vulnerabilities, as it allows cybersecurity experts to dissect and analyze code - providing valuable insights into how potential weaknesses and security flaws can be exploited or mitigated.
Office 3D Parsing
The dynamic library MSOSPECTRE.DLL(shown in Figure 5) is responsible for parsing 3D file formats in Microsoft 365 apps. Our vulnerability research on the SketchUp file format was conducted in version 16.0.16026.20000, which was released in January 2023.
Figure 5: MSOSPECTRE.DLL is responsible for parsing 3D file formats in Microsoft 365 apps
During our analysis of MSOSPECTRE.DLLusing IDA Pro, a series of functions with names prefixed with "SU" caught our attention, as depicted in Figure 6. It's worth noting that these functions are, in fact, SketchUp C APIs sourced from the SketchUp SDK.
Figure 6: A bunch of functions with name prefixed with "SU" in IDA Pro
By combining reverse engineering MSOSPECTRE.DLLwith dynamic debugging, we determined the function Spectre::Transcoder::ImporterSKP::ImportToAsset3Dis responsible for parsing an SKP file in Microsoft 365 apps. Figure 7 provides a code snippet of its pseudo code.
Figure 7: The function Spectre::Transcoder::ImporterSKP::ImportToAsset3D
This function calls a sequence of SketchUp APIs and certain wrapper functions that, in turn, invoke additional SketchUp APIs, as demonstrated below.
Now, we'll examine the implementation for each of these wrapper functions.
1. Spectre::Transcoder::ImporterSKP::CountEntities(Shown in Figure 8)
Figure 8: Spectre::Transcoder::ImporterSKP::CountEntities
Figure 9: Spectre::Transcoder::ImporterSKP::CountComponentInstance
2. Spectre::Transcoder::ImporterSKP::ExportEntities(Shown in Figure 10)
Figure 10: Spectre::Transcoder::ImporterSKP::ExportEntities
3. Spectre::Transcoder::ImporterSKP::ExportComponentInstance(Shown in Figure 11)
Figure 11: Spectre::Transcoder::ImporterSKP::ExportComponentInstance
4. Spectre::Transcoder::ImporterSKP::ExportFaces(Shown in Figure 12)
Figure 12: Spectre::Transcoder::ImporterSKP::ExportFaces
5. Spectre::Transcoder::ImporterSKP::GetMaterial(Shown in Figure 13)
Figure 13: Spectre::Transcoder::ImporterSKP::GetMaterial
6. Spectre::Transcoder::SkpUtils::GetTextureId(Shown in Figure 14)
Figure 14: Spectre::Transcoder::SkpUtils::GetTextureId
7. Spectre::Transcoder::ImporterSKP::GetTexture(Shown in Figure 15)
Figure 15: Spectre::Transcoder::ImporterSKP::GetTexture
8. Spectre::Transcoder::ImporterSKP::AddFacesGeometry(Shown in Figure 16)
Figure 16: Spectre::Transcoder::ImporterSKP::AddFacesGeometry
Throughout our reverse engineering process, we successfully analyzed all of the relevant functions involved in parsing SKP files within the Office 3D component. In particular, we discovered Microsoft leveraged a series of SketchUp C APIs to implement the functionality to parse an SKP file.
SketchUp provides an SDK, including a C API. The online C API documentationcontains reference material for all functions, data structures, and enumerations in both the SketchUp C API and the SketchUp Importer/Exporter interface. This was helpful to create and refine our SketchUp fuzzing harness.
Numerous SketchUp APIs were used in the fuzzing harness. We will highlight some key functions below.
Figure 17: The function SUModelCreateFromBufferWithStatus
The function SUModelCreateFromBufferWithStatustakes 4 parameters, where the 2nd and 3rd parameters are input parameters, and the 1st and 4th parameters are output parameters.
Creating a harness for fuzzing
Now, we'll explore how to develop a harness for fuzzing the Office 3D component MSOSPECTRE.DLL. Figure 18 provides an overview of the source code of our SketchUp harness.
Figure 18: An overview of the source code for our SketchUp harness
In this code, we declared various SketchUp APIs and implemented several wrapper functions, which were derived from reverse engineering the Office 3D component.
Figure 19 provides a code snippet for our SketchUp fuzzing harness. In the main function, the first step loads MSOSPECTRE.DLLusing the LoadLibrary API, which returns the base address of MSOSPECTRE.DLL in memory. Then the function SUInitialize is called to initialize the SketchUp API functions. Once initialization occurs, the function fuzzme() is called. To ensure proper cleanup, the function SUTerminate is called.
Figure 19: A code snippet of our SketchUp fuzzing harness
The function fuzzme()implements the functionality found in the method Spectre::Transcoder::ImporterSKP::ImportToAsset3Din MSOSPECTRE.DLLas shown in Figure 20.
Figure 20: The function fuzzme() in harness
With our SketchUp harness complete, the next important step is setting up a fuzzer to effectively test it as follows:
1. Gather thousands of samples of SKP files from various websites. For example:
2. To make the fuzzing process efficient, narrow down this collection to a smaller group of SKP files using winafl-cmin.py.
Note:While integrating this harness into WinAFL, we encountered a timeout issue. This might have been due to the slightly longer time it takes to parse an SKP file within this harness.
Despite the timeout challenge, we adopted a dumb file format fuzzer, which proved to be a workable solution. Ultimately, this approach led to impressive results, uncovering a total of 20 unique vulnerabilities illustrated in Figure 21 in just one month. These findings include various types of vulnerabilities such as use-after-free, heap buffer overflow, integer overflow, out-of-bounds write, type confusion, stack buffer overflow, etc.
Figure 21: Vulnerabilities discovered by ThreatLabz through SketchUp harness
SKP file format
Through reverse engineering, we also uncovered that SKP files support two distinct data types:
As shown in Figure 22, the function SketchUpModelReader::ReadModelis used to read data from an SKP file. If a VFF header is present in the SKP file, it calls SketchUpModelReaderVFF::ReadModelto handle VFF type data. Otherwise, it calls SketchUpModelReaderMFC::ReadModelto handle MFC type data.
Figure 22: The function SketchUpModelReader::ReadModel in MSOSPECTRE.DLL
We created a diagram in Figure 23 for the MFC data type structure thanks to our analysis of SketchUpModelReaderMFC::ReadModel. The structure starts with a SketchUp header, then a GUID, followed by a versionMap, and other specific data. Inside the versionMap and data sections, there are often bytes that start with FF FE FF, followed by a length field (1 byte), and then a Unicode string. After the Unicode string, there is specific data.
Figure 23: The SKP file structure of MFC data type
Next, we will explore the structure of an SKP file with the VFF data type. As illustrated in Figure 24, the structure starts with a SketchUp header, followed by a VFF header, and then a ZIP file. The VFF header contains 13 bytes of data, which includes the magic bytes 'VFF', followed by a length field indicating the length of the remaining VFF header, and then 4 bytes (currently unknown), and then a 4-byte checksum.
Figure 24: The SKP file structure of the VFF data type
Figure 25 shows a stack backtrace for a crash that indicates that the data type within the SKP file is the MFC type.
Figure 25: The stack backtrace of an SKP PoC file with an MFC type
The crash occurs during the parsing of a JPEG file embedded with the SKP file. What makes this finding particularly interesting is that another third-party library, FreeImage, is used to parse the image file embedded within an SKP file.
When comparing a normal SKP file to the minimized SKP PoC file, only 1 byte is mutated within a JPEG image that's part of the 'materials' structure in the SKP file (as shown in Figure 26).
Figure 26: Comparison between a normal SKP file and the minimized SKP PoC file
As shown in Figure 27, the function MSOSPECTRE!FreeImageUtils::CreateBmpFromMemoryparses the image file embedded within an SKP file. Figure 27 illustrates its pseudo code that calls a series of FreeImage APIs.
Figure 27: The function MSOSPECTRE!FreeImageUtils::CreateBmpFromMemory
FreeImage is an open-source library designed for developers who want to provide support for various popular graphic image formats including PNG, BMP, JPEG, TIFF, WEBP, and more. FreeImage has the capability to handle 30 different types of image file formats, as illustrated in Figure 28. Interestingly, the last update to this library was made available in 2018. The extensive range of supported formats presents a significant attack surface for potential fuzzing efforts.
Figure 28: FreeImage supports 30 image file formats
We developed a harness named freeimage_harness.exedesigned for fuzzing FreeImage by implementing the functionality of the function MSOSPECTRE!FreeImageUtils::CreateBmpFromMemory in MSOSPECTRE.DLL.
Once we had the FreeImage harness ready, setting up a fuzzer was a straightforward task. We then took the following steps:
The result was very successful, discovering 97 unique vulnerabilities in just two months.
Next, we will take a look at the process of reproducing these vulnerabilities within Microsoft 365 apps through a SketchUp file. We created a SketchUp template file based on the MFC data type as shown in Figure 29.
The following steps were performed: