Concerned about recent PAN-OS and other firewall/VPN CVEs? Take advantage of Zscaler’s special offer today

Zscaler Blog

Get the latest Zscaler blog updates in your inbox

Subscribe
Security Research

ThreatLabz Discovers 117 Vulnerabilities in Microsoft 365 Apps Via the SketchUp 3D Library - Part 1

image

Introduction

Microsoft launched support for SketchUp (SKP) files in June 2022 and in doing so, unknowingly introduced numerous vulnerabilities to Microsoft 365 applications. Within approximately three months, our research efforts unveiled 117 unique vulnerabilities. Microsoft assigned CVE-2023-28285, CVE-2023-29344, and CVE-2023-33146 to catalog these vulnerabilities. Consequently, Microsoft took the precautionary step of temporarily disabling SketchUp support in Microsoft 365 in June 2023. In this blog post, we will share the methodologies used to uncover these vulnerabilities and provide technical details for some of the vulnerabilities. This is Part 1 of our two-part series. The second part will be available soon.

Key Takeaways

  • The ThreatLabz research team discovered 117 vulnerabilities in Microsoft 365 applications, which were introduced when the SKP file format was added.
  • Microsoft assigned 3 CVEs to track these vulnerabilities: CVE-2023-28285, CVE-2023-29344, and CVE-2023-33146.
  • Microsoft created a patch to address the vulnerabilities that ThreatLabz was able to bypass.
  • Microsoft disabled support for the SketchUp file format in Office as a result.

Background

Towards the end of December 2022, Zero Day Initiative (ZDI) published 4 vulnerability advisories related to Microsoft Office SKP files. Those were the first observed SKP file parsing vulnerabilities in Microsoft Office. This discovery triggered our interest in the specific component responsible for parsing SKP files.

Figure 1: 4 vulnerability advisories about Microsoft Office SKP files from ZDIFigure 1: 4 vulnerability advisories about Microsoft Office SKP files from ZDI

Introduction to 3D Models in Microsoft 365

The Office 3D component is a feature within Microsoft 365 apps that facilitates the integration and manipulation of 3D content into various Office applications. This component empowers users to work with 3D models, making it especially valuable for tasks such as creating presentations, visualizing data, or enhancing the overall user experience. The list below represents the 7 supported 3D formats within Microsoft 365 apps.

  • Binary GL Transmission Format *.glb
  • Filmbox Format *.fbx
  • Object Format *.obj
  • 3D Manufacturing Format *.3mf
  • Polygon Format *.ply
  • StereoLithography Format *.stl
  • SketchUp *.skp (New!)

In 2022, the SketchUp file format was introduced as a new 3D file format to Microsoft 365 apps. It's important to note that various other 3D file formats have long-standing support within Microsoft 365 apps. As a general rule, the introduction of a new feature, such as the support of SketchUp files, may introduce security vulnerabilities.

SKP File Format

SKP is a proprietary file format developed by SketchUp Software for 3D modeling and design. An SKP file contains data and information necessary to create and render 3D models, including geometry, textures, materials, and more. The SKP format was originally developed in 2000 by @Last Software. Google acquired the SKP format in 2006, and then Trimble Navigation took ownership in 2012. The popularity of SketchUp has continued to grow and it was recently named the #1 architecture software program in the world (as shown in Figure 2), based on G2’s Grid® Report for Architecture, Spring 2023.

Figure 2:  G2’s Grid® Report for Architecture, Spring 2023

Figure 2:  G2’s Grid® Report for Architecture, Spring 2023

In June 2022, Microsoft officially announced the integration of SketchUp file support into their Office applications for both Windows and Mac platforms as shown in Figure 3.

Figure 3: Add SketchUp files to Office creations

Figure 3: Add SketchUp files to Office creations

SketchUp files are inserted into an Office document by selecting Insert → 3D Models and then choosing a SketchUp file as shown in Figure 4.

Figure 4: Process to insert SKP files into an Office document

Figure 4: Process to insert SKP files into an Office document

Reverse Engineering the Office 3D Component

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

Figure 5: MSOSPECTRE.DLL is responsible for parsing 3D file formats in Microsoft 365 apps

During our analysis of MSOSPECTRE.DLL using 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

Figure 6: A bunch of functions with name prefixed with “SU” in IDA Pro

