Google SketchUp 'lib3ds' 3DS Importer Memory Corruption

Advisory ID Internal
CORE-2009-1209

1. Advisory Information

Title: Google SketchUp 'lib3ds' 3DS Importer Memory Corruption
Advisory Id: CORE-2009-1209
Advisory URL: www.coresecurity.com/core-labs/advisories/google-sketchup-vulnerability
Date published: 2010-01-13
Date of last update: 2010-01-12
Vendors contacted: Google
Release mode: Coordinated release

2. Vulnerability Information

Class: Failure to Constrain Operations within the Bounds of a Memory Buffer [CWE-119], Out-of-bounds Write [CWE-787]
Impact: Code execution
Remotely Exploitable: Yes (client-side)
Locally Exploitable: No
Bugtraq ID: 37708
CVE Name: CVE-2010-0280

3. Vulnerability Description

Google SketchUp is a 3D modeling program designed for architects, civil engineers, filmmakers, game developers, and related professions. Google SketchUp bundles an old version of 'lib3ds', a library used to process 3DS files. This library is being compiled in a way that leads to improper validation of data when importing 3DS files; this condition can be exploited by remote attackers to trigger a memory corruption vulnerability by enticing an unsuspecting user to open a specially crafted 3DS file, possibly leading to arbitrary code execution.

4. Vulnerable packages

  • Google SketchUp 7.0.10247
  • Google SketchUp 7.1.4871
  • Google SketchUp 7.1.6087
  • Older versions are probably affected too, but they were not checked.

5. Non-vulnerable packages

  • Google SketchUp 7.1.6859 (Windows and Mac OS X)

6. Vendor Information, Solutions and Workarounds

Users can download the latest version of Google SketchUp from http://sketchup.google.com

7. Credits

This vulnerability was discovered and researched by Francisco Falcon from Core Security during Bugweek 2009 [1].

The publication of this advisory was coordinated by Jorge Lucangeli Obes from Core Security Advisories team.

8. Technical Description / Proof of Concept Code

8.1. Introduction

Google SketchUp [2] is a 3D modeling program designed for architects, civil engineers, filmmakers, game developers, and related professions. Google SketchUp bundles an old version of 'lib3ds', a library used to process 3DS files. This library is being compiled in a way that leads to improper validation of data when importing 3DS files; this condition can be exploited by remote attackers to trigger a memory corruption vulnerability by enticing an unsuspecting user to open a specially crafted 3DS file, possibly leading to arbitrary code execution.

When processing certain structures from a 3DS file, Google SketchUp trusts bytes from the 3DS file without performing validations and uses them as:

  1. an operand in pointer arithmetics to calculate an index for an array where user-controlled data will be written.
  2. a loop counter in a copy operation.

These bytes are used by the application without proper validation of their values, leading to the issues described below.


8.2. Memory Corruption

While importing 3DS files, Google SketchUp reads a sequence of 2-byte words from the .3DS file, starting at offset 0x6F49F. These words are used as operands in pointer arithmetics to calculate an index for an array where data will be copied to. However, the application does not check if the calculated index is inside the bounds of the destination array. By crafting a 3DS file with large values for the words located at the mentioned offset, the lack of bounds-checking can be exploited to write data outside the limits of the array, leading to a memory corruption vulnerability.

The following disassembled code of the Google SketchUp 3DS Importer module illustrates the vulnerability. As we can see, the data that is copied into the array is fetched from the 3DS file starting at offset 0x6F491. That means that if the memory corruption vulnerability is triggered, the data that will overwrite memory contents is fully controlled by the attacker.

