Zscaler Blog
Get the latest Zscaler blog updates in your inbox
SubscribeThreatLabz Discovers 117 Vulnerabilities in Microsoft 365 Apps Via the SketchUp 3D Library - Part 1
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 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
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
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
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
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
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
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 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
3. Spectre::Transcoder::ImporterSKP::ExportComponentInstance (Shown in Figure 11)
- SUComponentInstanceGetDefinition
- SUGroupToDrawingElement
- SUComponentDefinitionGetEntities
- SUDrawingElementGetMaterial
- Spectre::Transcoder::ImporterSKP::ExportEntities
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
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
6. Spectre::Transcoder::SkpUtils::GetTextureId (Shown in Figure 14)
- SUTextureWriterLoadFace
- SUGroupToDrawingElement
- SUTextureWriterLoadEntity
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
8. Spectre::Transcoder::ImporterSKP::AddFacesGeometry (Shown in Figure 16)
- SUMeshHelperCreate
- SUMeshHelperGetNumVertices
- SUMeshHelperGetNumTriangles
- SUMeshHelperGetVertexIndices
- SUMeshHelperGetVertices
- SUMeshHelperGetNormals
- SUMeshHelperGetBackSTQCoords
- SUMeshHelperGetFrontSTQCoords
- SUMeshHelperRelease
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
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
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
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
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:
- https://3dwarehouse.sketchup.com/my_3d_warehouse
- https://www.cgtrader.com/3d-models?free=1&file_types[]=14
- https://sketchup.cgtips.org/
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:
- 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
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::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
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.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:
- Gather thousands of samples for the 30 different image file formats supported by the library.
- Minimize the collected samples for each image format using winafl-cmin.py.
- 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
The following steps were performed:
- Obtain the size of the crafted image file (PoC file for FreeImage).
- Replace the image data in the SKP template file with the specially crafted image file.
- 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.
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.
Was this post useful?
Get the latest Zscaler blog updates in your inbox
By submitting the form, you are agreeing to our privacy policy.