By combining reverse engineering MSOSPECTRE.DLL with dynamic debugging, we determined the function Spectre::Transcoder::ImporterSKP::ImportToAsset3D is 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

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.

  • SUInitialize
  • SUModelCreateFromBufferWithStatus
  • SUTextureWriterCreate
  • SUModelGetRenderingOptions
  • SUModelGetEntities
  • Spectre::Transcoder::ImporterSKP::CountEntities
  • Spectre::Transcoder::ImporterSKP::ExportEntities

Now, we’ll examine the implementation for each of these wrapper functions.

1. Spectre::Transcoder::ImporterSKP::CountEntities (Shown in Figure 8)

  • SUEntitiesGetNumGroups
  • SUEntitiesGetGroups
  • Spectre::Transcoder::SkpUtils::IsVisible
  • Spectre::Transcoder::ImporterSKP::CountEntities
  • SUEntitiesGetNumInstances
  • SUEntitiesGetInstances
  • Spectre::Transcoder::ImporterSKP::CountComponentInstance (Shown in Figure 9)
  • SUEntitiesGetNumFaces
  • Spectre::Transcoder::SkpUtils::GetRenderingOptionValue
  • SUEntitiesGetNumEdges

Figure 8: Spectre::Transcoder::ImporterSKP::CountEntities

Figure 8: Spectre::Transcoder::ImporterSKP::CountEntities

Figure 9: Spectre::Transcoder::ImporterSKP::CountComponentInstance

Figure 9: Spectre::Transcoder::ImporterSKP::CountComponentInstance 

2. Spectre::Transcoder::ImporterSKP::ExportEntities (Shown in Figure 10)

  • SUEntitiesGetNumGroups
  • SUEntitiesGetGroups
  • SUGroupToDrawingElement
  • Spectre::Transcoder::ImporterSKP::ExportEntities
  • SUEntitiesGetNumInstances
  • SUEntitiesGetInstances
  • Spectre::Transcoder::ImporterSKP::ExportComponentInstance
  • SUEntitiesGetNumFaces
  • SUEntitiesGetFaces
  • Spectre::Transcoder::ImporterSKP::ExportFaces
  • SUEntitiesGetNumEdges
  • SUEntitiesGetEdges
  • SUEdgeGetSoft
  • SUEdgeGetStartVertex
  • SUEdgeGetEndVertex
  • SUVertexGetPosition
  • Spectre::Transcoder::SkpUtils::ToVector3

Figure 10: Spectre::Transcoder::ImporterSKP::ExportEntities

Figure 10: Spectre::Transcoder::ImporterSKP::ExportEntities 

3. Spectre::Transcoder::ImporterSKP::ExportComponentInstance (Shown in Figure 11)

  • SUComponentInstanceGetDefinition
  • SUGroupToDrawingElement
  • SUComponentDefinitionGetEntities
  • SUDrawingElementGetMaterial
  • Spectre::Transcoder::ImporterSKP::ExportEntities

Figure 11: Spectre::Transcoder::ImporterSKP::ExportComponentInstance

Figure 11: Spectre::Transcoder::ImporterSKP::ExportComponentInstance

4. Spectre::Transcoder::ImporterSKP::ExportFaces (Shown in Figure 12)

  • Spectre::Transcoder::SkpUtils::GetEffectiveMaterial
  • Spectre::Transcoder::ImporterSKP::GetMaterial
  • Spectre::Transcoder::ImporterSKP::AddFacesGeometry

Figure 12: Spectre::Transcoder::ImporterSKP::ExportFaces

Figure 12: Spectre::Transcoder::ImporterSKP::ExportFaces

5. Spectre::Transcoder::ImporterSKP::GetMaterial (Shown in Figure 13)

  • SUMaterialGetType
  • SUMaterialGetUseOpacity
  • SUTextureGetAverageColor_0
  • Spectre::Transcoder::SkpUtils::GetMaterialColor
  • Spectre::Transcoder::SkpUtils::GetTextureId
  • Spectre::Transcoder::ImporterSKP::GetTexture
  • SUMaterialGetOpacity

Figure 13: Spectre::Transcoder::ImporterSKP::GetMaterial

Figure 13: Spectre::Transcoder::ImporterSKP::GetMaterial

6. Spectre::Transcoder::SkpUtils::GetTextureId (Shown in Figure 14)

  • SUTextureWriterLoadFace
  • SUGroupToDrawingElement
  • SUTextureWriterLoadEntity