[Module:3DSImporter.dll] 0603AD86 |. 8B97 A8000000 ||MOV EDX,DWORD PTR DS:[EDI+A8] ; EDX = pointer to destination array 0603AD8C |. 0FB7C0 ||MOVZX EAX,AX ; AX = words starting at offset 0x6F49F (user-controlled) 0603AD8F |. 83C4 04 ||ADD ESP,4 0603AD92 |. 6BC0 5C ||IMUL EAX,EAX,5C 0603AD95 |. 8D4C24 18 ||LEA ECX,DWORD PTR SS:[ESP+18] 0603AD99 |. 8D5410 04 ||LEA EDX,DWORD PTR DS:[EAX+EDX+4] ; calculates the index of the array where it will write, using user-controlled data 0603AD9D |. 8D49 00 ||LEA ECX,DWORD PTR DS:[ECX] 0603ADA0 |> 8A01 ||/MOV AL,BYTE PTR DS:[ECX] ; reads bytes starting at offset 0x6F491 (user-controlled) 0603ADA2 |. 8802 |||MOV BYTE PTR DS:[EDX],AL ; copies the byte in AL to the array; *MEMORY CORRUPTION OCCURS HERE* 0603ADA4 |. 83C1 01 |||ADD ECX,1 0603ADA7 |. 83C2 01 |||ADD EDX,1 0603ADAA |. 84C0 |||TEST AL,AL 0603ADAC |.^ 75 F2 ||\JNZ SHORT 3DSImpor.0603ADA0 ; keep copying till AL = 0 

8.2.1. Vulnerable function

We believe the vulnerable function to be face_array_read(), starting at line 238 in file src/lib3ds_mesh.c of lib3ds. The vulnerable code is executed in case CHK_MSH_MAT_GROUP of the following switch statement:

[Function:src/lib3ds_mesh.c:face_array_read()] switch (chunk) { case CHK_MSH_MAT_GROUP: { char name[64]; unsigned n; unsigned i; int index; int material; lib3ds_io_read_string(io, name, 64); material = lib3ds_file_material_by_name(file, name); n = lib3ds_io_read_word(io); for (i = 0; i < n; ++i) { index = lib3ds_io_read_word(io); if (index < mesh->nfaces) { /* <- bounds check */ mesh->faces[index].material = material; } else { // TODO warning } } break; } 

In the latest version of lib3ds, version 2.0, there is a bounds check present in the code. However, in the vulnerable Google SketchUp binary there is no bounds check. Moreover, the assignment following the bounds check does not match the assembler in the binary, but the previous version of lib3ds does match. In version 1.3.0 of lib3ds 'strcpy' is used to copy a string into the array, which is what the binary shows. The file is lib3ds/mesh.c, line 77:

[Function:lib3ds/mesh.c:77] case LIB3DS_MSH_MAT_GROUP: { char name[64]; unsigned faces; unsigned i; unsigned index; if (!lib3ds_io_read_string(io, name, 64)) { return(LIB3DS_FALSE); } faces=lib3ds_io_read_word(io); for (i=0; i<faces; ++i) { index=lib3ds_io_read_word(io); ASSERT(index<mesh->faces); /* <- assert for bounds check */ strcpy(mesh->faceL[index].material, name); } } 

It seems that SketchUp is being compiled in a way that removes the assert, leaving the shipped binary without the bounds check.

8.3. Additional input validation problem

There is an additional input validation problem in the same function of the 3DS Importer module, which may imply security problems if the function is later modified. The copy operation shown above in the disassembled code excerpt is located inside an outer loop. The counter for this outer loop is directly loaded from the 2-byte word located at offset 0x6F49D of the 3DS file without any validations; by providing a 3DS file with a large value for the word located at the mentioned offset, an attacker may cause the application to loop more times than the expected. This behavior could lead to a heap-based buffer overflow vulnerability under a slightly different scenario. Right now, a large value for the word located at offset 0x6F49D of the 3DS file will likely trigger the memory corruption vulnerability described above, because the application will continue reading 2-byte words from the file beyond the intended limit, to use them in the calculation of the index for the array where data will be copied to; if any of these words has a large enough value, the memory corruption condition will be triggered, as previously explained.

The following disassembled code shows this input validation problem:

0603AD7C |. 8BF0 |MOV ESI,EAX ; ESI=loop counter, byte at offset 0x6F49D (user-controlled) 0603AD7E |. 8BFF |MOV EDI,EDI 0603AD80 |> 53 |/PUSH EBX 0603AD81 |. E8 7A1F0000 ||CALL 3DSImpor.0603CD00 0603AD86 |. 8B97 A8000000 ||MOV EDX,DWORD PTR DS:[EDI+A8] ; EDX = pointer to destination array 0603AD8C |. 0FB7C0 ||MOVZX EAX,AX ; AX = words starting at offset 0x6F49F (user-controlled) 0603AD8F |. 83C4 04 ||ADD ESP,4 0603AD92 |. 6BC0 5C ||IMUL EAX,EAX,5C 0603AD95 |. 8D4C24 18 ||LEA ECX,DWORD PTR SS:[ESP+18] 0603AD99 |. 8D5410 04 ||LEA EDX,DWORD PTR DS:[EAX+EDX+4] ; calculates the index of the array where it will write, using user-controlled data 0603AD9D |. 8D49 00 ||LEA ECX,DWORD PTR DS:[ECX] 0603ADA0 |> 8A01 ||/MOV AL,BYTE PTR DS:[ECX] ; reads bytes starting at offset 0x6F491 (user-controlled) 0603ADA2 |. 8802 |||MOV BYTE PTR DS:[EDX],AL ; copies the byte in AL to the array 0603ADA4 |. 83C1 01 |||ADD ECX,1 0603ADA7 |. 83C2 01 |||ADD EDX,1 0603ADAA |. 84C0 |||TEST AL,AL 0603ADAC |.^ 75 F2 ||\JNZ SHORT 3DSImpor.0603ADA0 ; keep copying till AL = 0 0603ADAE |. 83EE 01 ||SUB ESI,1 ; is the outer loop counter (user-controlled) == 0? 0603ADB1 |.^ 75 CD |\JNZ SHORT 3DSImpor.0603AD80 ; if not, keep copying data to the array 

9. Report Timeline

  • 2009-12-14: Core Security notifies the Google Security team of the vulnerability.
  • 2009-12-15: The Google Security team asks Core for the test case for the vulnerability.
  • 2009-12-15: Core replies with the PoC test case.
  • 2009-12-21: The Google Security team replies explaining that the bug is in a 3rd party library. They propose a tentative release date: January 12th.
  • 2009-12-21: After more research done by Francisco Falcon, Core confirms the bug in an old version of the 3rd party library. Core replies with this information, and acknowledging the tentative release date of January 12th.
  • 2010-01-07: Core requests a status update regarding the proposed release date of January 12th.
  • 2010-01-11: The Google Security team replies notifying Core that a release of Google SketchUp 7.1 including this security fix will be available on January 12th, and releases for older versions of SketchUp will follow after.
  • 2010-01-11: Core Security requests the build number of the non-vulnerable versions.
  • 2010-01-12: The Google Security team replies asking to postpone the release of the advisory to January 13th, and informing the build numbers of the non-vulnerable versions.
  • 2010-01-13: The advisory CORE-2009-1209 is published.

10. References

[1] The author participated in Core Security's Bugweek 2009 as member of the team "Estupido y Sensual Flanders".
[2] Google SketchUp: http://sketchup.google.com/

11. About CoreLabs

CoreLabs, the research center of Core Security Technologies, is charged with anticipating the future needs and requirements for information security technologies. We conduct our research in several important areas of computer security including system vulnerabilities, cyber attack planning and simulation, source code auditing, and cryptography. Our results include problem formalization, identification of vulnerabilities, novel solutions and prototypes for new technologies. CoreLabs regularly publishes security advisories, technical papers, project information and shared software tools for public use at: www.coresecurity.com/core-labs.

12. About Core Security

Core Security Technologies develops strategic solutions that help security-conscious organizations worldwide develop and maintain a proactive process for securing their networks. The company's flagship product, CORE IMPACT, is the most comprehensive product for performing enterprise security assurance testing. CORE IMPACT evaluates network, endpoint and end-user vulnerabilities and identifies what resources are exposed. It enables organizations to determine if current security investments are detecting and preventing attacks. Core Security Technologies augments its leading technology solution with world-class security consulting services, including penetration testing and software security auditing. Based in Boston, MA and Buenos Aires, Argentina, Core Security Technologies can be reached at 617-399-6980 or on the Web at www.coresecurity.com.

13. Disclaimer

The contents of this advisory are copyright (c) 2010 Core Security Technologies and (c) 2010 CoreLabs, and may be distributed freely provided that no fee is charged for this distribution and proper credit is given.