Figure 14: Spectre::Transcoder::SkpUtils::GetTextureId

Figure 14: Spectre::Transcoder::SkpUtils::GetTextureId

7. Spectre::Transcoder::ImporterSKP::GetTexture (Shown in Figure 15)

  • SUImageRepCreate
  • SUTextureWriterGetImageRep
  • SUImageRepConvertTo32BitsPerPixel
  • SUImageRepGetDataSize
  • SUImageRepGetPixelDimensions
  • SUImageRepGetData
  • SUImageRepRelease

Figure 15: Spectre::Transcoder::ImporterSKP::GetTexture

Figure 15: Spectre::Transcoder::ImporterSKP::GetTexture

8. Spectre::Transcoder::ImporterSKP::AddFacesGeometry (Shown in Figure 16)

  • SUMeshHelperCreate
  • SUMeshHelperGetNumVertices
  • SUMeshHelperGetNumTriangles
  • SUMeshHelperGetVertexIndices
  • SUMeshHelperGetVertices
  • SUMeshHelperGetNormals
  • SUMeshHelperGetBackSTQCoords
  • SUMeshHelperGetFrontSTQCoords
  • SUMeshHelperRelease

Figure 16: Spectre::Transcoder::ImporterSKP::AddFacesGeometry

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 documentation contains 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. 

  • void SUInitialize (): Initializes the slapi interface. Must be called before calling any other API functions.
  • void SUTerminate (): Signals termination of the slapi interface. Must be called when done using API functions. 
  • enum SUResult SUModelCreateFromBufferWithStatus(SUModelRef *model, const unsigned char *buffer, size_t buffer_size, enum SUModelLoadStatus *status): Creates a model from a SketchUp skp file buffer.

Figure 17: The function SUModelCreateFromBufferWithStatus

Figure 17: The function SUModelCreateFromBufferWithStatus

The function SUModelCreateFromBufferWithStatus takes 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

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.DLL using 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

Figure 19: A code snippet of our SketchUp fuzzing harness

The function fuzzme() implements the functionality found in the method Spectre::Transcoder::ImporterSKP::ImportToAsset3D in MSOSPECTRE.DLL as shown in Figure 20.

Figure 20: The function fuzzme() in harness

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

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: 

  • MFC type 
  • VFF type

As shown in Figure 22, the function SketchUpModelReader::ReadModel is used to read data from an SKP file. If a VFF header is present in the SKP file, it calls SketchUpModelReaderVFF::ReadModel to handle VFF type data. Otherwise, it calls SketchUpModelReaderMFC::ReadModel to handle MFC type data.

Figure 22: The function SketchUpModelReader::ReadModel in MSOSPECTRE.DLL

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

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 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

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

Figure 26: Comparison between a normal SKP file and the minimized SKP PoC file

As shown in Figure 27, the function MSOSPECTRE!FreeImageUtils::CreateBmpFromMemory parses 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

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

Figure 28: FreeImage supports 30 image file formats

We developed a harness named freeimage_harness.exe designed 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:

  1. Gather thousands of samples for the 30 different image file formats supported by the library.
  2. Minimize the collected samples for each image format using winafl-cmin.py.
  3. Seamlessly integrate the FreeImage harness into WinAFL.

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.

Figure 29: A SketchUp template file with the MFC data type

Figure 29: A SketchUp template file with the MFC data type

The following steps were performed:

  1. Obtain the size of the crafted image file (PoC file for FreeImage).
  2. Replace the image data in the SKP template file with the specially crafted image file.
  3. Revise the size field (4 bytes), which is situated just before the image data.

     

Mitigation

All users of Microsoft 365 Apps are encouraged to upgrade to the latest version of this software. Zscaler’s Advanced Threat Protection and Advanced Cloud Sandbox can protect customers against these vulnerabilities.

Win64.Exploit.CVE-2023-28285

Win64.Exploit.CVE-2023-29344

Win64.Exploit.CVE-2023-33146

 

To Be Continued

In our journey through Part 1 of this series, we’ve explored how ThreatLabz reverse engineered 3D Models in Microsoft 365 and the SKP file format. In Part 2, we dive deeper into the vulnerabilities that we discovered and examine real-world case studies.

form submtited
Thank you for reading

Was this post useful?

dots pattern

Get the latest Zscaler blog updates in your inbox

By submitting the form, you are agreeing to our privacy policy.